applied diff between xpdf-1.01-orig and xpdf-1.01-swftools.
[swftools.git] / pdf2swf / 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");
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   c = clip01(color->c[0] + color->c[3]);
441   m = clip01(color->c[1] + color->c[3]);
442   y = clip01(color->c[2] + color->c[3]);
443   aw = (1-c) * (1-m) * (1-y);
444   ac = c * (1-m) * (1-y);
445   am = (1-c) * m * (1-y);
446   ay = (1-c) * (1-m) * y;
447   ar = (1-c) * m * y;
448   ag = c * (1-m) * y;
449   ab = c * m * (1-y);
450   rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
451   rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
452   rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
453                   0.4863*ab);
454 }
455
456 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
457   cmyk->c = clip01(color->c[0]);
458   cmyk->m = clip01(color->c[1]);
459   cmyk->y = clip01(color->c[2]);
460   cmyk->k = clip01(color->c[3]);
461 }
462
463 //------------------------------------------------------------------------
464 // GfxLabColorSpace
465 //------------------------------------------------------------------------
466
467 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
468 // Language Reference, Third Edition.
469 static double xyzrgb[3][3] = {
470   {  3.240449, -1.537136, -0.498531 },
471   { -0.969265,  1.876011,  0.041556 },
472   {  0.055643, -0.204026,  1.057229 }
473 };
474
475 GfxLabColorSpace::GfxLabColorSpace() {
476   whiteX = whiteY = whiteZ = 1;
477   blackX = blackY = blackZ = 0;
478   aMin = bMin = -100;
479   aMax = bMax = 100;
480 }
481
482 GfxLabColorSpace::~GfxLabColorSpace() {
483 }
484
485 GfxColorSpace *GfxLabColorSpace::copy() {
486   GfxLabColorSpace *cs;
487
488   cs = new GfxLabColorSpace();
489   cs->whiteX = whiteX;
490   cs->whiteY = whiteY;
491   cs->whiteZ = whiteZ;
492   cs->blackX = blackX;
493   cs->blackY = blackY;
494   cs->blackZ = blackZ;
495   cs->aMin = aMin;
496   cs->aMax = aMax;
497   cs->bMin = bMin;
498   cs->bMax = bMax;
499   cs->kr = kr;
500   cs->kg = kg;
501   cs->kb = kb;
502   return cs;
503 }
504
505 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
506   GfxLabColorSpace *cs;
507   Object obj1, obj2, obj3;
508
509   arr->get(1, &obj1);
510   if (!obj1.isDict()) {
511     error(-1, "Bad Lab color space");
512     obj1.free();
513     return NULL;
514   }
515   cs = new GfxLabColorSpace();
516   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
517       obj2.arrayGetLength() == 3) {
518     obj2.arrayGet(0, &obj3);
519     cs->whiteX = obj3.getNum();
520     obj3.free();
521     obj2.arrayGet(1, &obj3);
522     cs->whiteY = obj3.getNum();
523     obj3.free();
524     obj2.arrayGet(2, &obj3);
525     cs->whiteZ = obj3.getNum();
526     obj3.free();
527   }
528   obj2.free();
529   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
530       obj2.arrayGetLength() == 3) {
531     obj2.arrayGet(0, &obj3);
532     cs->blackX = obj3.getNum();
533     obj3.free();
534     obj2.arrayGet(1, &obj3);
535     cs->blackY = obj3.getNum();
536     obj3.free();
537     obj2.arrayGet(2, &obj3);
538     cs->blackZ = obj3.getNum();
539     obj3.free();
540   }
541   obj2.free();
542   if (obj1.dictLookup("Range", &obj2)->isArray() &&
543       obj2.arrayGetLength() == 4) {
544     obj2.arrayGet(0, &obj3);
545     cs->aMin = obj3.getNum();
546     obj3.free();
547     obj2.arrayGet(1, &obj3);
548     cs->aMax = obj3.getNum();
549     obj3.free();
550     obj2.arrayGet(2, &obj3);
551     cs->bMin = obj3.getNum();
552     obj3.free();
553     obj2.arrayGet(3, &obj3);
554     cs->bMax = obj3.getNum();
555     obj3.free();
556   }
557   obj2.free();
558   obj1.free();
559
560   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
561                 xyzrgb[0][1] * cs->whiteY +
562                 xyzrgb[0][2] * cs->whiteZ);
563   cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
564                 xyzrgb[1][1] * cs->whiteY +
565                 xyzrgb[1][2] * cs->whiteZ);
566   cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
567                 xyzrgb[2][1] * cs->whiteY +
568                 xyzrgb[2][2] * cs->whiteZ);
569
570   return cs;
571 }
572
573 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
574   GfxRGB rgb;
575
576   getRGB(color, &rgb);
577   *gray = clip01(0.299 * rgb.r +
578                  0.587 * rgb.g +
579                  0.114 * rgb.b);
580 }
581
582 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
583   double X, Y, Z;
584   double t1, t2;
585   double r, g, b;
586
587   // convert L*a*b* to CIE 1931 XYZ color space
588   t1 = (color->c[0] + 16) / 116;
589   t2 = t1 + color->c[1] / 500;
590   if (t2 >= (6.0 / 29.0)) {
591     X = t2 * t2 * t2;
592   } else {
593     X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
594   }
595   X *= whiteX;
596   if (t1 >= (6.0 / 29.0)) {
597     Y = t1 * t1 * t1;
598   } else {
599     Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
600   }
601   Y *= whiteY;
602   t2 = t1 - color->c[2] / 200;
603   if (t2 >= (6.0 / 29.0)) {
604     Z = t2 * t2 * t2;
605   } else {
606     Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
607   }
608   Z *= whiteZ;
609
610   // convert XYZ to RGB, including gamut mapping and gamma correction
611   r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
612   g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
613   b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
614   rgb->r = pow(clip01(r * kr), 0.5);
615   rgb->g = pow(clip01(g * kg), 0.5);
616   rgb->b = pow(clip01(b * kb), 0.5);
617 }
618
619 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
620   GfxRGB rgb;
621   double c, m, y, k;
622
623   getRGB(color, &rgb);
624   c = clip01(1 - rgb.r);
625   m = clip01(1 - rgb.g);
626   y = clip01(1 - rgb.b);
627   k = c;
628   if (m < k) {
629     k = m;
630   }
631   if (y < k) {
632     k = y;
633   }
634   cmyk->c = c - k;
635   cmyk->m = m - k;
636   cmyk->y = y - k;
637   cmyk->k = k;
638 }
639
640 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
641                                         int maxImgPixel) {
642   decodeLow[0] = 0;
643   decodeRange[0] = 100;
644   decodeLow[1] = aMin;
645   decodeRange[1] = aMax - aMin;
646   decodeLow[2] = bMin;
647   decodeRange[2] = bMax - bMin;
648 }
649
650 //------------------------------------------------------------------------
651 // GfxICCBasedColorSpace
652 //------------------------------------------------------------------------
653
654 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
655                                              Ref *iccProfileStreamA) {
656   nComps = nCompsA;
657   alt = altA;
658   iccProfileStream = *iccProfileStreamA;
659   rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
660   rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
661 }
662
663 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
664   delete alt;
665 }
666
667 GfxColorSpace *GfxICCBasedColorSpace::copy() {
668   GfxICCBasedColorSpace *cs;
669   int i;
670
671   cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
672   for (i = 0; i < 4; ++i) {
673     cs->rangeMin[i] = rangeMin[i];
674     cs->rangeMax[i] = rangeMax[i];
675   }
676   return cs;
677 }
678
679 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
680   GfxICCBasedColorSpace *cs;
681   Ref iccProfileStreamA;
682   int nCompsA;
683   GfxColorSpace *altA;
684   Dict *dict;
685   Object obj1, obj2, obj3;
686   int i;
687
688   arr->getNF(1, &obj1);
689   if (obj1.isRef()) {
690     iccProfileStreamA = obj1.getRef();
691   } else {
692     iccProfileStreamA.num = 0;
693     iccProfileStreamA.gen = 0;
694   }
695   obj1.free();
696   arr->get(1, &obj1);
697   if (!obj1.isStream()) {
698     error(-1, "Bad ICCBased color space (stream)");
699     obj1.free();
700     return NULL;
701   }
702   dict = obj1.streamGetDict();
703   if (!dict->lookup("N", &obj2)->isInt()) {
704     error(-1, "Bad ICCBased color space (N)");
705     obj2.free();
706     obj1.free();
707     return NULL;
708   }
709   nCompsA = obj2.getInt();
710   obj2.free();
711   if (dict->lookup("Alternate", &obj2)->isNull() ||
712       !(altA = GfxColorSpace::parse(&obj2))) {
713     switch (nCompsA) {
714     case 1:
715       altA = new GfxDeviceGrayColorSpace();
716       break;
717     case 3:
718       altA = new GfxDeviceRGBColorSpace();
719       break;
720     case 4:
721       altA = new GfxDeviceCMYKColorSpace();
722       break;
723     default:
724       error(-1, "Bad ICCBased color space - invalid N");
725       obj2.free();
726       obj1.free();
727       return NULL;
728     }
729   }
730   obj2.free();
731   cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
732   if (dict->lookup("Range", &obj2)->isArray() &&
733       obj2.arrayGetLength() == 2 * nCompsA) {
734     for (i = 0; i < nCompsA; ++i) {
735       obj2.arrayGet(2*i, &obj3);
736       cs->rangeMin[i] = obj3.getNum();
737       obj3.free();
738       obj2.arrayGet(2*i+1, &obj3);
739       cs->rangeMax[i] = obj3.getNum();
740       obj3.free();
741     }
742   }
743   obj2.free();
744   obj1.free();
745   return cs;
746 }
747
748 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
749   alt->getGray(color, gray);
750 }
751
752 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
753   alt->getRGB(color, rgb);
754 }
755
756 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
757   alt->getCMYK(color, cmyk);
758 }
759
760 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
761                                              double *decodeRange,
762                                              int maxImgPixel) {
763   alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
764
765 #if 0
766   // this is nominally correct, but some PDF files don't set the
767   // correct ranges in the ICCBased dict
768   int i;
769
770   for (i = 0; i < nComps; ++i) {
771     decodeLow[i] = rangeMin[i];
772     decodeRange[i] = rangeMax[i] - rangeMin[i];
773   }
774 #endif
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   if (nCompsA > gfxColorMaxComps) {
1057     error(-1, "DeviceN color space with more than %d > %d components",
1058           nCompsA, gfxColorMaxComps);
1059     nCompsA = gfxColorMaxComps;
1060   }
1061   for (i = 0; i < nCompsA; ++i) {
1062     if (!obj1.arrayGet(i, &obj2)->isName()) {
1063       error(-1, "Bad DeviceN color space (names)");
1064       obj2.free();
1065       goto err2;
1066     }
1067     namesA[i] = new GString(obj2.getName());
1068     obj2.free();
1069   }
1070   obj1.free();
1071   arr->get(2, &obj1);
1072   if (!(altA = GfxColorSpace::parse(&obj1))) {
1073     error(-1, "Bad DeviceN color space (alternate color space)");
1074     goto err3;
1075   }
1076   obj1.free();
1077   arr->get(3, &obj1);
1078   if (!(funcA = Function::parse(&obj1))) {
1079     goto err4;
1080   }
1081   obj1.free();
1082   cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1083   for (i = 0; i < nCompsA; ++i) {
1084     cs->names[i] = namesA[i];
1085   }
1086   return cs;
1087
1088  err4:
1089   delete altA;
1090  err3:
1091   for (i = 0; i < nCompsA; ++i) {
1092     delete namesA[i];
1093   }
1094  err2:
1095   obj1.free();
1096  err1:
1097   return NULL;
1098 }
1099
1100 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1101   GfxColor color2;
1102
1103   func->transform(color->c, color2.c);
1104   alt->getGray(&color2, gray);
1105 }
1106
1107 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1108   GfxColor color2;
1109
1110   func->transform(color->c, color2.c);
1111   alt->getRGB(&color2, rgb);
1112 }
1113
1114 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1115   GfxColor color2;
1116
1117   func->transform(color->c, color2.c);
1118   alt->getCMYK(&color2, cmyk);
1119 }
1120
1121 //------------------------------------------------------------------------
1122 // GfxPatternColorSpace
1123 //------------------------------------------------------------------------
1124
1125 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1126   under = underA;
1127 }
1128
1129 GfxPatternColorSpace::~GfxPatternColorSpace() {
1130   if (under) {
1131     delete under;
1132   }
1133 }
1134
1135 GfxColorSpace *GfxPatternColorSpace::copy() {
1136   return new GfxPatternColorSpace(under ? under->copy() :
1137                                           (GfxColorSpace *)NULL);
1138 }
1139
1140 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1141   GfxPatternColorSpace *cs;
1142   GfxColorSpace *underA;
1143   Object obj1;
1144
1145   if (arr->getLength() != 1 && arr->getLength() != 2) {
1146     error(-1, "Bad Pattern color space");
1147     return NULL;
1148   }
1149   underA = NULL;
1150   if (arr->getLength() == 2) {
1151     arr->get(1, &obj1);
1152     if (!(underA = GfxColorSpace::parse(&obj1))) {
1153       error(-1, "Bad Pattern color space (underlying color space)");
1154       obj1.free();
1155       return NULL;
1156     }
1157     obj1.free();
1158   }
1159   cs = new GfxPatternColorSpace(underA);
1160   return cs;
1161 }
1162
1163 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1164   *gray = 0;
1165 }
1166
1167 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1168   rgb->r = rgb->g = rgb->b = 0;
1169 }
1170
1171 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1172   cmyk->c = cmyk->m = cmyk->y = 0;
1173   cmyk->k = 1;
1174 }
1175
1176 //------------------------------------------------------------------------
1177 // Pattern
1178 //------------------------------------------------------------------------
1179
1180 GfxPattern::GfxPattern(int typeA) {
1181   type = typeA;
1182 }
1183
1184 GfxPattern::~GfxPattern() {
1185 }
1186
1187 GfxPattern *GfxPattern::parse(Object *obj) {
1188   GfxPattern *pattern;
1189   Object obj1;
1190
1191   if (obj->isDict()) {
1192     obj->dictLookup("PatternType", &obj1);
1193   } else if (obj->isStream()) {
1194     obj->streamGetDict()->lookup("PatternType", &obj1);
1195   } else {
1196     return NULL;
1197   }
1198   pattern = NULL;
1199   if (obj1.isInt() && obj1.getInt() == 1) {
1200     pattern = GfxTilingPattern::parse(obj);
1201   } else if (obj1.isInt() && obj1.getInt() == 2) {
1202     pattern = GfxShadingPattern::parse(obj);
1203   }
1204   obj1.free();
1205   return pattern;
1206 }
1207
1208 //------------------------------------------------------------------------
1209 // GfxTilingPattern
1210 //------------------------------------------------------------------------
1211
1212 GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
1213   GfxTilingPattern *pat;
1214   Dict *dict;
1215   int paintTypeA, tilingTypeA;
1216   double bboxA[4], matrixA[6];
1217   double xStepA, yStepA;
1218   Object resDictA;
1219   Object obj1, obj2;
1220   int i;
1221
1222   if (!patObj->isStream()) {
1223     return NULL;
1224   }
1225   dict = patObj->streamGetDict();
1226
1227   if (dict->lookup("PaintType", &obj1)->isInt()) {
1228     paintTypeA = obj1.getInt();
1229   } else {
1230     paintTypeA = 1;
1231     error(-1, "Invalid or missing PaintType in pattern");
1232   }
1233   obj1.free();
1234   if (dict->lookup("TilingType", &obj1)->isInt()) {
1235     tilingTypeA = obj1.getInt();
1236   } else {
1237     tilingTypeA = 1;
1238     error(-1, "Invalid or missing TilingType in pattern");
1239   }
1240   obj1.free();
1241   bboxA[0] = bboxA[1] = 0;
1242   bboxA[2] = bboxA[3] = 1;
1243   if (dict->lookup("BBox", &obj1)->isArray() &&
1244       obj1.arrayGetLength() == 4) {
1245     for (i = 0; i < 4; ++i) {
1246       if (obj1.arrayGet(i, &obj2)->isNum()) {
1247         bboxA[i] = obj2.getNum();
1248       }
1249       obj2.free();
1250     }
1251   } else {
1252     error(-1, "Invalid or missing BBox in pattern");
1253   }
1254   obj1.free();
1255   if (dict->lookup("XStep", &obj1)->isNum()) {
1256     xStepA = obj1.getNum();
1257   } else {
1258     xStepA = 1;
1259     error(-1, "Invalid or missing XStep in pattern");
1260   }
1261   obj1.free();
1262   if (dict->lookup("YStep", &obj1)->isNum()) {
1263     yStepA = obj1.getNum();
1264   } else {
1265     yStepA = 1;
1266     error(-1, "Invalid or missing YStep in pattern");
1267   }
1268   obj1.free();
1269   if (!dict->lookup("Resources", &resDictA)->isDict()) {
1270     resDictA.free();
1271     resDictA.initNull();
1272     error(-1, "Invalid or missing Resources in pattern");
1273   }
1274   matrixA[0] = 1; matrixA[1] = 0;
1275   matrixA[2] = 0; matrixA[3] = 1;
1276   matrixA[4] = 0; matrixA[5] = 0;
1277   if (dict->lookup("Matrix", &obj1)->isArray() &&
1278       obj1.arrayGetLength() == 6) {
1279     for (i = 0; i < 6; ++i) {
1280       if (obj1.arrayGet(i, &obj2)->isNum()) {
1281         matrixA[i] = obj2.getNum();
1282       }
1283       obj2.free();
1284     }
1285   }
1286   obj1.free();
1287
1288   pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
1289                              &resDictA, matrixA, patObj);
1290   resDictA.free();
1291   return pat;
1292 }
1293
1294 GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
1295                                    double *bboxA, double xStepA, double yStepA,
1296                                    Object *resDictA, double *matrixA,
1297                                    Object *contentStreamA):
1298   GfxPattern(1)
1299 {
1300   int i;
1301
1302   paintType = paintTypeA;
1303   tilingType = tilingTypeA;
1304   for (i = 0; i < 4; ++i) {
1305     bbox[i] = bboxA[i];
1306   }
1307   xStep = xStepA;
1308   yStep = yStepA;
1309   resDictA->copy(&resDict);
1310   for (i = 0; i < 6; ++i) {
1311     matrix[i] = matrixA[i];
1312   }
1313   contentStreamA->copy(&contentStream);
1314 }
1315
1316 GfxTilingPattern::~GfxTilingPattern() {
1317   resDict.free();
1318   contentStream.free();
1319 }
1320
1321 GfxPattern *GfxTilingPattern::copy() {
1322   return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
1323                               &resDict, matrix, &contentStream);
1324 }
1325
1326 //------------------------------------------------------------------------
1327 // GfxShadingPattern
1328 //------------------------------------------------------------------------
1329
1330 GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
1331   Dict *dict;
1332   GfxShading *shadingA;
1333   double matrixA[6];
1334   Object obj1, obj2;
1335   int i;
1336
1337   if (!patObj->isDict()) {
1338     return NULL;
1339   }
1340   dict = patObj->getDict();
1341
1342   dict->lookup("Shading", &obj1);
1343   shadingA = GfxShading::parse(&obj1);
1344   obj1.free();
1345   if (!shadingA) {
1346     return NULL;
1347   }
1348
1349   matrixA[0] = 1; matrixA[1] = 0;
1350   matrixA[2] = 0; matrixA[3] = 1;
1351   matrixA[4] = 0; matrixA[5] = 0;
1352   if (dict->lookup("Matrix", &obj1)->isArray() &&
1353       obj1.arrayGetLength() == 6) {
1354     for (i = 0; i < 6; ++i) {
1355       if (obj1.arrayGet(i, &obj2)->isNum()) {
1356         matrixA[i] = obj2.getNum();
1357       }
1358       obj2.free();
1359     }
1360   }
1361   obj1.free();
1362
1363   return new GfxShadingPattern(shadingA, matrixA);
1364 }
1365
1366 GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
1367   GfxPattern(2)
1368 {
1369   int i;
1370
1371   shading = shadingA;
1372   for (i = 0; i < 6; ++i) {
1373     matrix[i] = matrixA[i];
1374   }
1375 }
1376
1377 GfxShadingPattern::~GfxShadingPattern() {
1378   delete shading;
1379 }
1380
1381 GfxPattern *GfxShadingPattern::copy() {
1382   return new GfxShadingPattern(shading->copy(), matrix);
1383 }
1384
1385 //------------------------------------------------------------------------
1386 // GfxShading
1387 //------------------------------------------------------------------------
1388
1389 GfxShading::GfxShading(int typeA) {
1390   type = typeA;
1391   colorSpace = NULL;
1392 }
1393
1394 GfxShading::GfxShading(GfxShading *shading) {
1395   int i;
1396
1397   type = shading->type;
1398   colorSpace = shading->colorSpace->copy();
1399   for (i = 0; i < gfxColorMaxComps; ++i) {
1400     background.c[i] = shading->background.c[i];
1401   }
1402   hasBackground = shading->hasBackground;
1403   xMin = shading->xMin;
1404   yMin = shading->yMin;
1405   xMax = shading->xMax;
1406   yMax = shading->yMax;
1407   hasBBox = shading->hasBBox;
1408 }
1409
1410 GfxShading::~GfxShading() {
1411   if (colorSpace) {
1412     delete colorSpace;
1413   }
1414 }
1415
1416 GfxShading *GfxShading::parse(Object *obj) {
1417   GfxShading *shading;
1418   Dict *dict;
1419   int typeA;
1420   Object obj1;
1421
1422   if (obj->isDict()) {
1423     dict = obj->getDict();
1424   } else if (obj->isStream()) {
1425     dict = obj->streamGetDict();
1426   } else {
1427     return NULL;
1428   }
1429
1430   if (!dict->lookup("ShadingType", &obj1)->isInt()) {
1431     error(-1, "Invalid ShadingType in shading dictionary");
1432     obj1.free();
1433     return NULL;
1434   }
1435   typeA = obj1.getInt();
1436   obj1.free();
1437
1438   switch (typeA) {
1439   case 1:
1440     shading = GfxFunctionShading::parse(dict);
1441     break;
1442   case 2:
1443     shading = GfxAxialShading::parse(dict);
1444     break;
1445   case 3:
1446     shading = GfxRadialShading::parse(dict);
1447     break;
1448   default:
1449     error(-1, "Unimplemented shading type %d", typeA);
1450     goto err1;
1451   }
1452
1453   return shading;
1454
1455  err1:
1456   return NULL;
1457 }
1458
1459 GBool GfxShading::init(Dict *dict) {
1460   Object obj1, obj2;
1461   int i;
1462
1463   dict->lookup("ColorSpace", &obj1);
1464   if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
1465     error(-1, "Bad color space in shading dictionary");
1466     obj1.free();
1467     return gFalse;
1468   }
1469   obj1.free();
1470
1471   for (i = 0; i < gfxColorMaxComps; ++i) {
1472     background.c[i] = 0;
1473   }
1474   hasBackground = gFalse;
1475   if (dict->lookup("Background", &obj1)->isArray()) {
1476     if (obj1.arrayGetLength() == colorSpace->getNComps()) {
1477       hasBackground = gTrue;
1478       for (i = 0; i < colorSpace->getNComps(); ++i) {
1479         background.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1480         obj2.free();
1481       }
1482     } else {
1483       error(-1, "Bad Background in shading dictionary");
1484     }
1485   }
1486   obj1.free();
1487
1488   xMin = yMin = xMax = yMax = 0;
1489   hasBBox = gFalse;
1490   if (dict->lookup("BBox", &obj1)->isArray()) {
1491     if (obj1.arrayGetLength() == 4) {
1492       hasBBox = gTrue;
1493       xMin = obj1.arrayGet(0, &obj2)->getNum();
1494       obj2.free();
1495       yMin = obj1.arrayGet(1, &obj2)->getNum();
1496       obj2.free();
1497       xMax = obj1.arrayGet(2, &obj2)->getNum();
1498       obj2.free();
1499       yMax = obj1.arrayGet(3, &obj2)->getNum();
1500       obj2.free();
1501     } else {
1502       error(-1, "Bad BBox in shading dictionary");
1503     }
1504   }
1505   obj1.free();
1506
1507   return gTrue;
1508 }
1509
1510 //------------------------------------------------------------------------
1511 // GfxFunctionShading
1512 //------------------------------------------------------------------------
1513
1514 GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
1515                                        double x1A, double y1A,
1516                                        double *matrixA,
1517                                        Function **funcsA, int nFuncsA):
1518   GfxShading(1)
1519 {
1520   int i;
1521
1522   x0 = x0A;
1523   y0 = y0A;
1524   x1 = x1A;
1525   y1 = y1A;
1526   for (i = 0; i < 6; ++i) {
1527     matrix[i] = matrixA[i];
1528   }
1529   nFuncs = nFuncsA;
1530   for (i = 0; i < nFuncs; ++i) {
1531     funcs[i] = funcsA[i];
1532   }
1533 }
1534
1535 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
1536   GfxShading(shading)
1537 {
1538   int i;
1539
1540   x0 = shading->x0;
1541   y0 = shading->y0;
1542   x1 = shading->x1;
1543   y1 = shading->y1;
1544   for (i = 0; i < 6; ++i) {
1545     matrix[i] = shading->matrix[i];
1546   }
1547   nFuncs = shading->nFuncs;
1548   for (i = 0; i < nFuncs; ++i) {
1549     funcs[i] = shading->funcs[i]->copy();
1550   }
1551 }
1552
1553 GfxFunctionShading::~GfxFunctionShading() {
1554   int i;
1555
1556   for (i = 0; i < nFuncs; ++i) {
1557     delete funcs[i];
1558   }
1559 }
1560
1561 GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
1562   GfxFunctionShading *shading;
1563   double x0A, y0A, x1A, y1A;
1564   double matrixA[6];
1565   Function *funcsA[gfxColorMaxComps];
1566   int nFuncsA;
1567   Object obj1, obj2;
1568   int i;
1569
1570   x0A = y0A = 0;
1571   x1A = y1A = 1;
1572   if (dict->lookup("Domain", &obj1)->isArray() &&
1573       obj1.arrayGetLength() == 4) {
1574     x0A = obj1.arrayGet(0, &obj2)->getNum();
1575     obj2.free();
1576     y0A = obj1.arrayGet(1, &obj2)->getNum();
1577     obj2.free();
1578     x1A = obj1.arrayGet(2, &obj2)->getNum();
1579     obj2.free();
1580     y1A = obj1.arrayGet(3, &obj2)->getNum();
1581     obj2.free();
1582   }
1583   obj1.free();
1584
1585   matrixA[0] = 1; matrixA[1] = 0;
1586   matrixA[2] = 0; matrixA[3] = 1;
1587   matrixA[4] = 0; matrixA[5] = 0;
1588   if (dict->lookup("Matrix", &obj1)->isArray() &&
1589       obj1.arrayGetLength() == 6) {
1590     matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
1591     obj2.free();
1592     matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
1593     obj2.free();
1594     matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
1595     obj2.free();
1596     matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
1597     obj2.free();
1598     matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
1599     obj2.free();
1600     matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
1601     obj2.free();
1602   }
1603   obj1.free();
1604
1605   dict->lookup("Function", &obj1);
1606   if (obj1.isArray()) {
1607     nFuncsA = obj1.arrayGetLength();
1608     if (nFuncsA > gfxColorMaxComps) {
1609       error(-1, "Invalid Function array in shading dictionary");
1610       goto err1;
1611     }
1612     for (i = 0; i < nFuncsA; ++i) {
1613       obj1.arrayGet(i, &obj2);
1614       if (!(funcsA[i] = Function::parse(&obj2))) {
1615         goto err2;
1616       }
1617       obj2.free();
1618     }
1619   } else {
1620     nFuncsA = 1;
1621     if (!(funcsA[0] = Function::parse(&obj1))) {
1622       goto err1;
1623     }
1624   }
1625   obj1.free();
1626
1627   shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
1628                                    funcsA, nFuncsA);
1629   if (!shading->init(dict)) {
1630     delete shading;
1631     return NULL;
1632   }
1633   return shading;
1634
1635  err2:
1636   obj2.free();
1637  err1:
1638   obj1.free();
1639   return NULL;
1640 }
1641
1642 GfxShading *GfxFunctionShading::copy() {
1643   return new GfxFunctionShading(this);
1644 }
1645
1646 void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
1647   double in[2];
1648   int i;
1649
1650   in[0] = x;
1651   in[1] = y;
1652   for (i = 0; i < nFuncs; ++i) {
1653     funcs[i]->transform(in, &color->c[i]);
1654   }
1655 }
1656
1657 //------------------------------------------------------------------------
1658 // GfxAxialShading
1659 //------------------------------------------------------------------------
1660
1661 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1662                                  double x1A, double y1A,
1663                                  double t0A, double t1A,
1664                                  Function **funcsA, int nFuncsA,
1665                                  GBool extend0A, GBool extend1A):
1666   GfxShading(2)
1667 {
1668   int i;
1669
1670   x0 = x0A;
1671   y0 = y0A;
1672   x1 = x1A;
1673   y1 = y1A;
1674   t0 = t0A;
1675   t1 = t1A;
1676   nFuncs = nFuncsA;
1677   for (i = 0; i < nFuncs; ++i) {
1678     funcs[i] = funcsA[i];
1679   }
1680   extend0 = extend0A;
1681   extend1 = extend1A;
1682 }
1683
1684 GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
1685   GfxShading(shading)
1686 {
1687   int i;
1688
1689   x0 = shading->x0;
1690   y0 = shading->y0;
1691   x1 = shading->x1;
1692   y1 = shading->y1;
1693   t0 = shading->t0;
1694   y1 = shading->t1;
1695   nFuncs = shading->nFuncs;
1696   for (i = 0; i < nFuncs; ++i) {
1697     funcs[i] = shading->funcs[i]->copy();
1698   }
1699   extend0 = shading->extend0;
1700   extend1 = shading->extend1;
1701 }
1702
1703 GfxAxialShading::~GfxAxialShading() {
1704   int i;
1705
1706   for (i = 0; i < nFuncs; ++i) {
1707     delete funcs[i];
1708   }
1709 }
1710
1711 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1712   GfxAxialShading *shading;
1713   double x0A, y0A, x1A, y1A;
1714   double t0A, t1A;
1715   Function *funcsA[gfxColorMaxComps];
1716   int nFuncsA;
1717   GBool extend0A, extend1A;
1718   Object obj1, obj2;
1719   int i;
1720
1721   x0A = y0A = x1A = y1A = 0;
1722   if (dict->lookup("Coords", &obj1)->isArray() &&
1723       obj1.arrayGetLength() == 4) {
1724     x0A = obj1.arrayGet(0, &obj2)->getNum();
1725     obj2.free();
1726     y0A = obj1.arrayGet(1, &obj2)->getNum();
1727     obj2.free();
1728     x1A = obj1.arrayGet(2, &obj2)->getNum();
1729     obj2.free();
1730     y1A = obj1.arrayGet(3, &obj2)->getNum();
1731     obj2.free();
1732   } else {
1733     error(-1, "Missing or invalid Coords in shading dictionary");
1734     goto err1;
1735   }
1736   obj1.free();
1737
1738   t0A = 0;
1739   t1A = 1;
1740   if (dict->lookup("Domain", &obj1)->isArray() &&
1741       obj1.arrayGetLength() == 2) {
1742     t0A = obj1.arrayGet(0, &obj2)->getNum();
1743     obj2.free();
1744     t1A = obj1.arrayGet(1, &obj2)->getNum();
1745     obj2.free();
1746   }
1747   obj1.free();
1748
1749   dict->lookup("Function", &obj1);
1750   if (obj1.isArray()) {
1751     nFuncsA = obj1.arrayGetLength();
1752     if (nFuncsA > gfxColorMaxComps) {
1753       error(-1, "Invalid Function array in shading dictionary");
1754       goto err1;
1755     }
1756     for (i = 0; i < nFuncsA; ++i) {
1757       obj1.arrayGet(i, &obj2);
1758       if (!(funcsA[i] = Function::parse(&obj2))) {
1759         obj1.free();
1760         obj2.free();
1761         goto err1;
1762       }
1763       obj2.free();
1764     }
1765   } else {
1766     nFuncsA = 1;
1767     if (!(funcsA[0] = Function::parse(&obj1))) {
1768       obj1.free();
1769       goto err1;
1770     }
1771   }
1772   obj1.free();
1773
1774   extend0A = extend1A = gFalse;
1775   if (dict->lookup("Extend", &obj1)->isArray() &&
1776       obj1.arrayGetLength() == 2) {
1777     extend0A = obj1.arrayGet(0, &obj2)->getBool();
1778     obj2.free();
1779     extend1A = obj1.arrayGet(1, &obj2)->getBool();
1780     obj2.free();
1781   }
1782   obj1.free();
1783
1784   shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1785                                 funcsA, nFuncsA, extend0A, extend1A);
1786   if (!shading->init(dict)) {
1787     delete shading;
1788     return NULL;
1789   }
1790   return shading;
1791
1792  err1:
1793   return NULL;
1794 }
1795
1796 GfxShading *GfxAxialShading::copy() {
1797   return new GfxAxialShading(this);
1798 }
1799
1800 void GfxAxialShading::getColor(double t, GfxColor *color) {
1801   int i;
1802
1803   // NB: there can be one function with n outputs or n functions with
1804   // one output each (where n = number of color components)
1805   for (i = 0; i < nFuncs; ++i) {
1806     funcs[i]->transform(&t, &color->c[i]);
1807   }
1808 }
1809
1810 //------------------------------------------------------------------------
1811 // GfxRadialShading
1812 //------------------------------------------------------------------------
1813
1814 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
1815                                    double x1A, double y1A, double r1A,
1816                                    double t0A, double t1A,
1817                                    Function **funcsA, int nFuncsA,
1818                                    GBool extend0A, GBool extend1A):
1819   GfxShading(3)
1820 {
1821   int i;
1822
1823   x0 = x0A;
1824   y0 = y0A;
1825   r0 = r0A;
1826   x1 = x1A;
1827   y1 = y1A;
1828   r1 = r1A;
1829   t0 = t0A;
1830   t1 = t1A;
1831   nFuncs = nFuncsA;
1832   for (i = 0; i < nFuncs; ++i) {
1833     funcs[i] = funcsA[i];
1834   }
1835   extend0 = extend0A;
1836   extend1 = extend1A;
1837 }
1838
1839 GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
1840   GfxShading(shading)
1841 {
1842   int i;
1843
1844   x0 = shading->x0;
1845   y0 = shading->y0;
1846   r0 = shading->r0;
1847   x1 = shading->x1;
1848   y1 = shading->y1;
1849   r1 = shading->r1;
1850   t0 = shading->t0;
1851   y1 = shading->t1;
1852   nFuncs = shading->nFuncs;
1853   for (i = 0; i < nFuncs; ++i) {
1854     funcs[i] = shading->funcs[i]->copy();
1855   }
1856   extend0 = shading->extend0;
1857   extend1 = shading->extend1;
1858 }
1859
1860 GfxRadialShading::~GfxRadialShading() {
1861   int i;
1862
1863   for (i = 0; i < nFuncs; ++i) {
1864     delete funcs[i];
1865   }
1866 }
1867
1868 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
1869   GfxRadialShading *shading;
1870   double x0A, y0A, r0A, x1A, y1A, r1A;
1871   double t0A, t1A;
1872   Function *funcsA[gfxColorMaxComps];
1873   int nFuncsA;
1874   GBool extend0A, extend1A;
1875   Object obj1, obj2;
1876   int i;
1877
1878   x0A = y0A = r0A = x1A = y1A = r1A = 0;
1879   if (dict->lookup("Coords", &obj1)->isArray() &&
1880       obj1.arrayGetLength() == 6) {
1881     x0A = obj1.arrayGet(0, &obj2)->getNum();
1882     obj2.free();
1883     y0A = obj1.arrayGet(1, &obj2)->getNum();
1884     obj2.free();
1885     r0A = obj1.arrayGet(2, &obj2)->getNum();
1886     obj2.free();
1887     x1A = obj1.arrayGet(3, &obj2)->getNum();
1888     obj2.free();
1889     y1A = obj1.arrayGet(4, &obj2)->getNum();
1890     obj2.free();
1891     r1A = obj1.arrayGet(5, &obj2)->getNum();
1892     obj2.free();
1893   } else {
1894     error(-1, "Missing or invalid Coords in shading dictionary");
1895     goto err1;
1896   }
1897   obj1.free();
1898
1899   t0A = 0;
1900   t1A = 1;
1901   if (dict->lookup("Domain", &obj1)->isArray() &&
1902       obj1.arrayGetLength() == 2) {
1903     t0A = obj1.arrayGet(0, &obj2)->getNum();
1904     obj2.free();
1905     t1A = obj1.arrayGet(1, &obj2)->getNum();
1906     obj2.free();
1907   }
1908   obj1.free();
1909
1910   dict->lookup("Function", &obj1);
1911   if (obj1.isArray()) {
1912     nFuncsA = obj1.arrayGetLength();
1913     if (nFuncsA > gfxColorMaxComps) {
1914       error(-1, "Invalid Function array in shading dictionary");
1915       goto err1;
1916     }
1917     for (i = 0; i < nFuncsA; ++i) {
1918       obj1.arrayGet(i, &obj2);
1919       if (!(funcsA[i] = Function::parse(&obj2))) {
1920         obj1.free();
1921         obj2.free();
1922         goto err1;
1923       }
1924       obj2.free();
1925     }
1926   } else {
1927     nFuncsA = 1;
1928     if (!(funcsA[0] = Function::parse(&obj1))) {
1929       obj1.free();
1930       goto err1;
1931     }
1932   }
1933   obj1.free();
1934
1935   extend0A = extend1A = gFalse;
1936   if (dict->lookup("Extend", &obj1)->isArray() &&
1937       obj1.arrayGetLength() == 2) {
1938     extend0A = obj1.arrayGet(0, &obj2)->getBool();
1939     obj2.free();
1940     extend1A = obj1.arrayGet(1, &obj2)->getBool();
1941     obj2.free();
1942   }
1943   obj1.free();
1944
1945   shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
1946                                  funcsA, nFuncsA, extend0A, extend1A);
1947   if (!shading->init(dict)) {
1948     delete shading;
1949     return NULL;
1950   }
1951   return shading;
1952
1953  err1:
1954   return NULL;
1955 }
1956
1957 GfxShading *GfxRadialShading::copy() {
1958   return new GfxRadialShading(this);
1959 }
1960
1961 void GfxRadialShading::getColor(double t, GfxColor *color) {
1962   int i;
1963
1964   // NB: there can be one function with n outputs or n functions with
1965   // one output each (where n = number of color components)
1966   for (i = 0; i < nFuncs; ++i) {
1967     funcs[i]->transform(&t, &color->c[i]);
1968   }
1969 }
1970
1971 //------------------------------------------------------------------------
1972 // GfxImageColorMap
1973 //------------------------------------------------------------------------
1974
1975 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1976                                    GfxColorSpace *colorSpaceA) {
1977   GfxIndexedColorSpace *indexedCS;
1978   GfxSeparationColorSpace *sepCS;
1979   int maxPixel, indexHigh;
1980   Guchar *lookup2;
1981   Function *sepFunc;
1982   Object obj;
1983   double x[gfxColorMaxComps];
1984   double y[gfxColorMaxComps];
1985   int i, j, k;
1986   int maxPixelForAlloc;
1987
1988   ok = gTrue;
1989
1990   // bits per component and color space
1991   bits = bitsA;
1992   maxPixel = (1 << bits) - 1;
1993   maxPixelForAlloc = (1 << (bits>8?bits:8));
1994   colorSpace = colorSpaceA;
1995
1996   // get decode map
1997   if (decode->isNull()) {
1998     nComps = colorSpace->getNComps();
1999     colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
2000   } else if (decode->isArray()) {
2001     nComps = decode->arrayGetLength() / 2;
2002     if (nComps != colorSpace->getNComps()) {
2003       goto err1;
2004     }
2005     for (i = 0; i < nComps; ++i) {
2006       decode->arrayGet(2*i, &obj);
2007       if (!obj.isNum()) {
2008         goto err2;
2009       }
2010       decodeLow[i] = obj.getNum();
2011       obj.free();
2012       decode->arrayGet(2*i+1, &obj);
2013       if (!obj.isNum()) {
2014         goto err2;
2015       }
2016       decodeRange[i] = obj.getNum() - decodeLow[i];
2017       obj.free();
2018     }
2019   } else {
2020     goto err1;
2021   }
2022
2023   // Construct a lookup table -- this stores pre-computed decoded
2024   // values for each component, i.e., the result of applying the
2025   // decode mapping to each possible image pixel component value.
2026   //
2027   // Optimization: for Indexed and Separation color spaces (which have
2028   // only one component), we store color values in the lookup table
2029   // rather than component values.
2030   colorSpace2 = NULL;
2031   nComps2 = 0;
2032   if (colorSpace->getMode() == csIndexed) {
2033     // Note that indexHigh may not be the same as maxPixel --
2034     // Distiller will remove unused palette entries, resulting in
2035     // indexHigh < maxPixel.
2036     indexedCS = (GfxIndexedColorSpace *)colorSpace;
2037     colorSpace2 = indexedCS->getBase();
2038     indexHigh = indexedCS->getIndexHigh();
2039     nComps2 = colorSpace2->getNComps();
2040     lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
2041     lookup2 = indexedCS->getLookup();
2042     colorSpace2->getDefaultRanges(x, y, indexHigh);
2043     for (i = 0; i <= maxPixel; ++i) {
2044       j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
2045       if (j < 0) {
2046         j = 0;
2047       } else if (j > indexHigh) {
2048         j = indexHigh;
2049       }
2050       for (k = 0; k < nComps2; ++k) {
2051         lookup[i*nComps2 + k] = x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k];
2052       }
2053     }
2054   } else if (colorSpace->getMode() == csSeparation) {
2055     sepCS = (GfxSeparationColorSpace *)colorSpace;
2056     colorSpace2 = sepCS->getAlt();
2057     nComps2 = colorSpace2->getNComps();
2058     lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
2059     sepFunc = sepCS->getFunc();
2060     for (i = 0; i <= maxPixel; ++i) {
2061       x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
2062       sepFunc->transform(x, y);
2063       for (k = 0; k < nComps2; ++k) {
2064         lookup[i*nComps2 + k] = y[k];
2065       }
2066     }
2067   } else {
2068     lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps * sizeof(double));
2069     for (i = 0; i <= maxPixel; ++i) {
2070       for (k = 0; k < nComps; ++k) {
2071         lookup[i*nComps + k] = decodeLow[k] +
2072                                  (i * decodeRange[k]) / maxPixel;
2073       }
2074     }
2075   }
2076
2077   return;
2078
2079  err2:
2080   obj.free();
2081  err1:
2082   ok = gFalse;
2083 }
2084
2085 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
2086   int n, i;
2087
2088   colorSpace = colorMap->colorSpace->copy();
2089   bits = colorMap->bits;
2090   nComps = colorMap->nComps;
2091   nComps2 = colorMap->nComps2;
2092   colorSpace2 = NULL;
2093   lookup = NULL;
2094   n = 1 << bits;
2095   if (colorSpace->getMode() == csIndexed) {
2096     colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
2097     n = n * nComps2 * sizeof(double);
2098   } else if (colorSpace->getMode() == csSeparation) {
2099     colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
2100     n = n * nComps2 * sizeof(double);
2101   } else {
2102     n = n * nComps * sizeof(double);
2103   }
2104   lookup = (double *)gmalloc(n);
2105   memcpy(lookup, colorMap->lookup, n);
2106   for (i = 0; i < nComps; ++i) {
2107     decodeLow[i] = colorMap->decodeLow[i];
2108     decodeRange[i] = colorMap->decodeRange[i];
2109   }
2110   ok = gTrue;
2111 }
2112
2113 GfxImageColorMap::~GfxImageColorMap() {
2114   delete colorSpace;
2115   gfree(lookup);
2116 }
2117
2118 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
2119   GfxColor color;
2120   double *p;
2121   int i;
2122
2123   if (colorSpace2) {
2124     p = &lookup[x[0] * nComps2];
2125     for (i = 0; i < nComps2; ++i) {
2126       color.c[i] = *p++;
2127     }
2128     colorSpace2->getGray(&color, gray);
2129   } else {
2130     for (i = 0; i < nComps; ++i) {
2131       color.c[i] = lookup[x[i] * nComps + i];
2132     }
2133     colorSpace->getGray(&color, gray);
2134   }
2135 }
2136
2137 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
2138   GfxColor color;
2139   double *p;
2140   int i;
2141
2142   if (colorSpace2) {
2143     p = &lookup[x[0] * nComps2];
2144     for (i = 0; i < nComps2; ++i) {
2145       color.c[i] = *p++;
2146     }
2147     colorSpace2->getRGB(&color, rgb);
2148   } else {
2149     for (i = 0; i < nComps; ++i) {
2150       color.c[i] = lookup[x[i] * nComps + i];
2151     }
2152     colorSpace->getRGB(&color, rgb);
2153   }
2154 }
2155
2156 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
2157   GfxColor color;
2158   double *p;
2159   int i;
2160
2161   if (colorSpace2) {
2162     p = &lookup[x[0] * nComps2];
2163     for (i = 0; i < nComps2; ++i) {
2164       color.c[i] = *p++;
2165     }
2166     colorSpace2->getCMYK(&color, cmyk);
2167   } else {
2168     for (i = 0; i < nComps; ++i) {
2169       color.c[i] = lookup[x[i] * nComps + i];
2170     }
2171     colorSpace->getCMYK(&color, cmyk);
2172   }
2173 }
2174
2175 void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
2176   int maxPixel, i;
2177
2178   maxPixel = (1 << bits) - 1;
2179   for (i = 0; i < nComps; ++i) {
2180     color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel;
2181   }
2182 }
2183
2184 //------------------------------------------------------------------------
2185 // GfxSubpath and GfxPath
2186 //------------------------------------------------------------------------
2187
2188 GfxSubpath::GfxSubpath(double x1, double y1) {
2189   size = 16;
2190   x = (double *)gmalloc(size * sizeof(double));
2191   y = (double *)gmalloc(size * sizeof(double));
2192   curve = (GBool *)gmalloc(size * sizeof(GBool));
2193   n = 1;
2194   x[0] = x1;
2195   y[0] = y1;
2196   curve[0] = gFalse;
2197   closed = gFalse;
2198 }
2199
2200 GfxSubpath::~GfxSubpath() {
2201   gfree(x);
2202   gfree(y);
2203   gfree(curve);
2204 }
2205
2206 // Used for copy().
2207 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
2208   size = subpath->size;
2209   n = subpath->n;
2210   x = (double *)gmalloc(size * sizeof(double));
2211   y = (double *)gmalloc(size * sizeof(double));
2212   curve = (GBool *)gmalloc(size * sizeof(GBool));
2213   memcpy(x, subpath->x, n * sizeof(double));
2214   memcpy(y, subpath->y, n * sizeof(double));
2215   memcpy(curve, subpath->curve, n * sizeof(GBool));
2216   closed = subpath->closed;
2217 }
2218
2219 void GfxSubpath::lineTo(double x1, double y1) {
2220   if (n >= size) {
2221     size += 16;
2222     x = (double *)grealloc(x, size * sizeof(double));
2223     y = (double *)grealloc(y, size * sizeof(double));
2224     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2225   }
2226   x[n] = x1;
2227   y[n] = y1;
2228   curve[n] = gFalse;
2229   ++n;
2230 }
2231
2232 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
2233                          double x3, double y3) {
2234   if (n+3 > size) {
2235     size += 16;
2236     x = (double *)grealloc(x, size * sizeof(double));
2237     y = (double *)grealloc(y, size * sizeof(double));
2238     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2239   }
2240   x[n] = x1;
2241   y[n] = y1;
2242   x[n+1] = x2;
2243   y[n+1] = y2;
2244   x[n+2] = x3;
2245   y[n+2] = y3;
2246   curve[n] = curve[n+1] = gTrue;
2247   curve[n+2] = gFalse;
2248   n += 3;
2249 }
2250
2251 void GfxSubpath::close() {
2252   if (x[n-1] != x[0] || y[n-1] != y[0]) {
2253     lineTo(x[0], y[0]);
2254   }
2255   closed = gTrue;
2256 }
2257
2258 void GfxSubpath::offset(double dx, double dy) {
2259   int i;
2260
2261   for (i = 0; i < n; ++i) {
2262     x[i] += dx;
2263     y[i] += dy;
2264   }
2265 }
2266
2267 GfxPath::GfxPath() {
2268   justMoved = gFalse;
2269   size = 16;
2270   n = 0;
2271   firstX = firstY = 0;
2272   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2273 }
2274
2275 GfxPath::~GfxPath() {
2276   int i;
2277
2278   for (i = 0; i < n; ++i)
2279     delete subpaths[i];
2280   gfree(subpaths);
2281 }
2282
2283 // Used for copy().
2284 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
2285                  GfxSubpath **subpaths1, int n1, int size1) {
2286   int i;
2287
2288   justMoved = justMoved1;
2289   firstX = firstX1;
2290   firstY = firstY1;
2291   size = size1;
2292   n = n1;
2293   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2294   for (i = 0; i < n; ++i)
2295     subpaths[i] = subpaths1[i]->copy();
2296 }
2297
2298 void GfxPath::moveTo(double x, double y) {
2299   justMoved = gTrue;
2300   firstX = x;
2301   firstY = y;
2302 }
2303
2304 void GfxPath::lineTo(double x, double y) {
2305   if (justMoved) {
2306     if (n >= size) {
2307       size += 16;
2308       subpaths = (GfxSubpath **)
2309                    grealloc(subpaths, size * sizeof(GfxSubpath *));
2310     }
2311     subpaths[n] = new GfxSubpath(firstX, firstY);
2312     ++n;
2313     justMoved = gFalse;
2314   }
2315   subpaths[n-1]->lineTo(x, y);
2316 }
2317
2318 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
2319              double x3, double y3) {
2320   if (justMoved) {
2321     if (n >= size) {
2322       size += 16;
2323       subpaths = (GfxSubpath **)
2324                    grealloc(subpaths, size * sizeof(GfxSubpath *));
2325     }
2326     subpaths[n] = new GfxSubpath(firstX, firstY);
2327     ++n;
2328     justMoved = gFalse;
2329   }
2330   subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
2331 }
2332
2333 void GfxPath::close() {
2334   // this is necessary to handle the pathological case of
2335   // moveto/closepath/clip, which defines an empty clipping region
2336   if (justMoved) {
2337     if (n >= size) {
2338       size += 16;
2339       subpaths = (GfxSubpath **)
2340                    grealloc(subpaths, size * sizeof(GfxSubpath *));
2341     }
2342     subpaths[n] = new GfxSubpath(firstX, firstY);
2343     ++n;
2344     justMoved = gFalse;
2345   }
2346   subpaths[n-1]->close();
2347 }
2348
2349 void GfxPath::append(GfxPath *path) {
2350   int i;
2351
2352   if (n + path->n > size) {
2353     size = n + path->n;
2354     subpaths = (GfxSubpath **)
2355                  grealloc(subpaths, size * sizeof(GfxSubpath *));
2356   }
2357   for (i = 0; i < path->n; ++i) {
2358     subpaths[n++] = path->subpaths[i]->copy();
2359   }
2360   justMoved = gFalse;
2361 }
2362
2363 void GfxPath::offset(double dx, double dy) {
2364   int i;
2365
2366   for (i = 0; i < n; ++i) {
2367     subpaths[i]->offset(dx, dy);
2368   }
2369 }
2370
2371 //------------------------------------------------------------------------
2372 // GfxState
2373 //------------------------------------------------------------------------
2374
2375 GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
2376                    int rotate, GBool upsideDown) {
2377   double kx, ky;
2378
2379   px1 = pageBox->x1;
2380   py1 = pageBox->y1;
2381   px2 = pageBox->x2;
2382   py2 = pageBox->y2;
2383   kx = hDPI / 72.0;
2384   ky = vDPI / 72.0;
2385   if (rotate == 90) {
2386     ctm[0] = 0;
2387     ctm[1] = upsideDown ? ky : -ky;
2388     ctm[2] = kx;
2389     ctm[3] = 0;
2390     ctm[4] = -kx * py1;
2391     ctm[5] = ky * (upsideDown ? -px1 : px2);
2392     pageWidth = kx * (py2 - py1);
2393     pageHeight = ky * (px2 - px1);
2394   } else if (rotate == 180) {
2395     ctm[0] = -kx;
2396     ctm[1] = 0;
2397     ctm[2] = 0;
2398     ctm[3] = upsideDown ? ky : -ky;
2399     ctm[4] = kx * px2;
2400     ctm[5] = ky * (upsideDown ? -py1 : py2);
2401     pageWidth = kx * (px2 - px1);
2402     pageHeight = ky * (py2 - py1);
2403   } else if (rotate == 270) {
2404     ctm[0] = 0;
2405     ctm[1] = upsideDown ? -ky : ky;
2406     ctm[2] = -kx;
2407     ctm[3] = 0;
2408     ctm[4] = kx * py2;
2409     ctm[5] = ky * (upsideDown ? px2 : -px1);
2410     pageWidth = kx * (py2 - py1);
2411     pageHeight = ky * (px2 - px1);
2412   } else {
2413     ctm[0] = kx;
2414     ctm[1] = 0;
2415     ctm[2] = 0;
2416     ctm[3] = upsideDown ? -ky : ky;
2417     ctm[4] = -kx * px1;
2418     ctm[5] = ky * (upsideDown ? py2 : -py1);
2419     pageWidth = kx * (px2 - px1);
2420     pageHeight = ky * (py2 - py1);
2421   }
2422
2423   fillColorSpace = new GfxDeviceGrayColorSpace();
2424   strokeColorSpace = new GfxDeviceGrayColorSpace();
2425   fillColor.c[0] = 0;
2426   strokeColor.c[0] = 0;
2427   fillPattern = NULL;
2428   strokePattern = NULL;
2429   fillOpacity = 1;
2430   strokeOpacity = 1;
2431
2432   lineWidth = 1;
2433   lineDash = NULL;
2434   lineDashLength = 0;
2435   lineDashStart = 0;
2436   flatness = 1;
2437   lineJoin = 0;
2438   lineCap = 0;
2439   miterLimit = 10;
2440
2441   font = NULL;
2442   fontSize = 0;
2443   textMat[0] = 1; textMat[1] = 0;
2444   textMat[2] = 0; textMat[3] = 1;
2445   textMat[4] = 0; textMat[5] = 0;
2446   charSpace = 0;
2447   wordSpace = 0;
2448   horizScaling = 1;
2449   leading = 0;
2450   rise = 0;
2451   render = 0;
2452
2453   path = new GfxPath();
2454   curX = curY = 0;
2455   lineX = lineY = 0;
2456
2457   clipXMin = 0;
2458   clipYMin = 0;
2459   clipXMax = pageWidth;
2460   clipYMax = pageHeight;
2461
2462   saved = NULL;
2463 }
2464
2465 GfxState::~GfxState() {
2466   if (fillColorSpace) {
2467     delete fillColorSpace;
2468   }
2469   if (strokeColorSpace) {
2470     delete strokeColorSpace;
2471   }
2472   if (fillPattern) {
2473     delete fillPattern;
2474   }
2475   if (strokePattern) {
2476     delete strokePattern;
2477   }
2478   gfree(lineDash);
2479   if (path) {
2480     // this gets set to NULL by restore()
2481     delete path;
2482   }
2483   if (saved) {
2484     delete saved;
2485   }
2486 }
2487
2488 // Used for copy();
2489 GfxState::GfxState(GfxState *state) {
2490   memcpy(this, state, sizeof(GfxState));
2491   if (fillColorSpace) {
2492     fillColorSpace = state->fillColorSpace->copy();
2493   }
2494   if (strokeColorSpace) {
2495     strokeColorSpace = state->strokeColorSpace->copy();
2496   }
2497   if (fillPattern) {
2498     fillPattern = state->fillPattern->copy();
2499   }
2500   if (strokePattern) {
2501     strokePattern = state->strokePattern->copy();
2502   }
2503   if (lineDashLength > 0) {
2504     lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2505     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2506   }
2507   saved = NULL;
2508 }
2509
2510 void GfxState::setPath(GfxPath *pathA) {
2511   delete path;
2512   path = pathA;
2513 }
2514
2515 void GfxState::getUserClipBBox(double *xMin, double *yMin,
2516                                double *xMax, double *yMax) {
2517   double ictm[6];
2518   double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
2519
2520   // invert the CTM
2521   det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2522   ictm[0] = ctm[3] * det;
2523   ictm[1] = -ctm[1] * det;
2524   ictm[2] = -ctm[2] * det;
2525   ictm[3] = ctm[0] * det;
2526   ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2527   ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2528
2529   // transform all four corners of the clip bbox; find the min and max
2530   // x and y values
2531   xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
2532   yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
2533   tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
2534   ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
2535   if (tx < xMin1) {
2536     xMin1 = tx;
2537   } else if (tx > xMax1) {
2538     xMax1 = tx;
2539   }
2540   if (ty < yMin1) {
2541     yMin1 = ty;
2542   } else if (ty > yMax1) {
2543     yMax1 = ty;
2544   }
2545   tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
2546   ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
2547   if (tx < xMin1) {
2548     xMin1 = tx;
2549   } else if (tx > xMax1) {
2550     xMax1 = tx;
2551   }
2552   if (ty < yMin1) {
2553     yMin1 = ty;
2554   } else if (ty > yMax1) {
2555     yMax1 = ty;
2556   }
2557   tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
2558   ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
2559   if (tx < xMin1) {
2560     xMin1 = tx;
2561   } else if (tx > xMax1) {
2562     xMax1 = tx;
2563   }
2564   if (ty < yMin1) {
2565     yMin1 = ty;
2566   } else if (ty > yMax1) {
2567     yMax1 = ty;
2568   }
2569
2570   *xMin = xMin1;
2571   *yMin = yMin1;
2572   *xMax = xMax1;
2573   *yMax = yMax1;
2574 }
2575
2576 double GfxState::transformWidth(double w) {
2577   double x, y;
2578
2579   x = ctm[0] + ctm[2];
2580   y = ctm[1] + ctm[3];
2581   return w * sqrt(0.5 * (x * x + y * y));
2582 }
2583
2584 double GfxState::getTransformedFontSize() {
2585   double x1, y1, x2, y2;
2586
2587   x1 = textMat[2] * fontSize;
2588   y1 = textMat[3] * fontSize;
2589   x2 = ctm[0] * x1 + ctm[2] * y1;
2590   y2 = ctm[1] * x1 + ctm[3] * y1;
2591   return sqrt(x2 * x2 + y2 * y2);
2592 }
2593
2594 void GfxState::getFontTransMat(double *m11, double *m12,
2595                                double *m21, double *m22) {
2596   *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2597   *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2598   *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2599   *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2600 }
2601
2602 void GfxState::setCTM(double a, double b, double c,
2603                       double d, double e, double f) {
2604   int i;
2605
2606   ctm[0] = a;
2607   ctm[1] = b;
2608   ctm[2] = c;
2609   ctm[3] = d;
2610   ctm[4] = e;
2611   ctm[5] = f;
2612
2613   // avoid FP exceptions on badly messed up PDF files
2614   for (i = 0; i < 6; ++i) {
2615     if (ctm[i] > 1e10) {
2616       ctm[i] = 1e10;
2617     } else if (ctm[i] < -1e10) {
2618       ctm[i] = -1e10;
2619     }
2620   }
2621 }
2622
2623 void GfxState::concatCTM(double a, double b, double c,
2624                          double d, double e, double f) {
2625   double a1 = ctm[0];
2626   double b1 = ctm[1];
2627   double c1 = ctm[2];
2628   double d1 = ctm[3];
2629   int i;
2630
2631   ctm[0] = a * a1 + b * c1;
2632   ctm[1] = a * b1 + b * d1;
2633   ctm[2] = c * a1 + d * c1;
2634   ctm[3] = c * b1 + d * d1;
2635   ctm[4] = e * a1 + f * c1 + ctm[4];
2636   ctm[5] = e * b1 + f * d1 + ctm[5];
2637
2638   // avoid FP exceptions on badly messed up PDF files
2639   for (i = 0; i < 6; ++i) {
2640     if (ctm[i] > 1e10) {
2641       ctm[i] = 1e10;
2642     } else if (ctm[i] < -1e10) {
2643       ctm[i] = -1e10;
2644     }
2645   }
2646 }
2647
2648 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2649   if (fillColorSpace) {
2650     delete fillColorSpace;
2651   }
2652   fillColorSpace = colorSpace;
2653 }
2654
2655 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2656   if (strokeColorSpace) {
2657     delete strokeColorSpace;
2658   }
2659   strokeColorSpace = colorSpace;
2660 }
2661
2662 void GfxState::setFillPattern(GfxPattern *pattern) {
2663   if (fillPattern) {
2664     delete fillPattern;
2665   }
2666   fillPattern = pattern;
2667 }
2668
2669 void GfxState::setStrokePattern(GfxPattern *pattern) {
2670   if (strokePattern) {
2671     delete strokePattern;
2672   }
2673   strokePattern = pattern;
2674 }
2675
2676 void GfxState::setLineDash(double *dash, int length, double start) {
2677   if (lineDash)
2678     gfree(lineDash);
2679   lineDash = dash;
2680   lineDashLength = length;
2681   lineDashStart = start;
2682 }
2683
2684 void GfxState::clearPath() {
2685   delete path;
2686   path = new GfxPath();
2687 }
2688
2689 void GfxState::clip() {
2690   double xMin, yMin, xMax, yMax, x, y;
2691   GfxSubpath *subpath;
2692   int i, j;
2693
2694   xMin = xMax = yMin = yMax = 0; // make gcc happy
2695   for (i = 0; i < path->getNumSubpaths(); ++i) {
2696     subpath = path->getSubpath(i);
2697     for (j = 0; j < subpath->getNumPoints(); ++j) {
2698       transform(subpath->getX(j), subpath->getY(j), &x, &y);
2699       if (i == 0 && j == 0) {
2700         xMin = xMax = x;
2701         yMin = yMax = y;
2702       } else {
2703         if (x < xMin) {
2704           xMin = x;
2705         } else if (x > xMax) {
2706           xMax = x;
2707         }
2708         if (y < yMin) {
2709           yMin = y;
2710         } else if (y > yMax) {
2711           yMax = y;
2712         }
2713       }
2714     }
2715   }
2716   if (xMin > clipXMin) {
2717     clipXMin = xMin;
2718   }
2719   if (yMin > clipYMin) {
2720     clipYMin = yMin;
2721   }
2722   if (xMax < clipXMax) {
2723     clipXMax = xMax;
2724   }
2725   if (yMax < clipYMax) {
2726     clipYMax = yMax;
2727   }
2728 }
2729
2730 void GfxState::textShift(double tx, double ty) {
2731   double dx, dy;
2732
2733   textTransformDelta(tx, ty, &dx, &dy);
2734   curX += dx;
2735   curY += dy;
2736 }
2737
2738 void GfxState::shift(double dx, double dy) {
2739   curX += dx;
2740   curY += dy;
2741 }
2742
2743 GfxState *GfxState::save() {
2744   GfxState *newState;
2745
2746   newState = copy();
2747   newState->saved = this;
2748   return newState;
2749 }
2750
2751 GfxState *GfxState::restore() {
2752   GfxState *oldState;
2753
2754   if (saved) {
2755     oldState = saved;
2756
2757     // these attributes aren't saved/restored by the q/Q operators
2758     oldState->path = path;
2759     oldState->curX = curX;
2760     oldState->curY = curY;
2761     oldState->lineX = lineX;
2762     oldState->lineY = lineY;
2763
2764     path = NULL;
2765     saved = NULL;
2766     delete this;
2767
2768   } else {
2769     oldState = this;
2770   }
2771
2772   return oldState;
2773 }