]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/GfxState.cc
Merge with Xpdf 2.02 and make it build
[evince.git] / pdf / xpdf / GfxState.cc
1 //========================================================================
2 //
3 // GfxState.cc
4 //
5 // Copyright 1996-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
15 #include <stddef.h>
16 #include <math.h>
17 #include <string.h> // for memcpy()
18 #include "gmem.h"
19 #include "Error.h"
20 #include "Object.h"
21 #include "Array.h"
22 #include "Page.h"
23 #include "GfxState.h"
24
25 //------------------------------------------------------------------------
26
27 static inline double clip01(double x) {
28   return (x < 0) ? 0 : ((x > 1) ? 1 : x);
29 }
30
31 //------------------------------------------------------------------------
32
33 static char *gfxColorSpaceModeNames[] = {
34   "DeviceGray",
35   "CalGray",
36   "DeviceRGB",
37   "CalRGB",
38   "DeviceCMYK",
39   "Lab",
40   "ICCBased",
41   "Indexed",
42   "Separation",
43   "DeviceN",
44   "Pattern"
45 };
46
47 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
48
49 //------------------------------------------------------------------------
50 // GfxColorSpace
51 //------------------------------------------------------------------------
52
53 GfxColorSpace::GfxColorSpace() {
54 }
55
56 GfxColorSpace::~GfxColorSpace() {
57 }
58
59 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
60   GfxColorSpace *cs;
61   Object obj1;
62
63   cs = NULL;
64   if (csObj->isName()) {
65     if (csObj->isName("DeviceGray") || csObj->isName("G")) {
66       cs = new GfxDeviceGrayColorSpace();
67     } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
68       cs = new GfxDeviceRGBColorSpace();
69     } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
70       cs = new GfxDeviceCMYKColorSpace();
71     } else if (csObj->isName("Pattern")) {
72       cs = new GfxPatternColorSpace(NULL);
73     } else {
74       error(-1, "Bad color space '%s'", csObj->getName());
75     }
76   } else if (csObj->isArray()) {
77     csObj->arrayGet(0, &obj1);
78     if (obj1.isName("DeviceGray") || obj1.isName("G")) {
79       cs = new GfxDeviceGrayColorSpace();
80     } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
81       cs = new GfxDeviceRGBColorSpace();
82     } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
83       cs = new GfxDeviceCMYKColorSpace();
84     } else if (obj1.isName("CalGray")) {
85       cs = GfxCalGrayColorSpace::parse(csObj->getArray());
86     } else if (obj1.isName("CalRGB")) {
87       cs = GfxCalRGBColorSpace::parse(csObj->getArray());
88     } else if (obj1.isName("Lab")) {
89       cs = GfxLabColorSpace::parse(csObj->getArray());
90     } else if (obj1.isName("ICCBased")) {
91       cs = GfxICCBasedColorSpace::parse(csObj->getArray());
92     } else if (obj1.isName("Indexed") || obj1.isName("I")) {
93       cs = GfxIndexedColorSpace::parse(csObj->getArray());
94     } else if (obj1.isName("Separation")) {
95       cs = GfxSeparationColorSpace::parse(csObj->getArray());
96     } else if (obj1.isName("DeviceN")) {
97       cs = GfxDeviceNColorSpace::parse(csObj->getArray());
98     } else if (obj1.isName("Pattern")) {
99       cs = GfxPatternColorSpace::parse(csObj->getArray());
100     } else {
101       error(-1, "Bad color space '%s'", csObj->getName());
102     }
103     obj1.free();
104   } else {
105     error(-1, "Bad color space - expected name or array");
106   }
107   return cs;
108 }
109
110 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
111                                      int maxImgPixel) {
112   int i;
113
114   for (i = 0; i < getNComps(); ++i) {
115     decodeLow[i] = 0;
116     decodeRange[i] = 1;
117   }
118 }
119
120 int GfxColorSpace::getNumColorSpaceModes() {
121   return nGfxColorSpaceModes;
122 }
123
124 char *GfxColorSpace::getColorSpaceModeName(int idx) {
125   return gfxColorSpaceModeNames[idx];
126 }
127
128 //------------------------------------------------------------------------
129 // GfxDeviceGrayColorSpace
130 //------------------------------------------------------------------------
131
132 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
133 }
134
135 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
136 }
137
138 GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
139   return new GfxDeviceGrayColorSpace();
140 }
141
142 void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
143   *gray = clip01(color->c[0]);
144 }
145
146 void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
147   rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
148 }
149
150 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
151   cmyk->c = cmyk->m = cmyk->y = 0;
152   cmyk->k = clip01(1 - color->c[0]);
153 }
154
155 //------------------------------------------------------------------------
156 // GfxCalGrayColorSpace
157 //------------------------------------------------------------------------
158
159 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
160   whiteX = whiteY = whiteZ = 1;
161   blackX = blackY = blackZ = 0;
162   gamma = 1;
163 }
164
165 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
166 }
167
168 GfxColorSpace *GfxCalGrayColorSpace::copy() {
169   GfxCalGrayColorSpace *cs;
170
171   cs = new GfxCalGrayColorSpace();
172   cs->whiteX = whiteX;
173   cs->whiteY = whiteY;
174   cs->whiteZ = whiteZ;
175   cs->blackX = blackX;
176   cs->blackY = blackY;
177   cs->blackZ = blackZ;
178   cs->gamma = gamma;
179   return cs;
180 }
181
182 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
183   GfxCalGrayColorSpace *cs;
184   Object obj1, obj2, obj3;
185
186   arr->get(1, &obj1);
187   if (!obj1.isDict()) {
188     error(-1, "Bad CalGray color space");
189     obj1.free();
190     return NULL;
191   }
192   cs = new GfxCalGrayColorSpace();
193   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
194       obj2.arrayGetLength() == 3) {
195     obj2.arrayGet(0, &obj3);
196     cs->whiteX = obj3.getNum();
197     obj3.free();
198     obj2.arrayGet(1, &obj3);
199     cs->whiteY = obj3.getNum();
200     obj3.free();
201     obj2.arrayGet(2, &obj3);
202     cs->whiteZ = obj3.getNum();
203     obj3.free();
204   }
205   obj2.free();
206   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
207       obj2.arrayGetLength() == 3) {
208     obj2.arrayGet(0, &obj3);
209     cs->blackX = obj3.getNum();
210     obj3.free();
211     obj2.arrayGet(1, &obj3);
212     cs->blackY = obj3.getNum();
213     obj3.free();
214     obj2.arrayGet(2, &obj3);
215     cs->blackZ = obj3.getNum();
216     obj3.free();
217   }
218   obj2.free();
219   if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
220     cs->gamma = obj2.getNum();
221   }
222   obj2.free();
223   obj1.free();
224   return cs;
225 }
226
227 void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
228   *gray = clip01(color->c[0]);
229 }
230
231 void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
232   rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
233 }
234
235 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
236   cmyk->c = cmyk->m = cmyk->y = 0;
237   cmyk->k = clip01(1 - color->c[0]);
238 }
239
240 //------------------------------------------------------------------------
241 // GfxDeviceRGBColorSpace
242 //------------------------------------------------------------------------
243
244 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
245 }
246
247 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
248 }
249
250 GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
251   return new GfxDeviceRGBColorSpace();
252 }
253
254 void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
255   *gray = clip01(0.299 * color->c[0] +
256                  0.587 * color->c[1] +
257                  0.114 * color->c[2]);
258 }
259
260 void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
261   rgb->r = clip01(color->c[0]);
262   rgb->g = clip01(color->c[1]);
263   rgb->b = clip01(color->c[2]);
264 }
265
266 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
267   double c, m, y, k;
268
269   c = clip01(1 - color->c[0]);
270   m = clip01(1 - color->c[1]);
271   y = clip01(1 - color->c[2]);
272   k = c;
273   if (m < k) {
274     k = m;
275   }
276   if (y < k) {
277     k = y;
278   }
279   cmyk->c = c - k;
280   cmyk->m = m - k;
281   cmyk->y = y - k;
282   cmyk->k = k;
283 }
284
285 //------------------------------------------------------------------------
286 // GfxCalRGBColorSpace
287 //------------------------------------------------------------------------
288
289 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
290   whiteX = whiteY = whiteZ = 1;
291   blackX = blackY = blackZ = 0;
292   gammaR = gammaG = gammaB = 1;
293   mat[0] = 1; mat[1] = 0; mat[2] = 0;
294   mat[3] = 0; mat[4] = 1; mat[5] = 0;
295   mat[6] = 0; mat[7] = 0; mat[8] = 1;
296 }
297
298 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
299 }
300
301 GfxColorSpace *GfxCalRGBColorSpace::copy() {
302   GfxCalRGBColorSpace *cs;
303   int i;
304
305   cs = new GfxCalRGBColorSpace();
306   cs->whiteX = whiteX;
307   cs->whiteY = whiteY;
308   cs->whiteZ = whiteZ;
309   cs->blackX = blackX;
310   cs->blackY = blackY;
311   cs->blackZ = blackZ;
312   cs->gammaR = gammaR;
313   cs->gammaG = gammaG;
314   cs->gammaB = gammaB;
315   for (i = 0; i < 9; ++i) {
316     cs->mat[i] = mat[i];
317   }
318   return cs;
319 }
320
321 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
322   GfxCalRGBColorSpace *cs;
323   Object obj1, obj2, obj3;
324   int i;
325
326   arr->get(1, &obj1);
327   if (!obj1.isDict()) {
328     error(-1, "Bad CalRGB color space");
329     obj1.free();
330     return NULL;
331   }
332   cs = new GfxCalRGBColorSpace();
333   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
334       obj2.arrayGetLength() == 3) {
335     obj2.arrayGet(0, &obj3);
336     cs->whiteX = obj3.getNum();
337     obj3.free();
338     obj2.arrayGet(1, &obj3);
339     cs->whiteY = obj3.getNum();
340     obj3.free();
341     obj2.arrayGet(2, &obj3);
342     cs->whiteZ = obj3.getNum();
343     obj3.free();
344   }
345   obj2.free();
346   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
347       obj2.arrayGetLength() == 3) {
348     obj2.arrayGet(0, &obj3);
349     cs->blackX = obj3.getNum();
350     obj3.free();
351     obj2.arrayGet(1, &obj3);
352     cs->blackY = obj3.getNum();
353     obj3.free();
354     obj2.arrayGet(2, &obj3);
355     cs->blackZ = obj3.getNum();
356     obj3.free();
357   }
358   obj2.free();
359   if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
360       obj2.arrayGetLength() == 3) {
361     obj2.arrayGet(0, &obj3);
362     cs->gammaR = obj3.getNum();
363     obj3.free();
364     obj2.arrayGet(1, &obj3);
365     cs->gammaG = obj3.getNum();
366     obj3.free();
367     obj2.arrayGet(2, &obj3);
368     cs->gammaB = obj3.getNum();
369     obj3.free();
370   }
371   obj2.free();
372   if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
373       obj2.arrayGetLength() == 9) {
374     for (i = 0; i < 9; ++i) {
375       obj2.arrayGet(i, &obj3);
376       cs->mat[i] = obj3.getNum();
377       obj3.free();
378     }
379   }
380   obj2.free();
381   obj1.free();
382   return cs;
383 }
384
385 void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
386   *gray = clip01(0.299 * color->c[0] +
387                  0.587 * color->c[1] +
388                  0.114 * color->c[2]);
389 }
390
391 void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
392   rgb->r = clip01(color->c[0]);
393   rgb->g = clip01(color->c[1]);
394   rgb->b = clip01(color->c[2]);
395 }
396
397 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
398   double c, m, y, k;
399
400   c = clip01(1 - color->c[0]);
401   m = clip01(1 - color->c[1]);
402   y = clip01(1 - color->c[2]);
403   k = c;
404   if (m < k) {
405     k = m;
406   }
407   if (y < k) {
408     k = y;
409   }
410   cmyk->c = c - k;
411   cmyk->m = m - k;
412   cmyk->y = y - k;
413   cmyk->k = k;
414 }
415
416 //------------------------------------------------------------------------
417 // GfxDeviceCMYKColorSpace
418 //------------------------------------------------------------------------
419
420 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
421 }
422
423 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
424 }
425
426 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
427   return new GfxDeviceCMYKColorSpace();
428 }
429
430 void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
431   *gray = clip01(1 - color->c[3]
432                  - 0.299 * color->c[0]
433                  - 0.587 * color->c[1]
434                  - 0.114 * color->c[2]);
435 }
436
437 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
438   double c, m, y, aw, ac, am, ay, ar, ag, ab;
439
440   /* FIXME ask Derek */
441   if (color->c[0] == 0.0 && color->c[1] == 0 && color->c[2] == 0) {
442     rgb->r = rgb->g = rgb->b = 1 - color->c[3];
443     return;
444   }
445     
446   c = clip01(color->c[0] + color->c[3]);
447   m = clip01(color->c[1] + color->c[3]);
448   y = clip01(color->c[2] + color->c[3]);
449   aw = (1-c) * (1-m) * (1-y);
450   ac = c * (1-m) * (1-y);
451   am = (1-c) * m * (1-y);
452   ay = (1-c) * (1-m) * y;
453   ar = (1-c) * m * y;
454   ag = c * (1-m) * y;
455   ab = c * m * (1-y);
456   rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
457   rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
458   rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
459                   0.4863*ab);
460 }
461
462 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
463   cmyk->c = clip01(color->c[0]);
464   cmyk->m = clip01(color->c[1]);
465   cmyk->y = clip01(color->c[2]);
466   cmyk->k = clip01(color->c[3]);
467 }
468
469 //------------------------------------------------------------------------
470 // GfxLabColorSpace
471 //------------------------------------------------------------------------
472
473 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
474 // Language Reference, Third Edition.
475 static double xyzrgb[3][3] = {
476   {  3.240449, -1.537136, -0.498531 },
477   { -0.969265,  1.876011,  0.041556 },
478   {  0.055643, -0.204026,  1.057229 }
479 };
480
481 GfxLabColorSpace::GfxLabColorSpace() {
482   whiteX = whiteY = whiteZ = 1;
483   blackX = blackY = blackZ = 0;
484   aMin = bMin = -100;
485   aMax = bMax = 100;
486 }
487
488 GfxLabColorSpace::~GfxLabColorSpace() {
489 }
490
491 GfxColorSpace *GfxLabColorSpace::copy() {
492   GfxLabColorSpace *cs;
493
494   cs = new GfxLabColorSpace();
495   cs->whiteX = whiteX;
496   cs->whiteY = whiteY;
497   cs->whiteZ = whiteZ;
498   cs->blackX = blackX;
499   cs->blackY = blackY;
500   cs->blackZ = blackZ;
501   cs->aMin = aMin;
502   cs->aMax = aMax;
503   cs->bMin = bMin;
504   cs->bMax = bMax;
505   cs->kr = kr;
506   cs->kg = kg;
507   cs->kb = kb;
508   return cs;
509 }
510
511 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
512   GfxLabColorSpace *cs;
513   Object obj1, obj2, obj3;
514
515   arr->get(1, &obj1);
516   if (!obj1.isDict()) {
517     error(-1, "Bad Lab color space");
518     obj1.free();
519     return NULL;
520   }
521   cs = new GfxLabColorSpace();
522   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
523       obj2.arrayGetLength() == 3) {
524     obj2.arrayGet(0, &obj3);
525     cs->whiteX = obj3.getNum();
526     obj3.free();
527     obj2.arrayGet(1, &obj3);
528     cs->whiteY = obj3.getNum();
529     obj3.free();
530     obj2.arrayGet(2, &obj3);
531     cs->whiteZ = obj3.getNum();
532     obj3.free();
533   }
534   obj2.free();
535   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
536       obj2.arrayGetLength() == 3) {
537     obj2.arrayGet(0, &obj3);
538     cs->blackX = obj3.getNum();
539     obj3.free();
540     obj2.arrayGet(1, &obj3);
541     cs->blackY = obj3.getNum();
542     obj3.free();
543     obj2.arrayGet(2, &obj3);
544     cs->blackZ = obj3.getNum();
545     obj3.free();
546   }
547   obj2.free();
548   if (obj1.dictLookup("Range", &obj2)->isArray() &&
549       obj2.arrayGetLength() == 4) {
550     obj2.arrayGet(0, &obj3);
551     cs->aMin = obj3.getNum();
552     obj3.free();
553     obj2.arrayGet(1, &obj3);
554     cs->aMax = obj3.getNum();
555     obj3.free();
556     obj2.arrayGet(2, &obj3);
557     cs->bMin = obj3.getNum();
558     obj3.free();
559     obj2.arrayGet(3, &obj3);
560     cs->bMax = obj3.getNum();
561     obj3.free();
562   }
563   obj2.free();
564   obj1.free();
565
566   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
567                 xyzrgb[0][1] * cs->whiteY +
568                 xyzrgb[0][2] * cs->whiteZ);
569   cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
570                 xyzrgb[1][1] * cs->whiteY +
571                 xyzrgb[1][2] * cs->whiteZ);
572   cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
573                 xyzrgb[2][1] * cs->whiteY +
574                 xyzrgb[2][2] * cs->whiteZ);
575
576   return cs;
577 }
578
579 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
580   GfxRGB rgb;
581
582   getRGB(color, &rgb);
583   *gray = clip01(0.299 * rgb.r +
584                  0.587 * rgb.g +
585                  0.114 * rgb.b);
586 }
587
588 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
589   double X, Y, Z;
590   double t1, t2;
591   double r, g, b;
592
593   // convert L*a*b* to CIE 1931 XYZ color space
594   t1 = (color->c[0] + 16) / 116;
595   t2 = t1 + color->c[1] / 500;
596   if (t2 >= (6.0 / 29.0)) {
597     X = t2 * t2 * t2;
598   } else {
599     X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
600   }
601   X *= whiteX;
602   if (t1 >= (6.0 / 29.0)) {
603     Y = t1 * t1 * t1;
604   } else {
605     Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
606   }
607   Y *= whiteY;
608   t2 = t1 - color->c[2] / 200;
609   if (t2 >= (6.0 / 29.0)) {
610     Z = t2 * t2 * t2;
611   } else {
612     Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
613   }
614   Z *= whiteZ;
615
616   // convert XYZ to RGB, including gamut mapping and gamma correction
617   r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
618   g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
619   b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
620   rgb->r = pow(clip01(r * kr), 0.5);
621   rgb->g = pow(clip01(g * kg), 0.5);
622   rgb->b = pow(clip01(b * kb), 0.5);
623 }
624
625 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
626   GfxRGB rgb;
627   double c, m, y, k;
628
629   getRGB(color, &rgb);
630   c = clip01(1 - rgb.r);
631   m = clip01(1 - rgb.g);
632   y = clip01(1 - rgb.b);
633   k = c;
634   if (m < k) {
635     k = m;
636   }
637   if (y < k) {
638     k = y;
639   }
640   cmyk->c = c - k;
641   cmyk->m = m - k;
642   cmyk->y = y - k;
643   cmyk->k = k;
644 }
645
646 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
647                                         int maxImgPixel) {
648   decodeLow[0] = 0;
649   decodeRange[0] = 100;
650   decodeLow[1] = aMin;
651   decodeRange[1] = aMax - aMin;
652   decodeLow[2] = bMin;
653   decodeRange[2] = bMax - bMin;
654 }
655
656 //------------------------------------------------------------------------
657 // GfxICCBasedColorSpace
658 //------------------------------------------------------------------------
659
660 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
661                                              Ref *iccProfileStreamA) {
662   nComps = nCompsA;
663   alt = altA;
664   iccProfileStream = *iccProfileStreamA;
665   rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
666   rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
667 }
668
669 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
670   delete alt;
671 }
672
673 GfxColorSpace *GfxICCBasedColorSpace::copy() {
674   GfxICCBasedColorSpace *cs;
675   int i;
676
677   cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
678   for (i = 0; i < 4; ++i) {
679     cs->rangeMin[i] = rangeMin[i];
680     cs->rangeMax[i] = rangeMax[i];
681   }
682   return cs;
683 }
684
685 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
686   GfxICCBasedColorSpace *cs;
687   Ref iccProfileStreamA;
688   int nCompsA;
689   GfxColorSpace *altA;
690   Dict *dict;
691   Object obj1, obj2, obj3;
692   int i;
693
694   arr->getNF(1, &obj1);
695   if (obj1.isRef()) {
696     iccProfileStreamA = obj1.getRef();
697   } else {
698     iccProfileStreamA.num = 0;
699     iccProfileStreamA.gen = 0;
700   }
701   obj1.free();
702   arr->get(1, &obj1);
703   if (!obj1.isStream()) {
704     error(-1, "Bad ICCBased color space (stream)");
705     obj1.free();
706     return NULL;
707   }
708   dict = obj1.streamGetDict();
709   if (!dict->lookup("N", &obj2)->isInt()) {
710     error(-1, "Bad ICCBased color space (N)");
711     obj2.free();
712     obj1.free();
713     return NULL;
714   }
715   nCompsA = obj2.getInt();
716   obj2.free();
717   if (dict->lookup("Alternate", &obj2)->isNull() ||
718       !(altA = GfxColorSpace::parse(&obj2))) {
719     switch (nCompsA) {
720     case 1:
721       altA = new GfxDeviceGrayColorSpace();
722       break;
723     case 3:
724       altA = new GfxDeviceRGBColorSpace();
725       break;
726     case 4:
727       altA = new GfxDeviceCMYKColorSpace();
728       break;
729     default:
730       error(-1, "Bad ICCBased color space - invalid N");
731       obj2.free();
732       obj1.free();
733       return NULL;
734     }
735   }
736   obj2.free();
737   cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
738   if (dict->lookup("Range", &obj2)->isArray() &&
739       obj2.arrayGetLength() == 2 * nCompsA) {
740     for (i = 0; i < nCompsA; ++i) {
741       obj2.arrayGet(2*i, &obj3);
742       cs->rangeMin[i] = obj3.getNum();
743       obj3.free();
744       obj2.arrayGet(2*i+1, &obj3);
745       cs->rangeMax[i] = obj3.getNum();
746       obj3.free();
747     }
748   }
749   obj2.free();
750   obj1.free();
751   return cs;
752 }
753
754 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
755   alt->getGray(color, gray);
756 }
757
758 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
759   alt->getRGB(color, rgb);
760 }
761
762 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
763   alt->getCMYK(color, cmyk);
764 }
765
766 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
767                                              double *decodeRange,
768                                              int maxImgPixel) {
769   int i;
770
771   for (i = 0; i < nComps; ++i) {
772     decodeLow[i] = rangeMin[i];
773     decodeRange[i] = rangeMax[i] - rangeMin[i];
774   }
775 }
776
777 //------------------------------------------------------------------------
778 // GfxIndexedColorSpace
779 //------------------------------------------------------------------------
780
781 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
782                                            int indexHighA) {
783   base = baseA;
784   indexHigh = indexHighA;
785   lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
786                              sizeof(Guchar));
787 }
788
789 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
790   delete base;
791   gfree(lookup);
792 }
793
794 GfxColorSpace *GfxIndexedColorSpace::copy() {
795   GfxIndexedColorSpace *cs;
796
797   cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
798   memcpy(cs->lookup, lookup,
799          (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
800   return cs;
801 }
802
803 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
804   GfxIndexedColorSpace *cs;
805   GfxColorSpace *baseA;
806   int indexHighA;
807   Object obj1;
808   int x;
809   char *s;
810   int n, i, j;
811
812   if (arr->getLength() != 4) {
813     error(-1, "Bad Indexed color space");
814     goto err1;
815   }
816   arr->get(1, &obj1);
817   if (!(baseA = GfxColorSpace::parse(&obj1))) {
818     error(-1, "Bad Indexed color space (base color space)");
819     goto err2;
820   }
821   obj1.free();
822   if (!arr->get(2, &obj1)->isInt()) {
823     error(-1, "Bad Indexed color space (hival)");
824     delete baseA;
825     goto err2;
826   }
827   indexHighA = obj1.getInt();
828   if (indexHighA < 0 || indexHighA > 255) {
829     // the PDF spec requires indexHigh to be in [0,255] -- allowing
830     // values larger than 255 creates a security hole: if nComps *
831     // indexHigh is greater than 2^31, the loop below may overwrite
832     // past the end of the array
833     error(-1, "Bad Indexed color space (invalid indexHigh value)");
834     delete baseA;
835     goto err2;
836   }
837   obj1.free();
838   cs = new GfxIndexedColorSpace(baseA, indexHighA);
839   arr->get(3, &obj1);
840   n = baseA->getNComps();
841   if (obj1.isStream()) {
842     obj1.streamReset();
843     for (i = 0; i <= indexHighA; ++i) {
844       for (j = 0; j < n; ++j) {
845         if ((x = obj1.streamGetChar()) == EOF) {
846           error(-1, "Bad Indexed color space (lookup table stream too short)");
847           goto err3;
848         }
849         cs->lookup[i*n + j] = (Guchar)x;
850       }
851     }
852     obj1.streamClose();
853   } else if (obj1.isString()) {
854     if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
855       error(-1, "Bad Indexed color space (lookup table string too short)");
856       goto err3;
857     }
858     s = obj1.getString()->getCString();
859     for (i = 0; i <= indexHighA; ++i) {
860       for (j = 0; j < n; ++j) {
861         cs->lookup[i*n + j] = (Guchar)*s++;
862       }
863     }
864   } else {
865     error(-1, "Bad Indexed color space (lookup table)");
866     goto err3;
867   }
868   obj1.free();
869   return cs;
870
871  err3:
872   delete cs;
873  err2:
874   obj1.free();
875  err1:
876   return NULL;
877 }
878
879 GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
880                                                GfxColor *baseColor) {
881   Guchar *p;
882   double low[gfxColorMaxComps], range[gfxColorMaxComps];
883   int n, i;
884
885   n = base->getNComps();
886   base->getDefaultRanges(low, range, indexHigh);
887   p = &lookup[(int)(color->c[0] + 0.5) * n];
888   for (i = 0; i < n; ++i) {
889     baseColor->c[i] = low[i] + (p[i] / 255.0) * range[i];
890   }
891   return baseColor;
892 }
893
894 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
895   GfxColor color2;
896
897   base->getGray(mapColorToBase(color, &color2), gray);
898 }
899
900 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
901   GfxColor color2;
902
903   base->getRGB(mapColorToBase(color, &color2), rgb);
904 }
905
906 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
907   GfxColor color2;
908
909   base->getCMYK(mapColorToBase(color, &color2), cmyk);
910 }
911
912 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
913                                             double *decodeRange,
914                                             int maxImgPixel) {
915   decodeLow[0] = 0;
916   decodeRange[0] = maxImgPixel;
917 }
918
919 //------------------------------------------------------------------------
920 // GfxSeparationColorSpace
921 //------------------------------------------------------------------------
922
923 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
924                                                  GfxColorSpace *altA,
925                                                  Function *funcA) {
926   name = nameA;
927   alt = altA;
928   func = funcA;
929 }
930
931 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
932   delete name;
933   delete alt;
934   delete func;
935 }
936
937 GfxColorSpace *GfxSeparationColorSpace::copy() {
938   return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
939 }
940
941 //~ handle the 'All' and 'None' colorants
942 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
943   GfxSeparationColorSpace *cs;
944   GString *nameA;
945   GfxColorSpace *altA;
946   Function *funcA;
947   Object obj1;
948
949   if (arr->getLength() != 4) {
950     error(-1, "Bad Separation color space");
951     goto err1;
952   }
953   if (!arr->get(1, &obj1)->isName()) {
954     error(-1, "Bad Separation color space (name)");
955     goto err2;
956   }
957   nameA = new GString(obj1.getName());
958   obj1.free();
959   arr->get(2, &obj1);
960   if (!(altA = GfxColorSpace::parse(&obj1))) {
961     error(-1, "Bad Separation color space (alternate color space)");
962     goto err3;
963   }
964   obj1.free();
965   arr->get(3, &obj1);
966   if (!(funcA = Function::parse(&obj1))) {
967     goto err4;
968   }
969   obj1.free();
970   cs = new GfxSeparationColorSpace(nameA, altA, funcA);
971   return cs;
972
973  err4:
974   delete altA;
975  err3:
976   delete nameA;
977  err2:
978   obj1.free();
979  err1:
980   return NULL;
981 }
982
983 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
984   GfxColor color2;
985
986   func->transform(color->c, color2.c);
987   alt->getGray(&color2, gray);
988 }
989
990 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
991   GfxColor color2;
992
993   func->transform(color->c, color2.c);
994   alt->getRGB(&color2, rgb);
995 }
996
997 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
998   GfxColor color2;
999
1000   func->transform(color->c, color2.c);
1001   alt->getCMYK(&color2, cmyk);
1002 }
1003
1004 //------------------------------------------------------------------------
1005 // GfxDeviceNColorSpace
1006 //------------------------------------------------------------------------
1007
1008 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1009                                            GfxColorSpace *altA,
1010                                            Function *funcA) {
1011   nComps = nCompsA;
1012   alt = altA;
1013   func = funcA;
1014 }
1015
1016 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1017   int i;
1018
1019   for (i = 0; i < nComps; ++i) {
1020     delete names[i];
1021   }
1022   delete alt;
1023   delete func;
1024 }
1025
1026 GfxColorSpace *GfxDeviceNColorSpace::copy() {
1027   GfxDeviceNColorSpace *cs;
1028   int i;
1029
1030   cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
1031   for (i = 0; i < nComps; ++i) {
1032     cs->names[i] = names[i]->copy();
1033   }
1034   return cs;
1035 }
1036
1037 //~ handle the 'None' colorant
1038 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1039   GfxDeviceNColorSpace *cs;
1040   int nCompsA;
1041   GString *namesA[gfxColorMaxComps];
1042   GfxColorSpace *altA;
1043   Function *funcA;
1044   Object obj1, obj2;
1045   int i;
1046
1047   if (arr->getLength() != 4 && arr->getLength() != 5) {
1048     error(-1, "Bad DeviceN color space");
1049     goto err1;
1050   }
1051   if (!arr->get(1, &obj1)->isArray()) {
1052     error(-1, "Bad DeviceN color space (names)");
1053     goto err2;
1054   }
1055   nCompsA = obj1.arrayGetLength();
1056   for (i = 0; i < nCompsA; ++i) {
1057     if (!obj1.arrayGet(i, &obj2)->isName()) {
1058       error(-1, "Bad DeviceN color space (names)");
1059       obj2.free();
1060       goto err2;
1061     }
1062     namesA[i] = new GString(obj2.getName());
1063     obj2.free();
1064   }
1065   obj1.free();
1066   arr->get(2, &obj1);
1067   if (!(altA = GfxColorSpace::parse(&obj1))) {
1068     error(-1, "Bad DeviceN color space (alternate color space)");
1069     goto err3;
1070   }
1071   obj1.free();
1072   arr->get(3, &obj1);
1073   if (!(funcA = Function::parse(&obj1))) {
1074     goto err4;
1075   }
1076   obj1.free();
1077   cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1078   for (i = 0; i < nCompsA; ++i) {
1079     cs->names[i] = namesA[i];
1080   }
1081   return cs;
1082
1083  err4:
1084   delete altA;
1085  err3:
1086   for (i = 0; i < nCompsA; ++i) {
1087     delete namesA[i];
1088   }
1089  err2:
1090   obj1.free();
1091  err1:
1092   return NULL;
1093 }
1094
1095 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1096   GfxColor color2;
1097
1098   func->transform(color->c, color2.c);
1099   alt->getGray(&color2, gray);
1100 }
1101
1102 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1103   GfxColor color2;
1104
1105   func->transform(color->c, color2.c);
1106   alt->getRGB(&color2, rgb);
1107 }
1108
1109 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1110   GfxColor color2;
1111
1112   func->transform(color->c, color2.c);
1113   alt->getCMYK(&color2, cmyk);
1114 }
1115
1116 //------------------------------------------------------------------------
1117 // GfxPatternColorSpace
1118 //------------------------------------------------------------------------
1119
1120 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1121   under = underA;
1122 }
1123
1124 GfxPatternColorSpace::~GfxPatternColorSpace() {
1125   if (under) {
1126     delete under;
1127   }
1128 }
1129
1130 GfxColorSpace *GfxPatternColorSpace::copy() {
1131   return new GfxPatternColorSpace(under ? under->copy() :
1132                                           (GfxColorSpace *)NULL);
1133 }
1134
1135 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1136   GfxPatternColorSpace *cs;
1137   GfxColorSpace *underA;
1138   Object obj1;
1139
1140   if (arr->getLength() != 1 && arr->getLength() != 2) {
1141     error(-1, "Bad Pattern color space");
1142     return NULL;
1143   }
1144   underA = NULL;
1145   if (arr->getLength() == 2) {
1146     arr->get(1, &obj1);
1147     if (!(underA = GfxColorSpace::parse(&obj1))) {
1148       error(-1, "Bad Pattern color space (underlying color space)");
1149       obj1.free();
1150       return NULL;
1151     }
1152     obj1.free();
1153   }
1154   cs = new GfxPatternColorSpace(underA);
1155   return cs;
1156 }
1157
1158 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1159   *gray = 0;
1160 }
1161
1162 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1163   rgb->r = rgb->g = rgb->b = 0;
1164 }
1165
1166 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1167   cmyk->c = cmyk->m = cmyk->y = 0;
1168   cmyk->k = 1;
1169 }
1170
1171 //------------------------------------------------------------------------
1172 // Pattern
1173 //------------------------------------------------------------------------
1174
1175 GfxPattern::GfxPattern(int typeA) {
1176   type = typeA;
1177 }
1178
1179 GfxPattern::~GfxPattern() {
1180 }
1181
1182 GfxPattern *GfxPattern::parse(Object *obj) {
1183   GfxPattern *pattern;
1184   Dict *dict;
1185   Object obj1;
1186
1187   pattern = NULL;
1188   if (obj->isStream()) {
1189     dict = obj->streamGetDict();
1190     dict->lookup("PatternType", &obj1);
1191     if (obj1.isInt() && obj1.getInt() == 1) {
1192       pattern = new GfxTilingPattern(dict, obj);
1193     }
1194     obj1.free();
1195   }
1196   return pattern;
1197 }
1198
1199 //------------------------------------------------------------------------
1200 // GfxTilingPattern
1201 //------------------------------------------------------------------------
1202
1203 GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
1204   GfxPattern(1)
1205 {
1206   Object obj1, obj2;
1207   int i;
1208
1209   if (streamDict->lookup("PaintType", &obj1)->isInt()) {
1210     paintType = obj1.getInt();
1211   } else {
1212     paintType = 1;
1213     error(-1, "Invalid or missing PaintType in pattern");
1214   }
1215   obj1.free();
1216   if (streamDict->lookup("TilingType", &obj1)->isInt()) {
1217     tilingType = obj1.getInt();
1218   } else {
1219     tilingType = 1;
1220     error(-1, "Invalid or missing TilingType in pattern");
1221   }
1222   obj1.free();
1223   bbox[0] = bbox[1] = 0;
1224   bbox[2] = bbox[3] = 1;
1225   if (streamDict->lookup("BBox", &obj1)->isArray() &&
1226       obj1.arrayGetLength() == 4) {
1227     for (i = 0; i < 4; ++i) {
1228       if (obj1.arrayGet(i, &obj2)->isNum()) {
1229         bbox[i] = obj2.getNum();
1230       }
1231       obj2.free();
1232     }
1233   } else {
1234     error(-1, "Invalid or missing BBox in pattern");
1235   }
1236   obj1.free();
1237   if (streamDict->lookup("XStep", &obj1)->isNum()) {
1238     xStep = obj1.getNum();
1239   } else {
1240     xStep = 1;
1241     error(-1, "Invalid or missing XStep in pattern");
1242   }
1243   obj1.free();
1244   if (streamDict->lookup("YStep", &obj1)->isNum()) {
1245     yStep = obj1.getNum();
1246   } else {
1247     yStep = 1;
1248     error(-1, "Invalid or missing YStep in pattern");
1249   }
1250   obj1.free();
1251   if (!streamDict->lookup("Resources", &resDict)->isDict()) {
1252     resDict.free();
1253     resDict.initNull();
1254     error(-1, "Invalid or missing Resources in pattern");
1255   }
1256   matrix[0] = 1; matrix[1] = 0;
1257   matrix[2] = 0; matrix[3] = 1;
1258   matrix[4] = 0; matrix[5] = 0;
1259   if (streamDict->lookup("Matrix", &obj1)->isArray() &&
1260       obj1.arrayGetLength() == 6) {
1261     for (i = 0; i < 6; ++i) {
1262       if (obj1.arrayGet(i, &obj2)->isNum()) {
1263         matrix[i] = obj2.getNum();
1264       }
1265       obj2.free();
1266     }
1267   }
1268   obj1.free();
1269   stream->copy(&contentStream);
1270 }
1271
1272 GfxTilingPattern::~GfxTilingPattern() {
1273   resDict.free();
1274   contentStream.free();
1275 }
1276
1277 GfxPattern *GfxTilingPattern::copy() {
1278   return new GfxTilingPattern(this);
1279 }
1280
1281 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
1282   GfxPattern(1)
1283 {
1284   memcpy(this, pat, sizeof(GfxTilingPattern));
1285   pat->resDict.copy(&resDict);
1286   pat->contentStream.copy(&contentStream);
1287 }
1288
1289 //------------------------------------------------------------------------
1290 // GfxShading
1291 //------------------------------------------------------------------------
1292
1293 GfxShading::GfxShading() {
1294 }
1295
1296 GfxShading::~GfxShading() {
1297   delete colorSpace;
1298 }
1299
1300 GfxShading *GfxShading::parse(Object *obj) {
1301   GfxShading *shading;
1302   int typeA;
1303   GfxColorSpace *colorSpaceA;
1304   GfxColor backgroundA;
1305   GBool hasBackgroundA;
1306   double xMinA, yMinA, xMaxA, yMaxA;
1307   GBool hasBBoxA;
1308   Object obj1, obj2;
1309   int i;
1310
1311   shading = NULL;
1312   if (obj->isDict()) {
1313
1314     if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
1315       error(-1, "Invalid ShadingType in shading dictionary");
1316       obj1.free();
1317       goto err1;
1318     }
1319     typeA = obj1.getInt();
1320     obj1.free();
1321
1322     obj->dictLookup("ColorSpace", &obj1);
1323     if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
1324       error(-1, "Bad color space in shading dictionary");
1325       obj1.free();
1326       goto err1;
1327     }
1328     obj1.free();
1329
1330     for (i = 0; i < gfxColorMaxComps; ++i) {
1331       backgroundA.c[i] = 0;
1332     }
1333     hasBackgroundA = gFalse;
1334     if (obj->dictLookup("Background", &obj1)->isArray()) {
1335       if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
1336         hasBackgroundA = gTrue;
1337         for (i = 0; i < colorSpaceA->getNComps(); ++i) {
1338           backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1339           obj2.free();
1340         }
1341       } else {
1342         error(-1, "Bad Background in shading dictionary");
1343       }
1344     }
1345     obj1.free();
1346
1347     xMinA = yMinA = xMaxA = yMaxA = 0;
1348     hasBBoxA = gFalse;
1349     if (obj->dictLookup("BBox", &obj1)->isArray()) {
1350       if (obj1.arrayGetLength() == 4) {
1351         hasBBoxA = gTrue;
1352         xMinA = obj1.arrayGet(0, &obj2)->getNum();
1353         obj2.free();
1354         yMinA = obj1.arrayGet(1, &obj2)->getNum();
1355         obj2.free();
1356         xMaxA = obj1.arrayGet(2, &obj2)->getNum();
1357         obj2.free();
1358         yMaxA = obj1.arrayGet(3, &obj2)->getNum();
1359         obj2.free();
1360       } else {
1361         error(-1, "Bad BBox in shading dictionary");
1362       }
1363     }
1364     obj1.free();
1365
1366     switch (typeA) {
1367     case 2:
1368       shading = GfxAxialShading::parse(obj->getDict());
1369       break;
1370     case 3:
1371       shading = GfxRadialShading::parse(obj->getDict());
1372       break;
1373     default:
1374       error(-1, "Unimplemented shading type %d", typeA);
1375       goto err1;
1376     }
1377
1378     if (shading) {
1379       shading->type = typeA;
1380       shading->colorSpace = colorSpaceA;
1381       shading->background = backgroundA;
1382       shading->hasBackground = hasBackgroundA;
1383       shading->xMin = xMinA;
1384       shading->yMin = yMinA;
1385       shading->xMax = xMaxA;
1386       shading->yMax = yMaxA;
1387       shading->hasBBox = hasBBoxA;
1388     } else {
1389       delete colorSpaceA;
1390     }
1391   }
1392
1393   return shading;
1394
1395  err1:
1396   return NULL;
1397 }
1398
1399 //------------------------------------------------------------------------
1400 // GfxAxialShading
1401 //------------------------------------------------------------------------
1402
1403 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1404                                  double x1A, double y1A,
1405                                  double t0A, double t1A,
1406                                  Function **funcsA, int nFuncsA,
1407                                  GBool extend0A, GBool extend1A) {
1408   int i;
1409
1410   x0 = x0A;
1411   y0 = y0A;
1412   x1 = x1A;
1413   y1 = y1A;
1414   t0 = t0A;
1415   t1 = t1A;
1416   nFuncs = nFuncsA;
1417   for (i = 0; i < nFuncs; ++i) {
1418     funcs[i] = funcsA[i];
1419   }
1420   extend0 = extend0A;
1421   extend1 = extend1A;
1422 }
1423
1424 GfxAxialShading::~GfxAxialShading() {
1425   int i;
1426
1427   for (i = 0; i < nFuncs; ++i) {
1428     delete funcs[i];
1429   }
1430 }
1431
1432 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1433   double x0A, y0A, x1A, y1A;
1434   double t0A, t1A;
1435   Function *funcsA[gfxColorMaxComps];
1436   int nFuncsA;
1437   GBool extend0A, extend1A;
1438   Object obj1, obj2;
1439   int i;
1440
1441   x0A = y0A = x1A = y1A = 0;
1442   if (dict->lookup("Coords", &obj1)->isArray() &&
1443       obj1.arrayGetLength() == 4) {
1444     x0A = obj1.arrayGet(0, &obj2)->getNum();
1445     obj2.free();
1446     y0A = obj1.arrayGet(1, &obj2)->getNum();
1447     obj2.free();
1448     x1A = obj1.arrayGet(2, &obj2)->getNum();
1449     obj2.free();
1450     y1A = obj1.arrayGet(3, &obj2)->getNum();
1451     obj2.free();
1452   } else {
1453     error(-1, "Missing or invalid Coords in shading dictionary");
1454     goto err1;
1455   }
1456   obj1.free();
1457
1458   t0A = 0;
1459   t1A = 1;
1460   if (dict->lookup("Domain", &obj1)->isArray() &&
1461       obj1.arrayGetLength() == 2) {
1462     t0A = obj1.arrayGet(0, &obj2)->getNum();
1463     obj2.free();
1464     t1A = obj1.arrayGet(1, &obj2)->getNum();
1465     obj2.free();
1466   }
1467   obj1.free();
1468
1469   dict->lookup("Function", &obj1);
1470   if (obj1.isArray()) {
1471     nFuncsA = obj1.arrayGetLength();
1472     for (i = 0; i < nFuncsA; ++i) {
1473       obj1.arrayGet(i, &obj2);
1474       if (!(funcsA[i] = Function::parse(&obj2))) {
1475         obj1.free();
1476         obj2.free();
1477         goto err1;
1478       }
1479       obj2.free();
1480     }
1481   } else {
1482     nFuncsA = 1;
1483     if (!(funcsA[0] = Function::parse(&obj1))) {
1484       obj1.free();
1485       goto err1;
1486     }
1487   }
1488   obj1.free();
1489
1490   extend0A = extend1A = gFalse;
1491   if (dict->lookup("Extend", &obj1)->isArray() &&
1492       obj1.arrayGetLength() == 2) {
1493     extend0A = obj1.arrayGet(0, &obj2)->getBool();
1494     obj2.free();
1495     extend1A = obj1.arrayGet(1, &obj2)->getBool();
1496     obj2.free();
1497   }
1498   obj1.free();
1499
1500   return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1501                              funcsA, nFuncsA, extend0A, extend1A);
1502
1503  err1:
1504   return NULL;
1505 }
1506
1507 void GfxAxialShading::getColor(double t, GfxColor *color) {
1508   int i;
1509
1510   for (i = 0; i < nFuncs; ++i) {
1511     funcs[i]->transform(&t, &color->c[i]);
1512   }
1513 }
1514
1515 //------------------------------------------------------------------------
1516 // GfxRadialShading
1517 //------------------------------------------------------------------------
1518
1519 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
1520                                    double x1A, double y1A, double r1A,
1521                                    double t0A, double t1A,
1522                                    Function **funcsA, int nFuncsA,
1523                                    GBool extend0A, GBool extend1A) {
1524   int i;
1525
1526   x0 = x0A;
1527   y0 = y0A;
1528   r0 = r0A;
1529   x1 = x1A;
1530   y1 = y1A;
1531   r1 = r1A;
1532   t0 = t0A;
1533   t1 = t1A;
1534   nFuncs = nFuncsA;
1535   for (i = 0; i < nFuncs; ++i) {
1536     funcs[i] = funcsA[i];
1537   }
1538   extend0 = extend0A;
1539   extend1 = extend1A;
1540 }
1541
1542 GfxRadialShading::~GfxRadialShading() {
1543   int i;
1544
1545   for (i = 0; i < nFuncs; ++i) {
1546     delete funcs[i];
1547   }
1548 }
1549
1550 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
1551   double x0A, y0A, r0A, x1A, y1A, r1A;
1552   double t0A, t1A;
1553   Function *funcsA[gfxColorMaxComps];
1554   int nFuncsA;
1555   GBool extend0A, extend1A;
1556   Object obj1, obj2;
1557   int i;
1558
1559   x0A = y0A = r0A = x1A = y1A = r1A = 0;
1560   if (dict->lookup("Coords", &obj1)->isArray() &&
1561       obj1.arrayGetLength() == 6) {
1562     x0A = obj1.arrayGet(0, &obj2)->getNum();
1563     obj2.free();
1564     y0A = obj1.arrayGet(1, &obj2)->getNum();
1565     obj2.free();
1566     r0A = obj1.arrayGet(2, &obj2)->getNum();
1567     obj2.free();
1568     x1A = obj1.arrayGet(3, &obj2)->getNum();
1569     obj2.free();
1570     y1A = obj1.arrayGet(4, &obj2)->getNum();
1571     obj2.free();
1572     r1A = obj1.arrayGet(5, &obj2)->getNum();
1573     obj2.free();
1574   } else {
1575     error(-1, "Missing or invalid Coords in shading dictionary");
1576     goto err1;
1577   }
1578   obj1.free();
1579
1580   t0A = 0;
1581   t1A = 1;
1582   if (dict->lookup("Domain", &obj1)->isArray() &&
1583       obj1.arrayGetLength() == 2) {
1584     t0A = obj1.arrayGet(0, &obj2)->getNum();
1585     obj2.free();
1586     t1A = obj1.arrayGet(1, &obj2)->getNum();
1587     obj2.free();
1588   }
1589   obj1.free();
1590
1591   dict->lookup("Function", &obj1);
1592   if (obj1.isArray()) {
1593     nFuncsA = obj1.arrayGetLength();
1594     for (i = 0; i < nFuncsA; ++i) {
1595       obj1.arrayGet(i, &obj2);
1596       if (!(funcsA[i] = Function::parse(&obj2))) {
1597         obj1.free();
1598         obj2.free();
1599         goto err1;
1600       }
1601       obj2.free();
1602     }
1603   } else {
1604     nFuncsA = 1;
1605     if (!(funcsA[0] = Function::parse(&obj1))) {
1606       obj1.free();
1607       goto err1;
1608     }
1609   }
1610   obj1.free();
1611
1612   extend0A = extend1A = gFalse;
1613   if (dict->lookup("Extend", &obj1)->isArray() &&
1614       obj1.arrayGetLength() == 2) {
1615     extend0A = obj1.arrayGet(0, &obj2)->getBool();
1616     obj2.free();
1617     extend1A = obj1.arrayGet(1, &obj2)->getBool();
1618     obj2.free();
1619   }
1620   obj1.free();
1621
1622   return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
1623                               funcsA, nFuncsA, extend0A, extend1A);
1624
1625  err1:
1626   return NULL;
1627 }
1628
1629 void GfxRadialShading::getColor(double t, GfxColor *color) {
1630   int i;
1631
1632   for (i = 0; i < nFuncs; ++i) {
1633     funcs[i]->transform(&t, &color->c[i]);
1634   }
1635 }
1636
1637 //------------------------------------------------------------------------
1638 // GfxImageColorMap
1639 //------------------------------------------------------------------------
1640
1641 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1642                                    GfxColorSpace *colorSpaceA) {
1643   GfxIndexedColorSpace *indexedCS;
1644   GfxSeparationColorSpace *sepCS;
1645   int maxPixel, indexHigh;
1646   Guchar *lookup2;
1647   Function *sepFunc;
1648   Object obj;
1649   double x[gfxColorMaxComps];
1650   double y[gfxColorMaxComps];
1651   int i, j, k;
1652
1653   ok = gTrue;
1654
1655   // bits per component and color space
1656   bits = bitsA;
1657   maxPixel = (1 << bits) - 1;
1658   colorSpace = colorSpaceA;
1659
1660   // get decode map
1661   if (decode->isNull()) {
1662     nComps = colorSpace->getNComps();
1663     colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
1664   } else if (decode->isArray()) {
1665     nComps = decode->arrayGetLength() / 2;
1666     if (nComps != colorSpace->getNComps()) {
1667       goto err1;
1668     }
1669     for (i = 0; i < nComps; ++i) {
1670       decode->arrayGet(2*i, &obj);
1671       if (!obj.isNum()) {
1672         goto err2;
1673       }
1674       decodeLow[i] = obj.getNum();
1675       obj.free();
1676       decode->arrayGet(2*i+1, &obj);
1677       if (!obj.isNum()) {
1678         goto err2;
1679       }
1680       decodeRange[i] = obj.getNum() - decodeLow[i];
1681       obj.free();
1682     }
1683   } else {
1684     goto err1;
1685   }
1686
1687   // Construct a lookup table -- this stores pre-computed decoded
1688   // values for each component, i.e., the result of applying the
1689   // decode mapping to each possible image pixel component value.
1690   //
1691   // Optimization: for Indexed and Separation color spaces (which have
1692   // only one component), we store color values in the lookup table
1693   // rather than component values.
1694   colorSpace2 = NULL;
1695   nComps2 = 0;
1696   if (colorSpace->getMode() == csIndexed) {
1697     // Note that indexHigh may not be the same as maxPixel --
1698     // Distiller will remove unused palette entries, resulting in
1699     // indexHigh < maxPixel.
1700     indexedCS = (GfxIndexedColorSpace *)colorSpace;
1701     colorSpace2 = indexedCS->getBase();
1702     indexHigh = indexedCS->getIndexHigh();
1703     nComps2 = colorSpace2->getNComps();
1704     lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double));
1705     lookup2 = indexedCS->getLookup();
1706     colorSpace2->getDefaultRanges(x, y, indexHigh);
1707     for (i = 0; i <= indexHigh; ++i) {
1708       j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
1709       for (k = 0; k < nComps2; ++k) {
1710         lookup[j*nComps2 + k] = x[k] + (lookup2[i*nComps2 + k] / 255.0) * y[k];
1711       }
1712     }
1713   } else if (colorSpace->getMode() == csSeparation) {
1714     sepCS = (GfxSeparationColorSpace *)colorSpace;
1715     colorSpace2 = sepCS->getAlt();
1716     nComps2 = colorSpace2->getNComps();
1717     lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
1718     sepFunc = sepCS->getFunc();
1719     for (i = 0; i <= maxPixel; ++i) {
1720       x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
1721       sepFunc->transform(x, y);
1722       for (k = 0; k < nComps2; ++k) {
1723         lookup[i*nComps2 + k] = y[k];
1724       }
1725     }
1726   } else {
1727     lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
1728     for (i = 0; i <= maxPixel; ++i) {
1729       for (k = 0; k < nComps; ++k) {
1730         lookup[i*nComps + k] = decodeLow[k] +
1731                                  (i * decodeRange[k]) / maxPixel;
1732       }
1733     }
1734   }
1735
1736   return;
1737
1738  err2:
1739   obj.free();
1740  err1:
1741   ok = gFalse;
1742 }
1743
1744 GfxImageColorMap::~GfxImageColorMap() {
1745   delete colorSpace;
1746   gfree(lookup);
1747 }
1748
1749 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
1750   GfxColor color;
1751   double *p;
1752   int i;
1753
1754   if (colorSpace2) {
1755     p = &lookup[x[0] * nComps2];
1756     for (i = 0; i < nComps2; ++i) {
1757       color.c[i] = *p++;
1758     }
1759     colorSpace2->getGray(&color, gray);
1760   } else {
1761     for (i = 0; i < nComps; ++i) {
1762       color.c[i] = lookup[x[i] * nComps + i];
1763     }
1764     colorSpace->getGray(&color, gray);
1765   }
1766 }
1767
1768 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
1769   GfxColor color;
1770   double *p;
1771   int i;
1772
1773   if (colorSpace2) {
1774     p = &lookup[x[0] * nComps2];
1775     for (i = 0; i < nComps2; ++i) {
1776       color.c[i] = *p++;
1777     }
1778     colorSpace2->getRGB(&color, rgb);
1779   } else {
1780     for (i = 0; i < nComps; ++i) {
1781       color.c[i] = lookup[x[i] * nComps + i];
1782     }
1783     colorSpace->getRGB(&color, rgb);
1784   }
1785 }
1786
1787 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
1788   GfxColor color;
1789   double *p;
1790   int i;
1791
1792   if (colorSpace2) {
1793     p = &lookup[x[0] * nComps2];
1794     for (i = 0; i < nComps2; ++i) {
1795       color.c[i] = *p++;
1796     }
1797     colorSpace2->getCMYK(&color, cmyk);
1798   } else {
1799     for (i = 0; i < nComps; ++i) {
1800       color.c[i] = lookup[x[i] * nComps + i];
1801     }
1802     colorSpace->getCMYK(&color, cmyk);
1803   }
1804 }
1805
1806 void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
1807   int maxPixel, i;
1808
1809   maxPixel = (1 << bits) - 1;
1810   for (i = 0; i < nComps; ++i) {
1811     color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel;
1812   }
1813 }
1814
1815 //------------------------------------------------------------------------
1816 // GfxSubpath and GfxPath
1817 //------------------------------------------------------------------------
1818
1819 GfxSubpath::GfxSubpath(double x1, double y1) {
1820   size = 16;
1821   x = (double *)gmalloc(size * sizeof(double));
1822   y = (double *)gmalloc(size * sizeof(double));
1823   curve = (GBool *)gmalloc(size * sizeof(GBool));
1824   n = 1;
1825   x[0] = x1;
1826   y[0] = y1;
1827   curve[0] = gFalse;
1828   closed = gFalse;
1829 }
1830
1831 GfxSubpath::~GfxSubpath() {
1832   gfree(x);
1833   gfree(y);
1834   gfree(curve);
1835 }
1836
1837 // Used for copy().
1838 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
1839   size = subpath->size;
1840   n = subpath->n;
1841   x = (double *)gmalloc(size * sizeof(double));
1842   y = (double *)gmalloc(size * sizeof(double));
1843   curve = (GBool *)gmalloc(size * sizeof(GBool));
1844   memcpy(x, subpath->x, n * sizeof(double));
1845   memcpy(y, subpath->y, n * sizeof(double));
1846   memcpy(curve, subpath->curve, n * sizeof(GBool));
1847   closed = subpath->closed;
1848 }
1849
1850 void GfxSubpath::lineTo(double x1, double y1) {
1851   if (n >= size) {
1852     size += 16;
1853     x = (double *)grealloc(x, size * sizeof(double));
1854     y = (double *)grealloc(y, size * sizeof(double));
1855     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1856   }
1857   x[n] = x1;
1858   y[n] = y1;
1859   curve[n] = gFalse;
1860   ++n;
1861 }
1862
1863 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
1864                          double x3, double y3) {
1865   if (n+3 > size) {
1866     size += 16;
1867     x = (double *)grealloc(x, size * sizeof(double));
1868     y = (double *)grealloc(y, size * sizeof(double));
1869     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1870   }
1871   x[n] = x1;
1872   y[n] = y1;
1873   x[n+1] = x2;
1874   y[n+1] = y2;
1875   x[n+2] = x3;
1876   y[n+2] = y3;
1877   curve[n] = curve[n+1] = gTrue;
1878   curve[n+2] = gFalse;
1879   n += 3;
1880 }
1881
1882 void GfxSubpath::close() {
1883   if (x[n-1] != x[0] || y[n-1] != y[0]) {
1884     lineTo(x[0], y[0]);
1885   }
1886   closed = gTrue;
1887 }
1888
1889 GfxPath::GfxPath() {
1890   justMoved = gFalse;
1891   size = 16;
1892   n = 0;
1893   firstX = firstY = 0;
1894   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1895 }
1896
1897 GfxPath::~GfxPath() {
1898   int i;
1899
1900   for (i = 0; i < n; ++i)
1901     delete subpaths[i];
1902   gfree(subpaths);
1903 }
1904
1905 // Used for copy().
1906 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
1907                  GfxSubpath **subpaths1, int n1, int size1) {
1908   int i;
1909
1910   justMoved = justMoved1;
1911   firstX = firstX1;
1912   firstY = firstY1;
1913   size = size1;
1914   n = n1;
1915   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1916   for (i = 0; i < n; ++i)
1917     subpaths[i] = subpaths1[i]->copy();
1918 }
1919
1920 void GfxPath::moveTo(double x, double y) {
1921   justMoved = gTrue;
1922   firstX = x;
1923   firstY = y;
1924 }
1925
1926 void GfxPath::lineTo(double x, double y) {
1927   if (justMoved) {
1928     if (n >= size) {
1929       size += 16;
1930       subpaths = (GfxSubpath **)
1931                    grealloc(subpaths, size * sizeof(GfxSubpath *));
1932     }
1933     subpaths[n] = new GfxSubpath(firstX, firstY);
1934     ++n;
1935     justMoved = gFalse;
1936   }
1937   subpaths[n-1]->lineTo(x, y);
1938 }
1939
1940 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
1941              double x3, double y3) {
1942   if (justMoved) {
1943     if (n >= size) {
1944       size += 16;
1945       subpaths = (GfxSubpath **)
1946                    grealloc(subpaths, size * sizeof(GfxSubpath *));
1947     }
1948     subpaths[n] = new GfxSubpath(firstX, firstY);
1949     ++n;
1950     justMoved = gFalse;
1951   }
1952   subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
1953 }
1954
1955 void GfxPath::close() {
1956   // this is necessary to handle the pathological case of
1957   // moveto/closepath/clip, which defines an empty clipping region
1958   if (justMoved) {
1959     if (n >= size) {
1960       size += 16;
1961       subpaths = (GfxSubpath **)
1962                    grealloc(subpaths, size * sizeof(GfxSubpath *));
1963     }
1964     subpaths[n] = new GfxSubpath(firstX, firstY);
1965     ++n;
1966     justMoved = gFalse;
1967   }
1968   subpaths[n-1]->close();
1969 }
1970
1971 //------------------------------------------------------------------------
1972 // GfxState
1973 //------------------------------------------------------------------------
1974
1975 GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
1976                    GBool upsideDown) {
1977   double k;
1978
1979   px1 = pageBox->x1;
1980   py1 = pageBox->y1;
1981   px2 = pageBox->x2;
1982   py2 = pageBox->y2;
1983   k = dpi / 72.0;
1984   if (rotate == 90) {
1985     ctm[0] = 0;
1986     ctm[1] = upsideDown ? k : -k;
1987     ctm[2] = k;
1988     ctm[3] = 0;
1989     ctm[4] = -k * py1;
1990     ctm[5] = k * (upsideDown ? -px1 : px2);
1991     pageWidth = k * (py2 - py1);
1992     pageHeight = k * (px2 - px1);
1993   } else if (rotate == 180) {
1994     ctm[0] = -k;
1995     ctm[1] = 0;
1996     ctm[2] = 0;
1997     ctm[3] = upsideDown ? k : -k;
1998     ctm[4] = k * px2;
1999     ctm[5] = k * (upsideDown ? -py1 : py2);
2000     pageWidth = k * (px2 - px1);
2001     pageHeight = k * (py2 - py1);
2002   } else if (rotate == 270) {
2003     ctm[0] = 0;
2004     ctm[1] = upsideDown ? -k : k;
2005     ctm[2] = -k;
2006     ctm[3] = 0;
2007     ctm[4] = k * py2;
2008     ctm[5] = k * (upsideDown ? px2 : -px1);
2009     pageWidth = k * (py2 - py1);
2010     pageHeight = k * (px2 - px1);
2011   } else {
2012     ctm[0] = k;
2013     ctm[1] = 0;
2014     ctm[2] = 0;
2015     ctm[3] = upsideDown ? -k : k;
2016     ctm[4] = -k * px1;
2017     ctm[5] = k * (upsideDown ? py2 : -py1);
2018     pageWidth = k * (px2 - px1);
2019     pageHeight = k * (py2 - py1);
2020   }
2021
2022   fillColorSpace = new GfxDeviceGrayColorSpace();
2023   strokeColorSpace = new GfxDeviceGrayColorSpace();
2024   fillColor.c[0] = 0;
2025   strokeColor.c[0] = 0;
2026   fillPattern = NULL;
2027   strokePattern = NULL;
2028   fillOpacity = 1;
2029   strokeOpacity = 1;
2030
2031   lineWidth = 1;
2032   lineDash = NULL;
2033   lineDashLength = 0;
2034   lineDashStart = 0;
2035   flatness = 0;
2036   lineJoin = 0;
2037   lineCap = 0;
2038   miterLimit = 10;
2039
2040   font = NULL;
2041   fontSize = 0;
2042   textMat[0] = 1; textMat[1] = 0;
2043   textMat[2] = 0; textMat[3] = 1;
2044   textMat[4] = 0; textMat[5] = 0;
2045   charSpace = 0;
2046   wordSpace = 0;
2047   horizScaling = 1;
2048   leading = 0;
2049   rise = 0;
2050   render = 0;
2051
2052   path = new GfxPath();
2053   curX = curY = 0;
2054   lineX = lineY = 0;
2055
2056   clipXMin = 0;
2057   clipYMin = 0;
2058   clipXMax = pageWidth;
2059   clipYMax = pageHeight;
2060
2061   saved = NULL;
2062 }
2063
2064 GfxState::~GfxState() {
2065   if (fillColorSpace) {
2066     delete fillColorSpace;
2067   }
2068   if (strokeColorSpace) {
2069     delete strokeColorSpace;
2070   }
2071   if (fillPattern) {
2072     delete fillPattern;
2073   }
2074   if (strokePattern) {
2075     delete strokePattern;
2076   }
2077   gfree(lineDash);
2078   if (path) {
2079     // this gets set to NULL by restore()
2080     delete path;
2081   }
2082   if (saved) {
2083     delete saved;
2084   }
2085 }
2086
2087 // Used for copy();
2088 GfxState::GfxState(GfxState *state) {
2089   memcpy(this, state, sizeof(GfxState));
2090   if (fillColorSpace) {
2091     fillColorSpace = state->fillColorSpace->copy();
2092   }
2093   if (strokeColorSpace) {
2094     strokeColorSpace = state->strokeColorSpace->copy();
2095   }
2096   if (fillPattern) {
2097     fillPattern = state->fillPattern->copy();
2098   }
2099   if (strokePattern) {
2100     strokePattern = state->strokePattern->copy();
2101   }
2102   if (lineDashLength > 0) {
2103     lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2104     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2105   }
2106   saved = NULL;
2107 }
2108
2109 void GfxState::getUserClipBBox(double *xMin, double *yMin,
2110                                double *xMax, double *yMax) {
2111   double ictm[6];
2112   double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
2113
2114   // invert the CTM
2115   det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2116   ictm[0] = ctm[3] * det;
2117   ictm[1] = -ctm[1] * det;
2118   ictm[2] = -ctm[2] * det;
2119   ictm[3] = ctm[0] * det;
2120   ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2121   ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2122
2123   // transform all four corners of the clip bbox; find the min and max
2124   // x and y values
2125   xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
2126   yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
2127   tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
2128   ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
2129   if (tx < xMin1) {
2130     xMin1 = tx;
2131   } else if (tx > xMax1) {
2132     xMax1 = tx;
2133   }
2134   if (ty < yMin1) {
2135     yMin1 = ty;
2136   } else if (ty > yMax1) {
2137     yMax1 = ty;
2138   }
2139   tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
2140   ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
2141   if (tx < xMin1) {
2142     xMin1 = tx;
2143   } else if (tx > xMax1) {
2144     xMax1 = tx;
2145   }
2146   if (ty < yMin1) {
2147     yMin1 = ty;
2148   } else if (ty > yMax1) {
2149     yMax1 = ty;
2150   }
2151   tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
2152   ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
2153   if (tx < xMin1) {
2154     xMin1 = tx;
2155   } else if (tx > xMax1) {
2156     xMax1 = tx;
2157   }
2158   if (ty < yMin1) {
2159     yMin1 = ty;
2160   } else if (ty > yMax1) {
2161     yMax1 = ty;
2162   }
2163
2164   *xMin = xMin1;
2165   *yMin = yMin1;
2166   *xMax = xMax1;
2167   *yMax = yMax1;
2168 }
2169
2170 double GfxState::transformWidth(double w) {
2171   double x, y;
2172
2173   x = ctm[0] + ctm[2];
2174   y = ctm[1] + ctm[3];
2175   return w * sqrt(0.5 * (x * x + y * y));
2176 }
2177
2178 double GfxState::getTransformedFontSize() {
2179   double x1, y1, x2, y2;
2180
2181   x1 = textMat[2] * fontSize;
2182   y1 = textMat[3] * fontSize;
2183   x2 = ctm[0] * x1 + ctm[2] * y1;
2184   y2 = ctm[1] * x1 + ctm[3] * y1;
2185   return sqrt(x2 * x2 + y2 * y2);
2186 }
2187
2188 void GfxState::getFontTransMat(double *m11, double *m12,
2189                                double *m21, double *m22) {
2190   *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2191   *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2192   *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2193   *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2194 }
2195
2196 void GfxState::setCTM(double a, double b, double c,
2197                       double d, double e, double f) {
2198   int i;
2199
2200   ctm[0] = a;
2201   ctm[1] = b;
2202   ctm[2] = c;
2203   ctm[3] = d;
2204   ctm[4] = e;
2205   ctm[5] = f;
2206
2207   // avoid FP exceptions on badly messed up PDF files
2208   for (i = 0; i < 6; ++i) {
2209     if (ctm[i] > 1e10) {
2210       ctm[i] = 1e10;
2211     } else if (ctm[i] < -1e10) {
2212       ctm[i] = -1e10;
2213     }
2214   }
2215 }
2216
2217 void GfxState::concatCTM(double a, double b, double c,
2218                          double d, double e, double f) {
2219   double a1 = ctm[0];
2220   double b1 = ctm[1];
2221   double c1 = ctm[2];
2222   double d1 = ctm[3];
2223   int i;
2224
2225   ctm[0] = a * a1 + b * c1;
2226   ctm[1] = a * b1 + b * d1;
2227   ctm[2] = c * a1 + d * c1;
2228   ctm[3] = c * b1 + d * d1;
2229   ctm[4] = e * a1 + f * c1 + ctm[4];
2230   ctm[5] = e * b1 + f * d1 + ctm[5];
2231
2232   // avoid FP exceptions on badly messed up PDF files
2233   for (i = 0; i < 6; ++i) {
2234     if (ctm[i] > 1e10) {
2235       ctm[i] = 1e10;
2236     } else if (ctm[i] < -1e10) {
2237       ctm[i] = -1e10;
2238     }
2239   }
2240 }
2241
2242 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2243   if (fillColorSpace) {
2244     delete fillColorSpace;
2245   }
2246   fillColorSpace = colorSpace;
2247 }
2248
2249 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2250   if (strokeColorSpace) {
2251     delete strokeColorSpace;
2252   }
2253   strokeColorSpace = colorSpace;
2254 }
2255
2256 void GfxState::setFillPattern(GfxPattern *pattern) {
2257   if (fillPattern) {
2258     delete fillPattern;
2259   }
2260   fillPattern = pattern;
2261 }
2262
2263 void GfxState::setStrokePattern(GfxPattern *pattern) {
2264   if (strokePattern) {
2265     delete strokePattern;
2266   }
2267   strokePattern = pattern;
2268 }
2269
2270 void GfxState::setLineDash(double *dash, int length, double start) {
2271   if (lineDash)
2272     gfree(lineDash);
2273   lineDash = dash;
2274   lineDashLength = length;
2275   lineDashStart = start;
2276 }
2277
2278 void GfxState::clearPath() {
2279   delete path;
2280   path = new GfxPath();
2281 }
2282
2283 void GfxState::clip() {
2284   double xMin, yMin, xMax, yMax, x, y;
2285   GfxSubpath *subpath;
2286   int i, j;
2287
2288   xMin = xMax = yMin = yMax = 0; // make gcc happy
2289   for (i = 0; i < path->getNumSubpaths(); ++i) {
2290     subpath = path->getSubpath(i);
2291     for (j = 0; j < subpath->getNumPoints(); ++j) {
2292       transform(subpath->getX(j), subpath->getY(j), &x, &y);
2293       if (i == 0 && j == 0) {
2294         xMin = xMax = x;
2295         yMin = yMax = y;
2296       } else {
2297         if (x < xMin) {
2298           xMin = x;
2299         } else if (x > xMax) {
2300           xMax = x;
2301         }
2302         if (y < yMin) {
2303           yMin = y;
2304         } else if (y > yMax) {
2305           yMax = y;
2306         }
2307       }
2308     }
2309   }
2310   if (xMin > clipXMin) {
2311     clipXMin = xMin;
2312   }
2313   if (yMin > clipYMin) {
2314     clipYMin = yMin;
2315   }
2316   if (xMax < clipXMax) {
2317     clipXMax = xMax;
2318   }
2319   if (yMax < clipYMax) {
2320     clipYMax = yMax;
2321   }
2322 }
2323
2324 void GfxState::textShift(double tx, double ty) {
2325   double dx, dy;
2326
2327   textTransformDelta(tx, ty, &dx, &dy);
2328   curX += dx;
2329   curY += dy;
2330 }
2331
2332 void GfxState::shift(double dx, double dy) {
2333   curX += dx;
2334   curY += dy;
2335 }
2336
2337 GfxState *GfxState::save() {
2338   GfxState *newState;
2339
2340   newState = copy();
2341   newState->saved = this;
2342   return newState;
2343 }
2344
2345 GfxState *GfxState::restore() {
2346   GfxState *oldState;
2347
2348   if (saved) {
2349     oldState = saved;
2350
2351     // these attributes aren't saved/restored by the q/Q operators
2352     oldState->path = path;
2353     oldState->curX = curX;
2354     oldState->curY = curY;
2355     oldState->lineX = lineX;
2356     oldState->lineY = lineY;
2357
2358     path = NULL;
2359     saved = NULL;
2360     delete this;
2361
2362   } else {
2363     oldState = this;
2364   }
2365
2366   return oldState;
2367 }