]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/GfxState.cc
implement get/set properties
[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");
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 (nCompsA > gfxColorMaxComps) {
718     error(-1, "ICCBased color space with too many (%d > %d) components",
719           nCompsA, gfxColorMaxComps);
720     nCompsA = gfxColorMaxComps;
721   }
722   if (dict->lookup("Alternate", &obj2)->isNull() ||
723       !(altA = GfxColorSpace::parse(&obj2))) {
724     switch (nCompsA) {
725     case 1:
726       altA = new GfxDeviceGrayColorSpace();
727       break;
728     case 3:
729       altA = new GfxDeviceRGBColorSpace();
730       break;
731     case 4:
732       altA = new GfxDeviceCMYKColorSpace();
733       break;
734     default:
735       error(-1, "Bad ICCBased color space - invalid N");
736       obj2.free();
737       obj1.free();
738       return NULL;
739     }
740   }
741   obj2.free();
742   cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
743   if (dict->lookup("Range", &obj2)->isArray() &&
744       obj2.arrayGetLength() == 2 * nCompsA) {
745     for (i = 0; i < nCompsA; ++i) {
746       obj2.arrayGet(2*i, &obj3);
747       cs->rangeMin[i] = obj3.getNum();
748       obj3.free();
749       obj2.arrayGet(2*i+1, &obj3);
750       cs->rangeMax[i] = obj3.getNum();
751       obj3.free();
752     }
753   }
754   obj2.free();
755   obj1.free();
756   return cs;
757 }
758
759 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
760   alt->getGray(color, gray);
761 }
762
763 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
764   alt->getRGB(color, rgb);
765 }
766
767 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
768   alt->getCMYK(color, cmyk);
769 }
770
771 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
772                                              double *decodeRange,
773                                              int maxImgPixel) {
774   alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
775
776 #if 0
777   // this is nominally correct, but some PDF files don't set the
778   // correct ranges in the ICCBased dict
779   int i;
780
781   for (i = 0; i < nComps; ++i) {
782     decodeLow[i] = rangeMin[i];
783     decodeRange[i] = rangeMax[i] - rangeMin[i];
784   }
785 #endif
786 }
787
788 //------------------------------------------------------------------------
789 // GfxIndexedColorSpace
790 //------------------------------------------------------------------------
791
792 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
793                                            int indexHighA) {
794   base = baseA;
795   indexHigh = indexHighA;
796   lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
797                              sizeof(Guchar));
798 }
799
800 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
801   delete base;
802   gfree(lookup);
803 }
804
805 GfxColorSpace *GfxIndexedColorSpace::copy() {
806   GfxIndexedColorSpace *cs;
807
808   cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
809   memcpy(cs->lookup, lookup,
810          (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
811   return cs;
812 }
813
814 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
815   GfxIndexedColorSpace *cs;
816   GfxColorSpace *baseA;
817   int indexHighA;
818   Object obj1;
819   int x;
820   char *s;
821   int n, i, j;
822
823   if (arr->getLength() != 4) {
824     error(-1, "Bad Indexed color space");
825     goto err1;
826   }
827   arr->get(1, &obj1);
828   if (!(baseA = GfxColorSpace::parse(&obj1))) {
829     error(-1, "Bad Indexed color space (base color space)");
830     goto err2;
831   }
832   obj1.free();
833   if (!arr->get(2, &obj1)->isInt()) {
834     error(-1, "Bad Indexed color space (hival)");
835     delete baseA;
836     goto err2;
837   }
838   indexHighA = obj1.getInt();
839   if (indexHighA < 0 || indexHighA > 255) {
840     // the PDF spec requires indexHigh to be in [0,255] -- allowing
841     // values larger than 255 creates a security hole: if nComps *
842     // indexHigh is greater than 2^31, the loop below may overwrite
843     // past the end of the array
844     error(-1, "Bad Indexed color space (invalid indexHigh value)");
845     delete baseA;
846     goto err2;
847   }
848   obj1.free();
849   cs = new GfxIndexedColorSpace(baseA, indexHighA);
850   arr->get(3, &obj1);
851   n = baseA->getNComps();
852   if (obj1.isStream()) {
853     obj1.streamReset();
854     for (i = 0; i <= indexHighA; ++i) {
855       for (j = 0; j < n; ++j) {
856         if ((x = obj1.streamGetChar()) == EOF) {
857           error(-1, "Bad Indexed color space (lookup table stream too short)");
858           goto err3;
859         }
860         cs->lookup[i*n + j] = (Guchar)x;
861       }
862     }
863     obj1.streamClose();
864   } else if (obj1.isString()) {
865     if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
866       error(-1, "Bad Indexed color space (lookup table string too short)");
867       goto err3;
868     }
869     s = obj1.getString()->getCString();
870     for (i = 0; i <= indexHighA; ++i) {
871       for (j = 0; j < n; ++j) {
872         cs->lookup[i*n + j] = (Guchar)*s++;
873       }
874     }
875   } else {
876     error(-1, "Bad Indexed color space (lookup table)");
877     goto err3;
878   }
879   obj1.free();
880   return cs;
881
882  err3:
883   delete cs;
884  err2:
885   obj1.free();
886  err1:
887   return NULL;
888 }
889
890 GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
891                                                GfxColor *baseColor) {
892   Guchar *p;
893   double low[gfxColorMaxComps], range[gfxColorMaxComps];
894   int n, i;
895
896   n = base->getNComps();
897   base->getDefaultRanges(low, range, indexHigh);
898   p = &lookup[(int)(color->c[0] + 0.5) * n];
899   for (i = 0; i < n; ++i) {
900     baseColor->c[i] = low[i] + (p[i] / 255.0) * range[i];
901   }
902   return baseColor;
903 }
904
905 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
906   GfxColor color2;
907
908   base->getGray(mapColorToBase(color, &color2), gray);
909 }
910
911 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
912   GfxColor color2;
913
914   base->getRGB(mapColorToBase(color, &color2), rgb);
915 }
916
917 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
918   GfxColor color2;
919
920   base->getCMYK(mapColorToBase(color, &color2), cmyk);
921 }
922
923 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
924                                             double *decodeRange,
925                                             int maxImgPixel) {
926   decodeLow[0] = 0;
927   decodeRange[0] = maxImgPixel;
928 }
929
930 //------------------------------------------------------------------------
931 // GfxSeparationColorSpace
932 //------------------------------------------------------------------------
933
934 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
935                                                  GfxColorSpace *altA,
936                                                  Function *funcA) {
937   name = nameA;
938   alt = altA;
939   func = funcA;
940 }
941
942 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
943   delete name;
944   delete alt;
945   delete func;
946 }
947
948 GfxColorSpace *GfxSeparationColorSpace::copy() {
949   return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
950 }
951
952 //~ handle the 'All' and 'None' colorants
953 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
954   GfxSeparationColorSpace *cs;
955   GString *nameA;
956   GfxColorSpace *altA;
957   Function *funcA;
958   Object obj1;
959
960   if (arr->getLength() != 4) {
961     error(-1, "Bad Separation color space");
962     goto err1;
963   }
964   if (!arr->get(1, &obj1)->isName()) {
965     error(-1, "Bad Separation color space (name)");
966     goto err2;
967   }
968   nameA = new GString(obj1.getName());
969   obj1.free();
970   arr->get(2, &obj1);
971   if (!(altA = GfxColorSpace::parse(&obj1))) {
972     error(-1, "Bad Separation color space (alternate color space)");
973     goto err3;
974   }
975   obj1.free();
976   arr->get(3, &obj1);
977   if (!(funcA = Function::parse(&obj1))) {
978     goto err4;
979   }
980   obj1.free();
981   cs = new GfxSeparationColorSpace(nameA, altA, funcA);
982   return cs;
983
984  err4:
985   delete altA;
986  err3:
987   delete nameA;
988  err2:
989   obj1.free();
990  err1:
991   return NULL;
992 }
993
994 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
995   GfxColor color2;
996
997   func->transform(color->c, color2.c);
998   alt->getGray(&color2, gray);
999 }
1000
1001 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1002   GfxColor color2;
1003
1004   func->transform(color->c, color2.c);
1005   alt->getRGB(&color2, rgb);
1006 }
1007
1008 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1009   GfxColor color2;
1010
1011   func->transform(color->c, color2.c);
1012   alt->getCMYK(&color2, cmyk);
1013 }
1014
1015 //------------------------------------------------------------------------
1016 // GfxDeviceNColorSpace
1017 //------------------------------------------------------------------------
1018
1019 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1020                                            GfxColorSpace *altA,
1021                                            Function *funcA) {
1022   nComps = nCompsA;
1023   alt = altA;
1024   func = funcA;
1025 }
1026
1027 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1028   int i;
1029
1030   for (i = 0; i < nComps; ++i) {
1031     delete names[i];
1032   }
1033   delete alt;
1034   delete func;
1035 }
1036
1037 GfxColorSpace *GfxDeviceNColorSpace::copy() {
1038   GfxDeviceNColorSpace *cs;
1039   int i;
1040
1041   cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
1042   for (i = 0; i < nComps; ++i) {
1043     cs->names[i] = names[i]->copy();
1044   }
1045   return cs;
1046 }
1047
1048 //~ handle the 'None' colorant
1049 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1050   GfxDeviceNColorSpace *cs;
1051   int nCompsA;
1052   GString *namesA[gfxColorMaxComps];
1053   GfxColorSpace *altA;
1054   Function *funcA;
1055   Object obj1, obj2;
1056   int i;
1057
1058   if (arr->getLength() != 4 && arr->getLength() != 5) {
1059     error(-1, "Bad DeviceN color space");
1060     goto err1;
1061   }
1062   if (!arr->get(1, &obj1)->isArray()) {
1063     error(-1, "Bad DeviceN color space (names)");
1064     goto err2;
1065   }
1066   nCompsA = obj1.arrayGetLength();
1067   if (nCompsA > gfxColorMaxComps) {
1068     error(-1, "DeviceN color space with too many (%d > %d) components",
1069           nCompsA, gfxColorMaxComps);
1070     nCompsA = gfxColorMaxComps;
1071   }
1072   for (i = 0; i < nCompsA; ++i) {
1073     if (!obj1.arrayGet(i, &obj2)->isName()) {
1074       error(-1, "Bad DeviceN color space (names)");
1075       obj2.free();
1076       goto err2;
1077     }
1078     namesA[i] = new GString(obj2.getName());
1079     obj2.free();
1080   }
1081   obj1.free();
1082   arr->get(2, &obj1);
1083   if (!(altA = GfxColorSpace::parse(&obj1))) {
1084     error(-1, "Bad DeviceN color space (alternate color space)");
1085     goto err3;
1086   }
1087   obj1.free();
1088   arr->get(3, &obj1);
1089   if (!(funcA = Function::parse(&obj1))) {
1090     goto err4;
1091   }
1092   obj1.free();
1093   cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1094   for (i = 0; i < nCompsA; ++i) {
1095     cs->names[i] = namesA[i];
1096   }
1097   return cs;
1098
1099  err4:
1100   delete altA;
1101  err3:
1102   for (i = 0; i < nCompsA; ++i) {
1103     delete namesA[i];
1104   }
1105  err2:
1106   obj1.free();
1107  err1:
1108   return NULL;
1109 }
1110
1111 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1112   GfxColor color2;
1113
1114   func->transform(color->c, color2.c);
1115   alt->getGray(&color2, gray);
1116 }
1117
1118 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1119   GfxColor color2;
1120
1121   func->transform(color->c, color2.c);
1122   alt->getRGB(&color2, rgb);
1123 }
1124
1125 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1126   GfxColor color2;
1127
1128   func->transform(color->c, color2.c);
1129   alt->getCMYK(&color2, cmyk);
1130 }
1131
1132 //------------------------------------------------------------------------
1133 // GfxPatternColorSpace
1134 //------------------------------------------------------------------------
1135
1136 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1137   under = underA;
1138 }
1139
1140 GfxPatternColorSpace::~GfxPatternColorSpace() {
1141   if (under) {
1142     delete under;
1143   }
1144 }
1145
1146 GfxColorSpace *GfxPatternColorSpace::copy() {
1147   return new GfxPatternColorSpace(under ? under->copy() :
1148                                           (GfxColorSpace *)NULL);
1149 }
1150
1151 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1152   GfxPatternColorSpace *cs;
1153   GfxColorSpace *underA;
1154   Object obj1;
1155
1156   if (arr->getLength() != 1 && arr->getLength() != 2) {
1157     error(-1, "Bad Pattern color space");
1158     return NULL;
1159   }
1160   underA = NULL;
1161   if (arr->getLength() == 2) {
1162     arr->get(1, &obj1);
1163     if (!(underA = GfxColorSpace::parse(&obj1))) {
1164       error(-1, "Bad Pattern color space (underlying color space)");
1165       obj1.free();
1166       return NULL;
1167     }
1168     obj1.free();
1169   }
1170   cs = new GfxPatternColorSpace(underA);
1171   return cs;
1172 }
1173
1174 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1175   *gray = 0;
1176 }
1177
1178 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1179   rgb->r = rgb->g = rgb->b = 0;
1180 }
1181
1182 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1183   cmyk->c = cmyk->m = cmyk->y = 0;
1184   cmyk->k = 1;
1185 }
1186
1187 //------------------------------------------------------------------------
1188 // Pattern
1189 //------------------------------------------------------------------------
1190
1191 GfxPattern::GfxPattern(int typeA) {
1192   type = typeA;
1193 }
1194
1195 GfxPattern::~GfxPattern() {
1196 }
1197
1198 GfxPattern *GfxPattern::parse(Object *obj) {
1199   GfxPattern *pattern;
1200   Object obj1;
1201
1202   if (obj->isDict()) {
1203     obj->dictLookup("PatternType", &obj1);
1204   } else if (obj->isStream()) {
1205     obj->streamGetDict()->lookup("PatternType", &obj1);
1206   } else {
1207     return NULL;
1208   }
1209   pattern = NULL;
1210   if (obj1.isInt() && obj1.getInt() == 1) {
1211     pattern = GfxTilingPattern::parse(obj);
1212   } else if (obj1.isInt() && obj1.getInt() == 2) {
1213     pattern = GfxShadingPattern::parse(obj);
1214   }
1215   obj1.free();
1216   return pattern;
1217 }
1218
1219 //------------------------------------------------------------------------
1220 // GfxTilingPattern
1221 //------------------------------------------------------------------------
1222
1223 GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
1224   GfxTilingPattern *pat;
1225   Dict *dict;
1226   int paintTypeA, tilingTypeA;
1227   double bboxA[4], matrixA[6];
1228   double xStepA, yStepA;
1229   Object resDictA;
1230   Object obj1, obj2;
1231   int i;
1232
1233   if (!patObj->isStream()) {
1234     return NULL;
1235   }
1236   dict = patObj->streamGetDict();
1237
1238   if (dict->lookup("PaintType", &obj1)->isInt()) {
1239     paintTypeA = obj1.getInt();
1240   } else {
1241     paintTypeA = 1;
1242     error(-1, "Invalid or missing PaintType in pattern");
1243   }
1244   obj1.free();
1245   if (dict->lookup("TilingType", &obj1)->isInt()) {
1246     tilingTypeA = obj1.getInt();
1247   } else {
1248     tilingTypeA = 1;
1249     error(-1, "Invalid or missing TilingType in pattern");
1250   }
1251   obj1.free();
1252   bboxA[0] = bboxA[1] = 0;
1253   bboxA[2] = bboxA[3] = 1;
1254   if (dict->lookup("BBox", &obj1)->isArray() &&
1255       obj1.arrayGetLength() == 4) {
1256     for (i = 0; i < 4; ++i) {
1257       if (obj1.arrayGet(i, &obj2)->isNum()) {
1258         bboxA[i] = obj2.getNum();
1259       }
1260       obj2.free();
1261     }
1262   } else {
1263     error(-1, "Invalid or missing BBox in pattern");
1264   }
1265   obj1.free();
1266   if (dict->lookup("XStep", &obj1)->isNum()) {
1267     xStepA = obj1.getNum();
1268   } else {
1269     xStepA = 1;
1270     error(-1, "Invalid or missing XStep in pattern");
1271   }
1272   obj1.free();
1273   if (dict->lookup("YStep", &obj1)->isNum()) {
1274     yStepA = obj1.getNum();
1275   } else {
1276     yStepA = 1;
1277     error(-1, "Invalid or missing YStep in pattern");
1278   }
1279   obj1.free();
1280   if (!dict->lookup("Resources", &resDictA)->isDict()) {
1281     resDictA.free();
1282     resDictA.initNull();
1283     error(-1, "Invalid or missing Resources in pattern");
1284   }
1285   matrixA[0] = 1; matrixA[1] = 0;
1286   matrixA[2] = 0; matrixA[3] = 1;
1287   matrixA[4] = 0; matrixA[5] = 0;
1288   if (dict->lookup("Matrix", &obj1)->isArray() &&
1289       obj1.arrayGetLength() == 6) {
1290     for (i = 0; i < 6; ++i) {
1291       if (obj1.arrayGet(i, &obj2)->isNum()) {
1292         matrixA[i] = obj2.getNum();
1293       }
1294       obj2.free();
1295     }
1296   }
1297   obj1.free();
1298
1299   pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
1300                              &resDictA, matrixA, patObj);
1301   resDictA.free();
1302   return pat;
1303 }
1304
1305 GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
1306                                    double *bboxA, double xStepA, double yStepA,
1307                                    Object *resDictA, double *matrixA,
1308                                    Object *contentStreamA):
1309   GfxPattern(1)
1310 {
1311   int i;
1312
1313   paintType = paintTypeA;
1314   tilingType = tilingTypeA;
1315   for (i = 0; i < 4; ++i) {
1316     bbox[i] = bboxA[i];
1317   }
1318   xStep = xStepA;
1319   yStep = yStepA;
1320   resDictA->copy(&resDict);
1321   for (i = 0; i < 6; ++i) {
1322     matrix[i] = matrixA[i];
1323   }
1324   contentStreamA->copy(&contentStream);
1325 }
1326
1327 GfxTilingPattern::~GfxTilingPattern() {
1328   resDict.free();
1329   contentStream.free();
1330 }
1331
1332 GfxPattern *GfxTilingPattern::copy() {
1333   return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
1334                               &resDict, matrix, &contentStream);
1335 }
1336
1337 //------------------------------------------------------------------------
1338 // GfxShadingPattern
1339 //------------------------------------------------------------------------
1340
1341 GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
1342   Dict *dict;
1343   GfxShading *shadingA;
1344   double matrixA[6];
1345   Object obj1, obj2;
1346   int i;
1347
1348   if (!patObj->isDict()) {
1349     return NULL;
1350   }
1351   dict = patObj->getDict();
1352
1353   dict->lookup("Shading", &obj1);
1354   shadingA = GfxShading::parse(&obj1);
1355   obj1.free();
1356   if (!shadingA) {
1357     return NULL;
1358   }
1359
1360   matrixA[0] = 1; matrixA[1] = 0;
1361   matrixA[2] = 0; matrixA[3] = 1;
1362   matrixA[4] = 0; matrixA[5] = 0;
1363   if (dict->lookup("Matrix", &obj1)->isArray() &&
1364       obj1.arrayGetLength() == 6) {
1365     for (i = 0; i < 6; ++i) {
1366       if (obj1.arrayGet(i, &obj2)->isNum()) {
1367         matrixA[i] = obj2.getNum();
1368       }
1369       obj2.free();
1370     }
1371   }
1372   obj1.free();
1373
1374   return new GfxShadingPattern(shadingA, matrixA);
1375 }
1376
1377 GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
1378   GfxPattern(2)
1379 {
1380   int i;
1381
1382   shading = shadingA;
1383   for (i = 0; i < 6; ++i) {
1384     matrix[i] = matrixA[i];
1385   }
1386 }
1387
1388 GfxShadingPattern::~GfxShadingPattern() {
1389   delete shading;
1390 }
1391
1392 GfxPattern *GfxShadingPattern::copy() {
1393   return new GfxShadingPattern(shading->copy(), matrix);
1394 }
1395
1396 //------------------------------------------------------------------------
1397 // GfxShading
1398 //------------------------------------------------------------------------
1399
1400 GfxShading::GfxShading(int typeA) {
1401   type = typeA;
1402   colorSpace = NULL;
1403 }
1404
1405 GfxShading::GfxShading(GfxShading *shading) {
1406   int i;
1407
1408   type = shading->type;
1409   colorSpace = shading->colorSpace->copy();
1410   for (i = 0; i < gfxColorMaxComps; ++i) {
1411     background.c[i] = shading->background.c[i];
1412   }
1413   hasBackground = shading->hasBackground;
1414   xMin = shading->xMin;
1415   yMin = shading->yMin;
1416   xMax = shading->xMax;
1417   yMax = shading->yMax;
1418   hasBBox = shading->hasBBox;
1419 }
1420
1421 GfxShading::~GfxShading() {
1422   if (colorSpace) {
1423     delete colorSpace;
1424   }
1425 }
1426
1427 GfxShading *GfxShading::parse(Object *obj) {
1428   GfxShading *shading;
1429   Dict *dict;
1430   int typeA;
1431   Object obj1;
1432
1433   if (obj->isDict()) {
1434     dict = obj->getDict();
1435   } else if (obj->isStream()) {
1436     dict = obj->streamGetDict();
1437   } else {
1438     return NULL;
1439   }
1440
1441   if (!dict->lookup("ShadingType", &obj1)->isInt()) {
1442     error(-1, "Invalid ShadingType in shading dictionary");
1443     obj1.free();
1444     return NULL;
1445   }
1446   typeA = obj1.getInt();
1447   obj1.free();
1448
1449   switch (typeA) {
1450   case 1:
1451     shading = GfxFunctionShading::parse(dict);
1452     break;
1453   case 2:
1454     shading = GfxAxialShading::parse(dict);
1455     break;
1456   case 3:
1457     shading = GfxRadialShading::parse(dict);
1458     break;
1459   default:
1460     error(-1, "Unimplemented shading type %d", typeA);
1461     goto err1;
1462   }
1463
1464   return shading;
1465
1466  err1:
1467   return NULL;
1468 }
1469
1470 GBool GfxShading::init(Dict *dict) {
1471   Object obj1, obj2;
1472   int i;
1473
1474   dict->lookup("ColorSpace", &obj1);
1475   if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
1476     error(-1, "Bad color space in shading dictionary");
1477     obj1.free();
1478     return gFalse;
1479   }
1480   obj1.free();
1481
1482   for (i = 0; i < gfxColorMaxComps; ++i) {
1483     background.c[i] = 0;
1484   }
1485   hasBackground = gFalse;
1486   if (dict->lookup("Background", &obj1)->isArray()) {
1487     if (obj1.arrayGetLength() == colorSpace->getNComps()) {
1488       hasBackground = gTrue;
1489       for (i = 0; i < colorSpace->getNComps(); ++i) {
1490         background.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1491         obj2.free();
1492       }
1493     } else {
1494       error(-1, "Bad Background in shading dictionary");
1495     }
1496   }
1497   obj1.free();
1498
1499   xMin = yMin = xMax = yMax = 0;
1500   hasBBox = gFalse;
1501   if (dict->lookup("BBox", &obj1)->isArray()) {
1502     if (obj1.arrayGetLength() == 4) {
1503       hasBBox = gTrue;
1504       xMin = obj1.arrayGet(0, &obj2)->getNum();
1505       obj2.free();
1506       yMin = obj1.arrayGet(1, &obj2)->getNum();
1507       obj2.free();
1508       xMax = obj1.arrayGet(2, &obj2)->getNum();
1509       obj2.free();
1510       yMax = obj1.arrayGet(3, &obj2)->getNum();
1511       obj2.free();
1512     } else {
1513       error(-1, "Bad BBox in shading dictionary");
1514     }
1515   }
1516   obj1.free();
1517
1518   return gTrue;
1519 }
1520
1521 //------------------------------------------------------------------------
1522 // GfxFunctionShading
1523 //------------------------------------------------------------------------
1524
1525 GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
1526                                        double x1A, double y1A,
1527                                        double *matrixA,
1528                                        Function **funcsA, int nFuncsA):
1529   GfxShading(1)
1530 {
1531   int i;
1532
1533   x0 = x0A;
1534   y0 = y0A;
1535   x1 = x1A;
1536   y1 = y1A;
1537   for (i = 0; i < 6; ++i) {
1538     matrix[i] = matrixA[i];
1539   }
1540   nFuncs = nFuncsA;
1541   for (i = 0; i < nFuncs; ++i) {
1542     funcs[i] = funcsA[i];
1543   }
1544 }
1545
1546 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
1547   GfxShading(shading)
1548 {
1549   int i;
1550
1551   x0 = shading->x0;
1552   y0 = shading->y0;
1553   x1 = shading->x1;
1554   y1 = shading->y1;
1555   for (i = 0; i < 6; ++i) {
1556     matrix[i] = shading->matrix[i];
1557   }
1558   nFuncs = shading->nFuncs;
1559   for (i = 0; i < nFuncs; ++i) {
1560     funcs[i] = shading->funcs[i]->copy();
1561   }
1562 }
1563
1564 GfxFunctionShading::~GfxFunctionShading() {
1565   int i;
1566
1567   for (i = 0; i < nFuncs; ++i) {
1568     delete funcs[i];
1569   }
1570 }
1571
1572 GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
1573   GfxFunctionShading *shading;
1574   double x0A, y0A, x1A, y1A;
1575   double matrixA[6];
1576   Function *funcsA[gfxColorMaxComps];
1577   int nFuncsA;
1578   Object obj1, obj2;
1579   int i;
1580
1581   x0A = y0A = 0;
1582   x1A = y1A = 1;
1583   if (dict->lookup("Domain", &obj1)->isArray() &&
1584       obj1.arrayGetLength() == 4) {
1585     x0A = obj1.arrayGet(0, &obj2)->getNum();
1586     obj2.free();
1587     y0A = obj1.arrayGet(1, &obj2)->getNum();
1588     obj2.free();
1589     x1A = obj1.arrayGet(2, &obj2)->getNum();
1590     obj2.free();
1591     y1A = obj1.arrayGet(3, &obj2)->getNum();
1592     obj2.free();
1593   }
1594   obj1.free();
1595
1596   matrixA[0] = 1; matrixA[1] = 0;
1597   matrixA[2] = 0; matrixA[3] = 1;
1598   matrixA[4] = 0; matrixA[5] = 0;
1599   if (dict->lookup("Matrix", &obj1)->isArray() &&
1600       obj1.arrayGetLength() == 6) {
1601     matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
1602     obj2.free();
1603     matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
1604     obj2.free();
1605     matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
1606     obj2.free();
1607     matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
1608     obj2.free();
1609     matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
1610     obj2.free();
1611     matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
1612     obj2.free();
1613   }
1614   obj1.free();
1615
1616   dict->lookup("Function", &obj1);
1617   if (obj1.isArray()) {
1618     nFuncsA = obj1.arrayGetLength();
1619     if (nFuncsA > gfxColorMaxComps) {
1620       error(-1, "Invalid Function array in shading dictionary");
1621       goto err1;
1622     }
1623     for (i = 0; i < nFuncsA; ++i) {
1624       obj1.arrayGet(i, &obj2);
1625       if (!(funcsA[i] = Function::parse(&obj2))) {
1626         goto err2;
1627       }
1628       obj2.free();
1629     }
1630   } else {
1631     nFuncsA = 1;
1632     if (!(funcsA[0] = Function::parse(&obj1))) {
1633       goto err1;
1634     }
1635   }
1636   obj1.free();
1637
1638   shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
1639                                    funcsA, nFuncsA);
1640   if (!shading->init(dict)) {
1641     delete shading;
1642     return NULL;
1643   }
1644   return shading;
1645
1646  err2:
1647   obj2.free();
1648  err1:
1649   obj1.free();
1650   return NULL;
1651 }
1652
1653 GfxShading *GfxFunctionShading::copy() {
1654   return new GfxFunctionShading(this);
1655 }
1656
1657 void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
1658   double in[2];
1659   int i;
1660
1661   in[0] = x;
1662   in[1] = y;
1663   for (i = 0; i < nFuncs; ++i) {
1664     funcs[i]->transform(in, &color->c[i]);
1665   }
1666 }
1667
1668 //------------------------------------------------------------------------
1669 // GfxAxialShading
1670 //------------------------------------------------------------------------
1671
1672 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1673                                  double x1A, double y1A,
1674                                  double t0A, double t1A,
1675                                  Function **funcsA, int nFuncsA,
1676                                  GBool extend0A, GBool extend1A):
1677   GfxShading(2)
1678 {
1679   int i;
1680
1681   x0 = x0A;
1682   y0 = y0A;
1683   x1 = x1A;
1684   y1 = y1A;
1685   t0 = t0A;
1686   t1 = t1A;
1687   nFuncs = nFuncsA;
1688   for (i = 0; i < nFuncs; ++i) {
1689     funcs[i] = funcsA[i];
1690   }
1691   extend0 = extend0A;
1692   extend1 = extend1A;
1693 }
1694
1695 GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
1696   GfxShading(shading)
1697 {
1698   int i;
1699
1700   x0 = shading->x0;
1701   y0 = shading->y0;
1702   x1 = shading->x1;
1703   y1 = shading->y1;
1704   t0 = shading->t0;
1705   y1 = shading->t1;
1706   nFuncs = shading->nFuncs;
1707   for (i = 0; i < nFuncs; ++i) {
1708     funcs[i] = shading->funcs[i]->copy();
1709   }
1710   extend0 = shading->extend0;
1711   extend1 = shading->extend1;
1712 }
1713
1714 GfxAxialShading::~GfxAxialShading() {
1715   int i;
1716
1717   for (i = 0; i < nFuncs; ++i) {
1718     delete funcs[i];
1719   }
1720 }
1721
1722 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1723   GfxAxialShading *shading;
1724   double x0A, y0A, x1A, y1A;
1725   double t0A, t1A;
1726   Function *funcsA[gfxColorMaxComps];
1727   int nFuncsA;
1728   GBool extend0A, extend1A;
1729   Object obj1, obj2;
1730   int i;
1731
1732   x0A = y0A = x1A = y1A = 0;
1733   if (dict->lookup("Coords", &obj1)->isArray() &&
1734       obj1.arrayGetLength() == 4) {
1735     x0A = obj1.arrayGet(0, &obj2)->getNum();
1736     obj2.free();
1737     y0A = obj1.arrayGet(1, &obj2)->getNum();
1738     obj2.free();
1739     x1A = obj1.arrayGet(2, &obj2)->getNum();
1740     obj2.free();
1741     y1A = obj1.arrayGet(3, &obj2)->getNum();
1742     obj2.free();
1743   } else {
1744     error(-1, "Missing or invalid Coords in shading dictionary");
1745     goto err1;
1746   }
1747   obj1.free();
1748
1749   t0A = 0;
1750   t1A = 1;
1751   if (dict->lookup("Domain", &obj1)->isArray() &&
1752       obj1.arrayGetLength() == 2) {
1753     t0A = obj1.arrayGet(0, &obj2)->getNum();
1754     obj2.free();
1755     t1A = obj1.arrayGet(1, &obj2)->getNum();
1756     obj2.free();
1757   }
1758   obj1.free();
1759
1760   dict->lookup("Function", &obj1);
1761   if (obj1.isArray()) {
1762     nFuncsA = obj1.arrayGetLength();
1763     if (nFuncsA > gfxColorMaxComps) {
1764       error(-1, "Invalid Function array in shading dictionary");
1765       goto err1;
1766     }
1767     for (i = 0; i < nFuncsA; ++i) {
1768       obj1.arrayGet(i, &obj2);
1769       if (!(funcsA[i] = Function::parse(&obj2))) {
1770         obj1.free();
1771         obj2.free();
1772         goto err1;
1773       }
1774       obj2.free();
1775     }
1776   } else {
1777     nFuncsA = 1;
1778     if (!(funcsA[0] = Function::parse(&obj1))) {
1779       obj1.free();
1780       goto err1;
1781     }
1782   }
1783   obj1.free();
1784
1785   extend0A = extend1A = gFalse;
1786   if (dict->lookup("Extend", &obj1)->isArray() &&
1787       obj1.arrayGetLength() == 2) {
1788     extend0A = obj1.arrayGet(0, &obj2)->getBool();
1789     obj2.free();
1790     extend1A = obj1.arrayGet(1, &obj2)->getBool();
1791     obj2.free();
1792   }
1793   obj1.free();
1794
1795   shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1796                                 funcsA, nFuncsA, extend0A, extend1A);
1797   if (!shading->init(dict)) {
1798     delete shading;
1799     return NULL;
1800   }
1801   return shading;
1802
1803  err1:
1804   return NULL;
1805 }
1806
1807 GfxShading *GfxAxialShading::copy() {
1808   return new GfxAxialShading(this);
1809 }
1810
1811 void GfxAxialShading::getColor(double t, GfxColor *color) {
1812   int i;
1813
1814   // NB: there can be one function with n outputs or n functions with
1815   // one output each (where n = number of color components)
1816   for (i = 0; i < nFuncs; ++i) {
1817     funcs[i]->transform(&t, &color->c[i]);
1818   }
1819 }
1820
1821 //------------------------------------------------------------------------
1822 // GfxRadialShading
1823 //------------------------------------------------------------------------
1824
1825 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
1826                                    double x1A, double y1A, double r1A,
1827                                    double t0A, double t1A,
1828                                    Function **funcsA, int nFuncsA,
1829                                    GBool extend0A, GBool extend1A):
1830   GfxShading(3)
1831 {
1832   int i;
1833
1834   x0 = x0A;
1835   y0 = y0A;
1836   r0 = r0A;
1837   x1 = x1A;
1838   y1 = y1A;
1839   r1 = r1A;
1840   t0 = t0A;
1841   t1 = t1A;
1842   nFuncs = nFuncsA;
1843   for (i = 0; i < nFuncs; ++i) {
1844     funcs[i] = funcsA[i];
1845   }
1846   extend0 = extend0A;
1847   extend1 = extend1A;
1848 }
1849
1850 GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
1851   GfxShading(shading)
1852 {
1853   int i;
1854
1855   x0 = shading->x0;
1856   y0 = shading->y0;
1857   r0 = shading->r0;
1858   x1 = shading->x1;
1859   y1 = shading->y1;
1860   r1 = shading->r1;
1861   t0 = shading->t0;
1862   y1 = shading->t1;
1863   nFuncs = shading->nFuncs;
1864   for (i = 0; i < nFuncs; ++i) {
1865     funcs[i] = shading->funcs[i]->copy();
1866   }
1867   extend0 = shading->extend0;
1868   extend1 = shading->extend1;
1869 }
1870
1871 GfxRadialShading::~GfxRadialShading() {
1872   int i;
1873
1874   for (i = 0; i < nFuncs; ++i) {
1875     delete funcs[i];
1876   }
1877 }
1878
1879 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
1880   GfxRadialShading *shading;
1881   double x0A, y0A, r0A, x1A, y1A, r1A;
1882   double t0A, t1A;
1883   Function *funcsA[gfxColorMaxComps];
1884   int nFuncsA;
1885   GBool extend0A, extend1A;
1886   Object obj1, obj2;
1887   int i;
1888
1889   x0A = y0A = r0A = x1A = y1A = r1A = 0;
1890   if (dict->lookup("Coords", &obj1)->isArray() &&
1891       obj1.arrayGetLength() == 6) {
1892     x0A = obj1.arrayGet(0, &obj2)->getNum();
1893     obj2.free();
1894     y0A = obj1.arrayGet(1, &obj2)->getNum();
1895     obj2.free();
1896     r0A = obj1.arrayGet(2, &obj2)->getNum();
1897     obj2.free();
1898     x1A = obj1.arrayGet(3, &obj2)->getNum();
1899     obj2.free();
1900     y1A = obj1.arrayGet(4, &obj2)->getNum();
1901     obj2.free();
1902     r1A = obj1.arrayGet(5, &obj2)->getNum();
1903     obj2.free();
1904   } else {
1905     error(-1, "Missing or invalid Coords in shading dictionary");
1906     goto err1;
1907   }
1908   obj1.free();
1909
1910   t0A = 0;
1911   t1A = 1;
1912   if (dict->lookup("Domain", &obj1)->isArray() &&
1913       obj1.arrayGetLength() == 2) {
1914     t0A = obj1.arrayGet(0, &obj2)->getNum();
1915     obj2.free();
1916     t1A = obj1.arrayGet(1, &obj2)->getNum();
1917     obj2.free();
1918   }
1919   obj1.free();
1920
1921   dict->lookup("Function", &obj1);
1922   if (obj1.isArray()) {
1923     nFuncsA = obj1.arrayGetLength();
1924     if (nFuncsA > gfxColorMaxComps) {
1925       error(-1, "Invalid Function array in shading dictionary");
1926       goto err1;
1927     }
1928     for (i = 0; i < nFuncsA; ++i) {
1929       obj1.arrayGet(i, &obj2);
1930       if (!(funcsA[i] = Function::parse(&obj2))) {
1931         obj1.free();
1932         obj2.free();
1933         goto err1;
1934       }
1935       obj2.free();
1936     }
1937   } else {
1938     nFuncsA = 1;
1939     if (!(funcsA[0] = Function::parse(&obj1))) {
1940       obj1.free();
1941       goto err1;
1942     }
1943   }
1944   obj1.free();
1945
1946   extend0A = extend1A = gFalse;
1947   if (dict->lookup("Extend", &obj1)->isArray() &&
1948       obj1.arrayGetLength() == 2) {
1949     extend0A = obj1.arrayGet(0, &obj2)->getBool();
1950     obj2.free();
1951     extend1A = obj1.arrayGet(1, &obj2)->getBool();
1952     obj2.free();
1953   }
1954   obj1.free();
1955
1956   shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
1957                                  funcsA, nFuncsA, extend0A, extend1A);
1958   if (!shading->init(dict)) {
1959     delete shading;
1960     return NULL;
1961   }
1962   return shading;
1963
1964  err1:
1965   return NULL;
1966 }
1967
1968 GfxShading *GfxRadialShading::copy() {
1969   return new GfxRadialShading(this);
1970 }
1971
1972 void GfxRadialShading::getColor(double t, GfxColor *color) {
1973   int i;
1974
1975   // NB: there can be one function with n outputs or n functions with
1976   // one output each (where n = number of color components)
1977   for (i = 0; i < nFuncs; ++i) {
1978     funcs[i]->transform(&t, &color->c[i]);
1979   }
1980 }
1981
1982 //------------------------------------------------------------------------
1983 // GfxImageColorMap
1984 //------------------------------------------------------------------------
1985
1986 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1987                                    GfxColorSpace *colorSpaceA) {
1988   GfxIndexedColorSpace *indexedCS;
1989   GfxSeparationColorSpace *sepCS;
1990   int maxPixel, indexHigh;
1991   Guchar *lookup2;
1992   Function *sepFunc;
1993   Object obj;
1994   double x[gfxColorMaxComps];
1995   double y[gfxColorMaxComps];
1996   int i, j, k;
1997
1998   ok = gTrue;
1999
2000   // bits per component and color space
2001   bits = bitsA;
2002   maxPixel = (1 << bits) - 1;
2003   colorSpace = colorSpaceA;
2004
2005   // get decode map
2006   if (decode->isNull()) {
2007     nComps = colorSpace->getNComps();
2008     colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
2009   } else if (decode->isArray()) {
2010     nComps = decode->arrayGetLength() / 2;
2011     if (nComps != colorSpace->getNComps()) {
2012       goto err1;
2013     }
2014     for (i = 0; i < nComps; ++i) {
2015       decode->arrayGet(2*i, &obj);
2016       if (!obj.isNum()) {
2017         goto err2;
2018       }
2019       decodeLow[i] = obj.getNum();
2020       obj.free();
2021       decode->arrayGet(2*i+1, &obj);
2022       if (!obj.isNum()) {
2023         goto err2;
2024       }
2025       decodeRange[i] = obj.getNum() - decodeLow[i];
2026       obj.free();
2027     }
2028   } else {
2029     goto err1;
2030   }
2031
2032   // Construct a lookup table -- this stores pre-computed decoded
2033   // values for each component, i.e., the result of applying the
2034   // decode mapping to each possible image pixel component value.
2035   //
2036   // Optimization: for Indexed and Separation color spaces (which have
2037   // only one component), we store color values in the lookup table
2038   // rather than component values.
2039   colorSpace2 = NULL;
2040   nComps2 = 0;
2041   if (colorSpace->getMode() == csIndexed) {
2042     // Note that indexHigh may not be the same as maxPixel --
2043     // Distiller will remove unused palette entries, resulting in
2044     // indexHigh < maxPixel.
2045     indexedCS = (GfxIndexedColorSpace *)colorSpace;
2046     colorSpace2 = indexedCS->getBase();
2047     indexHigh = indexedCS->getIndexHigh();
2048     nComps2 = colorSpace2->getNComps();
2049     lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
2050     lookup2 = indexedCS->getLookup();
2051     colorSpace2->getDefaultRanges(x, y, indexHigh);
2052     for (i = 0; i <= maxPixel; ++i) {
2053       j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
2054       if (j < 0) {
2055         j = 0;
2056       } else if (j > indexHigh) {
2057         j = indexHigh;
2058       }
2059       for (k = 0; k < nComps2; ++k) {
2060         lookup[i*nComps2 + k] = x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k];
2061       }
2062     }
2063   } else if (colorSpace->getMode() == csSeparation) {
2064     sepCS = (GfxSeparationColorSpace *)colorSpace;
2065     colorSpace2 = sepCS->getAlt();
2066     nComps2 = colorSpace2->getNComps();
2067     lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
2068     sepFunc = sepCS->getFunc();
2069     for (i = 0; i <= maxPixel; ++i) {
2070       x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
2071       sepFunc->transform(x, y);
2072       for (k = 0; k < nComps2; ++k) {
2073         lookup[i*nComps2 + k] = y[k];
2074       }
2075     }
2076   } else {
2077     lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
2078     for (i = 0; i <= maxPixel; ++i) {
2079       for (k = 0; k < nComps; ++k) {
2080         lookup[i*nComps + k] = decodeLow[k] +
2081                                  (i * decodeRange[k]) / maxPixel;
2082       }
2083     }
2084   }
2085
2086   return;
2087
2088  err2:
2089   obj.free();
2090  err1:
2091   ok = gFalse;
2092 }
2093
2094 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
2095   int n, i;
2096
2097   colorSpace = colorMap->colorSpace->copy();
2098   bits = colorMap->bits;
2099   nComps = colorMap->nComps;
2100   nComps2 = colorMap->nComps2;
2101   colorSpace2 = NULL;
2102   lookup = NULL;
2103   n = 1 << bits;
2104   if (colorSpace->getMode() == csIndexed) {
2105     colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
2106     n = n * nComps2 * sizeof(double);
2107   } else if (colorSpace->getMode() == csSeparation) {
2108     colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
2109     n = n * nComps2 * sizeof(double);
2110   } else {
2111     n = n * nComps * sizeof(double);
2112   }
2113   lookup = (double *)gmalloc(n);
2114   memcpy(lookup, colorMap->lookup, n);
2115   for (i = 0; i < nComps; ++i) {
2116     decodeLow[i] = colorMap->decodeLow[i];
2117     decodeRange[i] = colorMap->decodeRange[i];
2118   }
2119   ok = gTrue;
2120 }
2121
2122 GfxImageColorMap::~GfxImageColorMap() {
2123   delete colorSpace;
2124   gfree(lookup);
2125 }
2126
2127 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
2128   GfxColor color;
2129   double *p;
2130   int i;
2131
2132   if (colorSpace2) {
2133     p = &lookup[x[0] * nComps2];
2134     for (i = 0; i < nComps2; ++i) {
2135       color.c[i] = *p++;
2136     }
2137     colorSpace2->getGray(&color, gray);
2138   } else {
2139     for (i = 0; i < nComps; ++i) {
2140       color.c[i] = lookup[x[i] * nComps + i];
2141     }
2142     colorSpace->getGray(&color, gray);
2143   }
2144 }
2145
2146 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
2147   GfxColor color;
2148   double *p;
2149   int i;
2150
2151   if (colorSpace2) {
2152     p = &lookup[x[0] * nComps2];
2153     for (i = 0; i < nComps2; ++i) {
2154       color.c[i] = *p++;
2155     }
2156     colorSpace2->getRGB(&color, rgb);
2157   } else {
2158     for (i = 0; i < nComps; ++i) {
2159       color.c[i] = lookup[x[i] * nComps + i];
2160     }
2161     colorSpace->getRGB(&color, rgb);
2162   }
2163 }
2164
2165 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
2166   GfxColor color;
2167   double *p;
2168   int i;
2169
2170   if (colorSpace2) {
2171     p = &lookup[x[0] * nComps2];
2172     for (i = 0; i < nComps2; ++i) {
2173       color.c[i] = *p++;
2174     }
2175     colorSpace2->getCMYK(&color, cmyk);
2176   } else {
2177     for (i = 0; i < nComps; ++i) {
2178       color.c[i] = lookup[x[i] * nComps + i];
2179     }
2180     colorSpace->getCMYK(&color, cmyk);
2181   }
2182 }
2183
2184 void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
2185   int maxPixel, i;
2186
2187   maxPixel = (1 << bits) - 1;
2188   for (i = 0; i < nComps; ++i) {
2189     color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel;
2190   }
2191 }
2192
2193 //------------------------------------------------------------------------
2194 // GfxSubpath and GfxPath
2195 //------------------------------------------------------------------------
2196
2197 GfxSubpath::GfxSubpath(double x1, double y1) {
2198   size = 16;
2199   x = (double *)gmalloc(size * sizeof(double));
2200   y = (double *)gmalloc(size * sizeof(double));
2201   curve = (GBool *)gmalloc(size * sizeof(GBool));
2202   n = 1;
2203   x[0] = x1;
2204   y[0] = y1;
2205   curve[0] = gFalse;
2206   closed = gFalse;
2207 }
2208
2209 GfxSubpath::~GfxSubpath() {
2210   gfree(x);
2211   gfree(y);
2212   gfree(curve);
2213 }
2214
2215 // Used for copy().
2216 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
2217   size = subpath->size;
2218   n = subpath->n;
2219   x = (double *)gmalloc(size * sizeof(double));
2220   y = (double *)gmalloc(size * sizeof(double));
2221   curve = (GBool *)gmalloc(size * sizeof(GBool));
2222   memcpy(x, subpath->x, n * sizeof(double));
2223   memcpy(y, subpath->y, n * sizeof(double));
2224   memcpy(curve, subpath->curve, n * sizeof(GBool));
2225   closed = subpath->closed;
2226 }
2227
2228 void GfxSubpath::lineTo(double x1, double y1) {
2229   if (n >= size) {
2230     size += 16;
2231     x = (double *)grealloc(x, size * sizeof(double));
2232     y = (double *)grealloc(y, size * sizeof(double));
2233     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2234   }
2235   x[n] = x1;
2236   y[n] = y1;
2237   curve[n] = gFalse;
2238   ++n;
2239 }
2240
2241 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
2242                          double x3, double y3) {
2243   if (n+3 > size) {
2244     size += 16;
2245     x = (double *)grealloc(x, size * sizeof(double));
2246     y = (double *)grealloc(y, size * sizeof(double));
2247     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2248   }
2249   x[n] = x1;
2250   y[n] = y1;
2251   x[n+1] = x2;
2252   y[n+1] = y2;
2253   x[n+2] = x3;
2254   y[n+2] = y3;
2255   curve[n] = curve[n+1] = gTrue;
2256   curve[n+2] = gFalse;
2257   n += 3;
2258 }
2259
2260 void GfxSubpath::close() {
2261   if (x[n-1] != x[0] || y[n-1] != y[0]) {
2262     lineTo(x[0], y[0]);
2263   }
2264   closed = gTrue;
2265 }
2266
2267 void GfxSubpath::offset(double dx, double dy) {
2268   int i;
2269
2270   for (i = 0; i < n; ++i) {
2271     x[i] += dx;
2272     y[i] += dy;
2273   }
2274 }
2275
2276 GfxPath::GfxPath() {
2277   justMoved = gFalse;
2278   size = 16;
2279   n = 0;
2280   firstX = firstY = 0;
2281   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2282 }
2283
2284 GfxPath::~GfxPath() {
2285   int i;
2286
2287   for (i = 0; i < n; ++i)
2288     delete subpaths[i];
2289   gfree(subpaths);
2290 }
2291
2292 // Used for copy().
2293 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
2294                  GfxSubpath **subpaths1, int n1, int size1) {
2295   int i;
2296
2297   justMoved = justMoved1;
2298   firstX = firstX1;
2299   firstY = firstY1;
2300   size = size1;
2301   n = n1;
2302   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2303   for (i = 0; i < n; ++i)
2304     subpaths[i] = subpaths1[i]->copy();
2305 }
2306
2307 void GfxPath::moveTo(double x, double y) {
2308   justMoved = gTrue;
2309   firstX = x;
2310   firstY = y;
2311 }
2312
2313 void GfxPath::lineTo(double x, double y) {
2314   if (justMoved) {
2315     if (n >= size) {
2316       size += 16;
2317       subpaths = (GfxSubpath **)
2318                    grealloc(subpaths, size * sizeof(GfxSubpath *));
2319     }
2320     subpaths[n] = new GfxSubpath(firstX, firstY);
2321     ++n;
2322     justMoved = gFalse;
2323   }
2324   subpaths[n-1]->lineTo(x, y);
2325 }
2326
2327 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
2328              double x3, double y3) {
2329   if (justMoved) {
2330     if (n >= size) {
2331       size += 16;
2332       subpaths = (GfxSubpath **)
2333                    grealloc(subpaths, size * sizeof(GfxSubpath *));
2334     }
2335     subpaths[n] = new GfxSubpath(firstX, firstY);
2336     ++n;
2337     justMoved = gFalse;
2338   }
2339   subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
2340 }
2341
2342 void GfxPath::close() {
2343   // this is necessary to handle the pathological case of
2344   // moveto/closepath/clip, which defines an empty clipping region
2345   if (justMoved) {
2346     if (n >= size) {
2347       size += 16;
2348       subpaths = (GfxSubpath **)
2349                    grealloc(subpaths, size * sizeof(GfxSubpath *));
2350     }
2351     subpaths[n] = new GfxSubpath(firstX, firstY);
2352     ++n;
2353     justMoved = gFalse;
2354   }
2355   subpaths[n-1]->close();
2356 }
2357
2358 void GfxPath::append(GfxPath *path) {
2359   int i;
2360
2361   if (n + path->n > size) {
2362     size = n + path->n;
2363     subpaths = (GfxSubpath **)
2364                  grealloc(subpaths, size * sizeof(GfxSubpath *));
2365   }
2366   for (i = 0; i < path->n; ++i) {
2367     subpaths[n++] = path->subpaths[i]->copy();
2368   }
2369   justMoved = gFalse;
2370 }
2371
2372 void GfxPath::offset(double dx, double dy) {
2373   int i;
2374
2375   for (i = 0; i < n; ++i) {
2376     subpaths[i]->offset(dx, dy);
2377   }
2378 }
2379
2380 //------------------------------------------------------------------------
2381 // GfxState
2382 //------------------------------------------------------------------------
2383
2384 GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
2385                    int rotate, GBool upsideDown) {
2386   double kx, ky;
2387
2388   px1 = pageBox->x1;
2389   py1 = pageBox->y1;
2390   px2 = pageBox->x2;
2391   py2 = pageBox->y2;
2392   kx = hDPI / 72.0;
2393   ky = vDPI / 72.0;
2394   if (rotate == 90) {
2395     ctm[0] = 0;
2396     ctm[1] = upsideDown ? ky : -ky;
2397     ctm[2] = kx;
2398     ctm[3] = 0;
2399     ctm[4] = -kx * py1;
2400     ctm[5] = ky * (upsideDown ? -px1 : px2);
2401     pageWidth = kx * (py2 - py1);
2402     pageHeight = ky * (px2 - px1);
2403   } else if (rotate == 180) {
2404     ctm[0] = -kx;
2405     ctm[1] = 0;
2406     ctm[2] = 0;
2407     ctm[3] = upsideDown ? ky : -ky;
2408     ctm[4] = kx * px2;
2409     ctm[5] = ky * (upsideDown ? -py1 : py2);
2410     pageWidth = kx * (px2 - px1);
2411     pageHeight = ky * (py2 - py1);
2412   } else if (rotate == 270) {
2413     ctm[0] = 0;
2414     ctm[1] = upsideDown ? -ky : ky;
2415     ctm[2] = -kx;
2416     ctm[3] = 0;
2417     ctm[4] = kx * py2;
2418     ctm[5] = ky * (upsideDown ? px2 : -px1);
2419     pageWidth = kx * (py2 - py1);
2420     pageHeight = ky * (px2 - px1);
2421   } else {
2422     ctm[0] = kx;
2423     ctm[1] = 0;
2424     ctm[2] = 0;
2425     ctm[3] = upsideDown ? -ky : ky;
2426     ctm[4] = -kx * px1;
2427     ctm[5] = ky * (upsideDown ? py2 : -py1);
2428     pageWidth = kx * (px2 - px1);
2429     pageHeight = ky * (py2 - py1);
2430   }
2431
2432   fillColorSpace = new GfxDeviceGrayColorSpace();
2433   strokeColorSpace = new GfxDeviceGrayColorSpace();
2434   fillColor.c[0] = 0;
2435   strokeColor.c[0] = 0;
2436   fillPattern = NULL;
2437   strokePattern = NULL;
2438   fillOpacity = 1;
2439   strokeOpacity = 1;
2440
2441   lineWidth = 1;
2442   lineDash = NULL;
2443   lineDashLength = 0;
2444   lineDashStart = 0;
2445   flatness = 1;
2446   lineJoin = 0;
2447   lineCap = 0;
2448   miterLimit = 10;
2449
2450   font = NULL;
2451   fontSize = 0;
2452   textMat[0] = 1; textMat[1] = 0;
2453   textMat[2] = 0; textMat[3] = 1;
2454   textMat[4] = 0; textMat[5] = 0;
2455   charSpace = 0;
2456   wordSpace = 0;
2457   horizScaling = 1;
2458   leading = 0;
2459   rise = 0;
2460   render = 0;
2461
2462   path = new GfxPath();
2463   curX = curY = 0;
2464   lineX = lineY = 0;
2465
2466   clipXMin = 0;
2467   clipYMin = 0;
2468   clipXMax = pageWidth;
2469   clipYMax = pageHeight;
2470
2471   saved = NULL;
2472 }
2473
2474 GfxState::~GfxState() {
2475   if (fillColorSpace) {
2476     delete fillColorSpace;
2477   }
2478   if (strokeColorSpace) {
2479     delete strokeColorSpace;
2480   }
2481   if (fillPattern) {
2482     delete fillPattern;
2483   }
2484   if (strokePattern) {
2485     delete strokePattern;
2486   }
2487   gfree(lineDash);
2488   if (path) {
2489     // this gets set to NULL by restore()
2490     delete path;
2491   }
2492   if (saved) {
2493     delete saved;
2494   }
2495 }
2496
2497 // Used for copy();
2498 GfxState::GfxState(GfxState *state) {
2499   memcpy(this, state, sizeof(GfxState));
2500   if (fillColorSpace) {
2501     fillColorSpace = state->fillColorSpace->copy();
2502   }
2503   if (strokeColorSpace) {
2504     strokeColorSpace = state->strokeColorSpace->copy();
2505   }
2506   if (fillPattern) {
2507     fillPattern = state->fillPattern->copy();
2508   }
2509   if (strokePattern) {
2510     strokePattern = state->strokePattern->copy();
2511   }
2512   if (lineDashLength > 0) {
2513     lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2514     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2515   }
2516   saved = NULL;
2517 }
2518
2519 void GfxState::setPath(GfxPath *pathA) {
2520   delete path;
2521   path = pathA;
2522 }
2523
2524 void GfxState::getUserClipBBox(double *xMin, double *yMin,
2525                                double *xMax, double *yMax) {
2526   double ictm[6];
2527   double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
2528
2529   // invert the CTM
2530   det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2531   ictm[0] = ctm[3] * det;
2532   ictm[1] = -ctm[1] * det;
2533   ictm[2] = -ctm[2] * det;
2534   ictm[3] = ctm[0] * det;
2535   ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2536   ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2537
2538   // transform all four corners of the clip bbox; find the min and max
2539   // x and y values
2540   xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
2541   yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
2542   tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
2543   ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
2544   if (tx < xMin1) {
2545     xMin1 = tx;
2546   } else if (tx > xMax1) {
2547     xMax1 = tx;
2548   }
2549   if (ty < yMin1) {
2550     yMin1 = ty;
2551   } else if (ty > yMax1) {
2552     yMax1 = ty;
2553   }
2554   tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
2555   ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
2556   if (tx < xMin1) {
2557     xMin1 = tx;
2558   } else if (tx > xMax1) {
2559     xMax1 = tx;
2560   }
2561   if (ty < yMin1) {
2562     yMin1 = ty;
2563   } else if (ty > yMax1) {
2564     yMax1 = ty;
2565   }
2566   tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
2567   ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
2568   if (tx < xMin1) {
2569     xMin1 = tx;
2570   } else if (tx > xMax1) {
2571     xMax1 = tx;
2572   }
2573   if (ty < yMin1) {
2574     yMin1 = ty;
2575   } else if (ty > yMax1) {
2576     yMax1 = ty;
2577   }
2578
2579   *xMin = xMin1;
2580   *yMin = yMin1;
2581   *xMax = xMax1;
2582   *yMax = yMax1;
2583 }
2584
2585 double GfxState::transformWidth(double w) {
2586   double x, y;
2587
2588   x = ctm[0] + ctm[2];
2589   y = ctm[1] + ctm[3];
2590   return w * sqrt(0.5 * (x * x + y * y));
2591 }
2592
2593 double GfxState::getTransformedFontSize() {
2594   double x1, y1, x2, y2;
2595
2596   x1 = textMat[2] * fontSize;
2597   y1 = textMat[3] * fontSize;
2598   x2 = ctm[0] * x1 + ctm[2] * y1;
2599   y2 = ctm[1] * x1 + ctm[3] * y1;
2600   return sqrt(x2 * x2 + y2 * y2);
2601 }
2602
2603 void GfxState::getFontTransMat(double *m11, double *m12,
2604                                double *m21, double *m22) {
2605   *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2606   *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2607   *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2608   *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2609 }
2610
2611 void GfxState::setCTM(double a, double b, double c,
2612                       double d, double e, double f) {
2613   int i;
2614
2615   ctm[0] = a;
2616   ctm[1] = b;
2617   ctm[2] = c;
2618   ctm[3] = d;
2619   ctm[4] = e;
2620   ctm[5] = f;
2621
2622   // avoid FP exceptions on badly messed up PDF files
2623   for (i = 0; i < 6; ++i) {
2624     if (ctm[i] > 1e10) {
2625       ctm[i] = 1e10;
2626     } else if (ctm[i] < -1e10) {
2627       ctm[i] = -1e10;
2628     }
2629   }
2630 }
2631
2632 void GfxState::concatCTM(double a, double b, double c,
2633                          double d, double e, double f) {
2634   double a1 = ctm[0];
2635   double b1 = ctm[1];
2636   double c1 = ctm[2];
2637   double d1 = ctm[3];
2638   int i;
2639
2640   ctm[0] = a * a1 + b * c1;
2641   ctm[1] = a * b1 + b * d1;
2642   ctm[2] = c * a1 + d * c1;
2643   ctm[3] = c * b1 + d * d1;
2644   ctm[4] = e * a1 + f * c1 + ctm[4];
2645   ctm[5] = e * b1 + f * d1 + ctm[5];
2646
2647   // avoid FP exceptions on badly messed up PDF files
2648   for (i = 0; i < 6; ++i) {
2649     if (ctm[i] > 1e10) {
2650       ctm[i] = 1e10;
2651     } else if (ctm[i] < -1e10) {
2652       ctm[i] = -1e10;
2653     }
2654   }
2655 }
2656
2657 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2658   if (fillColorSpace) {
2659     delete fillColorSpace;
2660   }
2661   fillColorSpace = colorSpace;
2662 }
2663
2664 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2665   if (strokeColorSpace) {
2666     delete strokeColorSpace;
2667   }
2668   strokeColorSpace = colorSpace;
2669 }
2670
2671 void GfxState::setFillPattern(GfxPattern *pattern) {
2672   if (fillPattern) {
2673     delete fillPattern;
2674   }
2675   fillPattern = pattern;
2676 }
2677
2678 void GfxState::setStrokePattern(GfxPattern *pattern) {
2679   if (strokePattern) {
2680     delete strokePattern;
2681   }
2682   strokePattern = pattern;
2683 }
2684
2685 void GfxState::setLineDash(double *dash, int length, double start) {
2686   if (lineDash)
2687     gfree(lineDash);
2688   lineDash = dash;
2689   lineDashLength = length;
2690   lineDashStart = start;
2691 }
2692
2693 void GfxState::clearPath() {
2694   delete path;
2695   path = new GfxPath();
2696 }
2697
2698 void GfxState::clip() {
2699   double xMin, yMin, xMax, yMax, x, y;
2700   GfxSubpath *subpath;
2701   int i, j;
2702
2703   xMin = xMax = yMin = yMax = 0; // make gcc happy
2704   for (i = 0; i < path->getNumSubpaths(); ++i) {
2705     subpath = path->getSubpath(i);
2706     for (j = 0; j < subpath->getNumPoints(); ++j) {
2707       transform(subpath->getX(j), subpath->getY(j), &x, &y);
2708       if (i == 0 && j == 0) {
2709         xMin = xMax = x;
2710         yMin = yMax = y;
2711       } else {
2712         if (x < xMin) {
2713           xMin = x;
2714         } else if (x > xMax) {
2715           xMax = x;
2716         }
2717         if (y < yMin) {
2718           yMin = y;
2719         } else if (y > yMax) {
2720           yMax = y;
2721         }
2722       }
2723     }
2724   }
2725   if (xMin > clipXMin) {
2726     clipXMin = xMin;
2727   }
2728   if (yMin > clipYMin) {
2729     clipYMin = yMin;
2730   }
2731   if (xMax < clipXMax) {
2732     clipXMax = xMax;
2733   }
2734   if (yMax < clipYMax) {
2735     clipYMax = yMax;
2736   }
2737 }
2738
2739 void GfxState::textShift(double tx, double ty) {
2740   double dx, dy;
2741
2742   textTransformDelta(tx, ty, &dx, &dy);
2743   curX += dx;
2744   curY += dy;
2745 }
2746
2747 void GfxState::shift(double dx, double dy) {
2748   curX += dx;
2749   curY += dy;
2750 }
2751
2752 GfxState *GfxState::save() {
2753   GfxState *newState;
2754
2755   newState = copy();
2756   newState->saved = this;
2757   return newState;
2758 }
2759
2760 GfxState *GfxState::restore() {
2761   GfxState *oldState;
2762
2763   if (saved) {
2764     oldState = saved;
2765
2766     // these attributes aren't saved/restored by the q/Q operators
2767     oldState->path = path;
2768     oldState->curX = curX;
2769     oldState->curY = curY;
2770     oldState->lineX = lineX;
2771     oldState->lineY = lineY;
2772
2773     path = NULL;
2774     saved = NULL;
2775     delete this;
2776
2777   } else {
2778     oldState = this;
2779   }
2780
2781   return oldState;
2782 }