applied diff between xpdf-3.00-orig and xpdf-3.00-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>
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 #include "cmyk.h"
25
26 //------------------------------------------------------------------------
27
28 static inline GfxColorComp clip01(GfxColorComp x) {
29   return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x;
30 }
31
32 static inline double clip01(double x) {
33   return (x < 0) ? 0 : (x > 1) ? 1 : x;
34 }
35
36 //------------------------------------------------------------------------
37
38 static struct {
39   char *name;
40   GfxBlendMode mode;
41 } gfxBlendModeNames[] = {
42   { "Normal",     gfxBlendNormal },
43   { "Compatible", gfxBlendNormal },
44   { "Multiply",   gfxBlendMultiply },
45   { "Screen",     gfxBlendScreen },
46   { "Overlay",    gfxBlendOverlay },
47   { "Darken",     gfxBlendDarken },
48   { "Lighten",    gfxBlendLighten },
49   { "ColorDodge", gfxBlendColorDodge },
50   { "ColorBurn",  gfxBlendColorBurn },
51   { "HardLight",  gfxBlendHardLight },
52   { "SoftLight",  gfxBlendSoftLight },
53   { "Difference", gfxBlendDifference },
54   { "Exclusion",  gfxBlendExclusion },
55   { "Hue",        gfxBlendHue },
56   { "Saturation", gfxBlendSaturation },
57   { "Color",      gfxBlendColor },
58   { "Luminosity", gfxBlendLuminosity }
59 };
60
61 #define nGfxBlendModeNames \
62           ((int)((sizeof(gfxBlendModeNames) / sizeof(char *))))
63
64 //------------------------------------------------------------------------
65
66 // NB: This must match the GfxColorSpaceMode enum defined in
67 // GfxState.h
68 static char *gfxColorSpaceModeNames[] = {
69   "DeviceGray",
70   "CalGray",
71   "DeviceRGB",
72   "CalRGB",
73   "DeviceCMYK",
74   "Lab",
75   "ICCBased",
76   "Indexed",
77   "Separation",
78   "DeviceN",
79   "Pattern"
80 };
81
82 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
83
84 //------------------------------------------------------------------------
85 // GfxColorSpace
86 //------------------------------------------------------------------------
87
88 GfxColorSpace::GfxColorSpace() {
89 }
90
91 GfxColorSpace::~GfxColorSpace() {
92 }
93
94 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
95   GfxColorSpace *cs;
96   Object obj1;
97
98   cs = NULL;
99   if (csObj->isName()) {
100     if (csObj->isName("DeviceGray") || csObj->isName("G")) {
101       cs = new GfxDeviceGrayColorSpace();
102     } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
103       cs = new GfxDeviceRGBColorSpace();
104     } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
105       cs = new GfxDeviceCMYKColorSpace();
106     } else if (csObj->isName("Pattern")) {
107       cs = new GfxPatternColorSpace(NULL);
108     } else {
109       error(-1, "Bad color space '%s'", csObj->getName());
110     }
111   } else if (csObj->isArray()) {
112     csObj->arrayGet(0, &obj1);
113     if (obj1.isName("DeviceGray") || obj1.isName("G")) {
114       cs = new GfxDeviceGrayColorSpace();
115     } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
116       cs = new GfxDeviceRGBColorSpace();
117     } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
118       cs = new GfxDeviceCMYKColorSpace();
119     } else if (obj1.isName("CalGray")) {
120       cs = GfxCalGrayColorSpace::parse(csObj->getArray());
121     } else if (obj1.isName("CalRGB")) {
122       cs = GfxCalRGBColorSpace::parse(csObj->getArray());
123     } else if (obj1.isName("Lab")) {
124       cs = GfxLabColorSpace::parse(csObj->getArray());
125     } else if (obj1.isName("ICCBased")) {
126       cs = GfxICCBasedColorSpace::parse(csObj->getArray());
127     } else if (obj1.isName("Indexed") || obj1.isName("I")) {
128       cs = GfxIndexedColorSpace::parse(csObj->getArray());
129     } else if (obj1.isName("Separation")) {
130       cs = GfxSeparationColorSpace::parse(csObj->getArray());
131     } else if (obj1.isName("DeviceN")) {
132       cs = GfxDeviceNColorSpace::parse(csObj->getArray());
133     } else if (obj1.isName("Pattern")) {
134       cs = GfxPatternColorSpace::parse(csObj->getArray());
135     } else {
136       error(-1, "Bad color space");
137     }
138     obj1.free();
139   } else {
140     error(-1, "Bad color space - expected name or array");
141   }
142   return cs;
143 }
144
145 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
146                                      int maxImgPixel) {
147   int i;
148
149   for (i = 0; i < getNComps(); ++i) {
150     decodeLow[i] = 0;
151     decodeRange[i] = 1;
152   }
153 }
154
155 int GfxColorSpace::getNumColorSpaceModes() {
156   return nGfxColorSpaceModes;
157 }
158
159 char *GfxColorSpace::getColorSpaceModeName(int idx) {
160   return gfxColorSpaceModeNames[idx];
161 }
162
163 //------------------------------------------------------------------------
164 // GfxDeviceGrayColorSpace
165 //------------------------------------------------------------------------
166
167 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
168 }
169
170 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
171 }
172
173 GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
174   return new GfxDeviceGrayColorSpace();
175 }
176
177 void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
178   *gray = clip01(color->c[0]);
179 }
180
181 void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
182   rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
183 }
184
185 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
186   cmyk->c = cmyk->m = cmyk->y = 0;
187   cmyk->k = clip01(gfxColorComp1 - color->c[0]);
188 }
189
190 //------------------------------------------------------------------------
191 // GfxCalGrayColorSpace
192 //------------------------------------------------------------------------
193
194 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
195   whiteX = whiteY = whiteZ = 1;
196   blackX = blackY = blackZ = 0;
197   gamma = 1;
198 }
199
200 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
201 }
202
203 GfxColorSpace *GfxCalGrayColorSpace::copy() {
204   GfxCalGrayColorSpace *cs;
205
206   cs = new GfxCalGrayColorSpace();
207   cs->whiteX = whiteX;
208   cs->whiteY = whiteY;
209   cs->whiteZ = whiteZ;
210   cs->blackX = blackX;
211   cs->blackY = blackY;
212   cs->blackZ = blackZ;
213   cs->gamma = gamma;
214   return cs;
215 }
216
217 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
218   GfxCalGrayColorSpace *cs;
219   Object obj1, obj2, obj3;
220
221   arr->get(1, &obj1);
222   if (!obj1.isDict()) {
223     error(-1, "Bad CalGray color space");
224     obj1.free();
225     return NULL;
226   }
227   cs = new GfxCalGrayColorSpace();
228   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
229       obj2.arrayGetLength() == 3) {
230     obj2.arrayGet(0, &obj3);
231     cs->whiteX = obj3.getNum();
232     obj3.free();
233     obj2.arrayGet(1, &obj3);
234     cs->whiteY = obj3.getNum();
235     obj3.free();
236     obj2.arrayGet(2, &obj3);
237     cs->whiteZ = obj3.getNum();
238     obj3.free();
239   }
240   obj2.free();
241   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
242       obj2.arrayGetLength() == 3) {
243     obj2.arrayGet(0, &obj3);
244     cs->blackX = obj3.getNum();
245     obj3.free();
246     obj2.arrayGet(1, &obj3);
247     cs->blackY = obj3.getNum();
248     obj3.free();
249     obj2.arrayGet(2, &obj3);
250     cs->blackZ = obj3.getNum();
251     obj3.free();
252   }
253   obj2.free();
254   if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
255     cs->gamma = obj2.getNum();
256   }
257   obj2.free();
258   obj1.free();
259   return cs;
260 }
261
262 void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
263   *gray = clip01(color->c[0]);
264 }
265
266 void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
267   rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
268 }
269
270 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
271   cmyk->c = cmyk->m = cmyk->y = 0;
272   cmyk->k = clip01(gfxColorComp1 - color->c[0]);
273 }
274
275 //------------------------------------------------------------------------
276 // GfxDeviceRGBColorSpace
277 //------------------------------------------------------------------------
278
279 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
280 }
281
282 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
283 }
284
285 GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
286   return new GfxDeviceRGBColorSpace();
287 }
288
289 void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
290   *gray = clip01((GfxColorComp)(0.3  * color->c[0] +
291                                 0.59 * color->c[1] +
292                                 0.11 * color->c[2] + 0.5));
293 }
294
295 void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
296   rgb->r = clip01(color->c[0]);
297   rgb->g = clip01(color->c[1]);
298   rgb->b = clip01(color->c[2]);
299 }
300
301 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
302   GfxColorComp c, m, y, k;
303
304   c = clip01(gfxColorComp1 - color->c[0]);
305   m = clip01(gfxColorComp1 - color->c[1]);
306   y = clip01(gfxColorComp1 - color->c[2]);
307   k = c;
308   if (m < k) {
309     k = m;
310   }
311   if (y < k) {
312     k = y;
313   }
314   cmyk->c = c - k;
315   cmyk->m = m - k;
316   cmyk->y = y - k;
317   cmyk->k = k;
318 }
319
320 //------------------------------------------------------------------------
321 // GfxCalRGBColorSpace
322 //------------------------------------------------------------------------
323
324 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
325   whiteX = whiteY = whiteZ = 1;
326   blackX = blackY = blackZ = 0;
327   gammaR = gammaG = gammaB = 1;
328   mat[0] = 1; mat[1] = 0; mat[2] = 0;
329   mat[3] = 0; mat[4] = 1; mat[5] = 0;
330   mat[6] = 0; mat[7] = 0; mat[8] = 1;
331 }
332
333 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
334 }
335
336 GfxColorSpace *GfxCalRGBColorSpace::copy() {
337   GfxCalRGBColorSpace *cs;
338   int i;
339
340   cs = new GfxCalRGBColorSpace();
341   cs->whiteX = whiteX;
342   cs->whiteY = whiteY;
343   cs->whiteZ = whiteZ;
344   cs->blackX = blackX;
345   cs->blackY = blackY;
346   cs->blackZ = blackZ;
347   cs->gammaR = gammaR;
348   cs->gammaG = gammaG;
349   cs->gammaB = gammaB;
350   for (i = 0; i < 9; ++i) {
351     cs->mat[i] = mat[i];
352   }
353   return cs;
354 }
355
356 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
357   GfxCalRGBColorSpace *cs;
358   Object obj1, obj2, obj3;
359   int i;
360
361   arr->get(1, &obj1);
362   if (!obj1.isDict()) {
363     error(-1, "Bad CalRGB color space");
364     obj1.free();
365     return NULL;
366   }
367   cs = new GfxCalRGBColorSpace();
368   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
369       obj2.arrayGetLength() == 3) {
370     obj2.arrayGet(0, &obj3);
371     cs->whiteX = obj3.getNum();
372     obj3.free();
373     obj2.arrayGet(1, &obj3);
374     cs->whiteY = obj3.getNum();
375     obj3.free();
376     obj2.arrayGet(2, &obj3);
377     cs->whiteZ = obj3.getNum();
378     obj3.free();
379   }
380   obj2.free();
381   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
382       obj2.arrayGetLength() == 3) {
383     obj2.arrayGet(0, &obj3);
384     cs->blackX = obj3.getNum();
385     obj3.free();
386     obj2.arrayGet(1, &obj3);
387     cs->blackY = obj3.getNum();
388     obj3.free();
389     obj2.arrayGet(2, &obj3);
390     cs->blackZ = obj3.getNum();
391     obj3.free();
392   }
393   obj2.free();
394   if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
395       obj2.arrayGetLength() == 3) {
396     obj2.arrayGet(0, &obj3);
397     cs->gammaR = obj3.getNum();
398     obj3.free();
399     obj2.arrayGet(1, &obj3);
400     cs->gammaG = obj3.getNum();
401     obj3.free();
402     obj2.arrayGet(2, &obj3);
403     cs->gammaB = obj3.getNum();
404     obj3.free();
405   }
406   obj2.free();
407   if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
408       obj2.arrayGetLength() == 9) {
409     for (i = 0; i < 9; ++i) {
410       obj2.arrayGet(i, &obj3);
411       cs->mat[i] = obj3.getNum();
412       obj3.free();
413     }
414   }
415   obj2.free();
416   obj1.free();
417   return cs;
418 }
419
420 void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
421   *gray = clip01((GfxColorComp)(0.299 * color->c[0] +
422                                 0.587 * color->c[1] +
423                                 0.114 * color->c[2] + 0.5));
424 }
425
426 void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
427   rgb->r = clip01(color->c[0]);
428   rgb->g = clip01(color->c[1]);
429   rgb->b = clip01(color->c[2]);
430 }
431
432 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
433   GfxColorComp c, m, y, k;
434
435   c = clip01(gfxColorComp1 - color->c[0]);
436   m = clip01(gfxColorComp1 - color->c[1]);
437   y = clip01(gfxColorComp1 - color->c[2]);
438   k = c;
439   if (m < k) {
440     k = m;
441   }
442   if (y < k) {
443     k = y;
444   }
445   cmyk->c = c - k;
446   cmyk->m = m - k;
447   cmyk->y = y - k;
448   cmyk->k = k;
449 }
450
451 //------------------------------------------------------------------------
452 // GfxDeviceCMYKColorSpace
453 //------------------------------------------------------------------------
454
455 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
456 }
457
458 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
459 }
460
461 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
462   return new GfxDeviceCMYKColorSpace();
463 }
464
465 void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) {
466   *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3]
467                                 - 0.3  * color->c[0]
468                                 - 0.59 * color->c[1]
469                                 - 0.11 * color->c[2] + 0.5));
470 }
471
472 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
473     unsigned char r,g,b;
474     float c = color->c[0];
475     float m = color->c[1];
476     float y = color->c[2];
477     float k = color->c[3];
478     convert_cmyk2rgb(c,m,y,k, &r,&g,&b);
479     rgb->r = r/255.0;
480     rgb->g = g/255.0;
481     rgb->b = b/255.0;
482 }
483
484 /*void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
485   double c, m, y, k, c1, m1, y1, k1, r, g, b, x;
486
487   c = colToDbl(color->c[0]);
488   m = colToDbl(color->c[1]);
489   y = colToDbl(color->c[2]);
490   k = colToDbl(color->c[3]);
491   c1 = 1 - c;
492   m1 = 1 - m;
493   y1 = 1 - y;
494   k1 = 1 - k;
495   // this is a matrix multiplication, unrolled for performance
496   //                        C M Y K
497   x = c1 * m1 * y1 * k1; // 0 0 0 0
498   r = g = b = x;
499   x = c1 * m1 * y1 * k;  // 0 0 0 1
500   r += 0.1373 * x;
501   g += 0.1216 * x;
502   b += 0.1255 * x;
503   x = c1 * m1 * y  * k1; // 0 0 1 0
504   r += x;
505   g += 0.9490 * x;
506   x = c1 * m1 * y  * k;  // 0 0 1 1
507   r += 0.1098 * x;
508   g += 0.1020 * x;
509   x = c1 * m  * y1 * k1; // 0 1 0 0
510   r += 0.9255 * x;
511   b += 0.5490 * x;
512   x = c1 * m  * y1 * k;  // 0 1 0 1
513   r += 0.1412 * x;
514   x = c1 * m  * y  * k1; // 0 1 1 0
515   r += 0.9294 * x;
516   g += 0.1098 * x;
517   b += 0.1412 * x;
518   x = c1 * m  * y  * k;  // 0 1 1 1
519   r += 0.1333 * x;
520   x = c  * m1 * y1 * k1; // 1 0 0 0
521   g += 0.6784 * x;
522   b += 0.9373 * x;
523   x = c  * m1 * y1 * k;  // 1 0 0 1
524   g += 0.0588 * x;
525   b += 0.1412 * x;
526   x = c  * m1 * y  * k1; // 1 0 1 0
527   g += 0.6510 * x;
528   b += 0.3137 * x;
529   x = c  * m1 * y  * k;  // 1 0 1 1
530   g += 0.0745 * x;
531   x = c  * m  * y1 * k1; // 1 1 0 0
532   r += 0.1804 * x;
533   g += 0.1922 * x;
534   b += 0.5725 * x;
535   x = c  * m  * y1 * k;  // 1 1 0 1
536   b += 0.0078 * x;
537   x = c  * m  * y  * k1; // 1 1 1 0
538   r += 0.2118 * x;
539   g += 0.2119 * x;
540   b += 0.2235 * x;
541   rgb->r = clip01(dblToCol(r));
542   rgb->g = clip01(dblToCol(g));
543   rgb->b = clip01(dblToCol(b));
544 }*/
545
546 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
547   cmyk->c = clip01(color->c[0]);
548   cmyk->m = clip01(color->c[1]);
549   cmyk->y = clip01(color->c[2]);
550   cmyk->k = clip01(color->c[3]);
551 }
552
553 //------------------------------------------------------------------------
554 // GfxLabColorSpace
555 //------------------------------------------------------------------------
556
557 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
558 // Language Reference, Third Edition.
559 static double xyzrgb[3][3] = {
560   {  3.240449, -1.537136, -0.498531 },
561   { -0.969265,  1.876011,  0.041556 },
562   {  0.055643, -0.204026,  1.057229 }
563 };
564
565 GfxLabColorSpace::GfxLabColorSpace() {
566   whiteX = whiteY = whiteZ = 1;
567   blackX = blackY = blackZ = 0;
568   aMin = bMin = -100;
569   aMax = bMax = 100;
570 }
571
572 GfxLabColorSpace::~GfxLabColorSpace() {
573 }
574
575 GfxColorSpace *GfxLabColorSpace::copy() {
576   GfxLabColorSpace *cs;
577
578   cs = new GfxLabColorSpace();
579   cs->whiteX = whiteX;
580   cs->whiteY = whiteY;
581   cs->whiteZ = whiteZ;
582   cs->blackX = blackX;
583   cs->blackY = blackY;
584   cs->blackZ = blackZ;
585   cs->aMin = aMin;
586   cs->aMax = aMax;
587   cs->bMin = bMin;
588   cs->bMax = bMax;
589   cs->kr = kr;
590   cs->kg = kg;
591   cs->kb = kb;
592   return cs;
593 }
594
595 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
596   GfxLabColorSpace *cs;
597   Object obj1, obj2, obj3;
598
599   arr->get(1, &obj1);
600   if (!obj1.isDict()) {
601     error(-1, "Bad Lab color space");
602     obj1.free();
603     return NULL;
604   }
605   cs = new GfxLabColorSpace();
606   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
607       obj2.arrayGetLength() == 3) {
608     obj2.arrayGet(0, &obj3);
609     cs->whiteX = obj3.getNum();
610     obj3.free();
611     obj2.arrayGet(1, &obj3);
612     cs->whiteY = obj3.getNum();
613     obj3.free();
614     obj2.arrayGet(2, &obj3);
615     cs->whiteZ = obj3.getNum();
616     obj3.free();
617   }
618   obj2.free();
619   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
620       obj2.arrayGetLength() == 3) {
621     obj2.arrayGet(0, &obj3);
622     cs->blackX = obj3.getNum();
623     obj3.free();
624     obj2.arrayGet(1, &obj3);
625     cs->blackY = obj3.getNum();
626     obj3.free();
627     obj2.arrayGet(2, &obj3);
628     cs->blackZ = obj3.getNum();
629     obj3.free();
630   }
631   obj2.free();
632   if (obj1.dictLookup("Range", &obj2)->isArray() &&
633       obj2.arrayGetLength() == 4) {
634     obj2.arrayGet(0, &obj3);
635     cs->aMin = obj3.getNum();
636     obj3.free();
637     obj2.arrayGet(1, &obj3);
638     cs->aMax = obj3.getNum();
639     obj3.free();
640     obj2.arrayGet(2, &obj3);
641     cs->bMin = obj3.getNum();
642     obj3.free();
643     obj2.arrayGet(3, &obj3);
644     cs->bMax = obj3.getNum();
645     obj3.free();
646   }
647   obj2.free();
648   obj1.free();
649
650   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
651                 xyzrgb[0][1] * cs->whiteY +
652                 xyzrgb[0][2] * cs->whiteZ);
653   cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
654                 xyzrgb[1][1] * cs->whiteY +
655                 xyzrgb[1][2] * cs->whiteZ);
656   cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
657                 xyzrgb[2][1] * cs->whiteY +
658                 xyzrgb[2][2] * cs->whiteZ);
659
660   return cs;
661 }
662
663 void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) {
664   GfxRGB rgb;
665
666   getRGB(color, &rgb);
667   *gray = clip01((GfxColorComp)(0.299 * rgb.r +
668                                 0.587 * rgb.g +
669                                 0.114 * rgb.b + 0.5));
670 }
671
672 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
673   double X, Y, Z;
674   double t1, t2;
675   double r, g, b;
676
677   // convert L*a*b* to CIE 1931 XYZ color space
678   t1 = (colToDbl(color->c[0]) + 16) / 116;
679   t2 = t1 + colToDbl(color->c[1]) / 500;
680   if (t2 >= (6.0 / 29.0)) {
681     X = t2 * t2 * t2;
682   } else {
683     X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
684   }
685   X *= whiteX;
686   if (t1 >= (6.0 / 29.0)) {
687     Y = t1 * t1 * t1;
688   } else {
689     Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
690   }
691   Y *= whiteY;
692   t2 = t1 - colToDbl(color->c[2]) / 200;
693   if (t2 >= (6.0 / 29.0)) {
694     Z = t2 * t2 * t2;
695   } else {
696     Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
697   }
698   Z *= whiteZ;
699
700   // convert XYZ to RGB, including gamut mapping and gamma correction
701   r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
702   g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
703   b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
704   rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
705   rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
706   rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
707 }
708
709 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
710   GfxRGB rgb;
711   GfxColorComp c, m, y, k;
712
713   getRGB(color, &rgb);
714   c = clip01(gfxColorComp1 - rgb.r);
715   m = clip01(gfxColorComp1 - rgb.g);
716   y = clip01(gfxColorComp1 - rgb.b);
717   k = c;
718   if (m < k) {
719     k = m;
720   }
721   if (y < k) {
722     k = y;
723   }
724   cmyk->c = c - k;
725   cmyk->m = m - k;
726   cmyk->y = y - k;
727   cmyk->k = k;
728 }
729
730 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
731                                         int maxImgPixel) {
732   decodeLow[0] = 0;
733   decodeRange[0] = 100;
734   decodeLow[1] = aMin;
735   decodeRange[1] = aMax - aMin;
736   decodeLow[2] = bMin;
737   decodeRange[2] = bMax - bMin;
738 }
739
740 //------------------------------------------------------------------------
741 // GfxICCBasedColorSpace
742 //------------------------------------------------------------------------
743
744 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
745                                              Ref *iccProfileStreamA) {
746   nComps = nCompsA;
747   alt = altA;
748   iccProfileStream = *iccProfileStreamA;
749   rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
750   rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
751 }
752
753 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
754   delete alt;
755 }
756
757 GfxColorSpace *GfxICCBasedColorSpace::copy() {
758   GfxICCBasedColorSpace *cs;
759   int i;
760
761   cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
762   for (i = 0; i < 4; ++i) {
763     cs->rangeMin[i] = rangeMin[i];
764     cs->rangeMax[i] = rangeMax[i];
765   }
766   return cs;
767 }
768
769 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
770   GfxICCBasedColorSpace *cs;
771   Ref iccProfileStreamA;
772   int nCompsA;
773   GfxColorSpace *altA;
774   Dict *dict;
775   Object obj1, obj2, obj3;
776   int i;
777
778   arr->getNF(1, &obj1);
779   if (obj1.isRef()) {
780     iccProfileStreamA = obj1.getRef();
781   } else {
782     iccProfileStreamA.num = 0;
783     iccProfileStreamA.gen = 0;
784   }
785   obj1.free();
786   arr->get(1, &obj1);
787   if (!obj1.isStream()) {
788     error(-1, "Bad ICCBased color space (stream)");
789     obj1.free();
790     return NULL;
791   }
792   dict = obj1.streamGetDict();
793   if (!dict->lookup("N", &obj2)->isInt()) {
794     error(-1, "Bad ICCBased color space (N)");
795     obj2.free();
796     obj1.free();
797     return NULL;
798   }
799   nCompsA = obj2.getInt();
800   obj2.free();
801   if (nCompsA > gfxColorMaxComps) {
802     error(-1, "ICCBased color space with too many (%d > %d) components",
803           nCompsA, gfxColorMaxComps);
804     nCompsA = gfxColorMaxComps;
805   }
806   if (dict->lookup("Alternate", &obj2)->isNull() ||
807       !(altA = GfxColorSpace::parse(&obj2))) {
808     switch (nCompsA) {
809     case 1:
810       altA = new GfxDeviceGrayColorSpace();
811       break;
812     case 3:
813       altA = new GfxDeviceRGBColorSpace();
814       break;
815     case 4:
816       altA = new GfxDeviceCMYKColorSpace();
817       break;
818     default:
819       error(-1, "Bad ICCBased color space - invalid N");
820       obj2.free();
821       obj1.free();
822       return NULL;
823     }
824   }
825   obj2.free();
826   cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
827   if (dict->lookup("Range", &obj2)->isArray() &&
828       obj2.arrayGetLength() == 2 * nCompsA) {
829     for (i = 0; i < nCompsA; ++i) {
830       obj2.arrayGet(2*i, &obj3);
831       cs->rangeMin[i] = obj3.getNum();
832       obj3.free();
833       obj2.arrayGet(2*i+1, &obj3);
834       cs->rangeMax[i] = obj3.getNum();
835       obj3.free();
836     }
837   }
838   obj2.free();
839   obj1.free();
840   return cs;
841 }
842
843 void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
844   alt->getGray(color, gray);
845 }
846
847 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
848   alt->getRGB(color, rgb);
849 }
850
851 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
852   alt->getCMYK(color, cmyk);
853 }
854
855 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
856                                              double *decodeRange,
857                                              int maxImgPixel) {
858   alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
859
860 #if 0
861   // this is nominally correct, but some PDF files don't set the
862   // correct ranges in the ICCBased dict
863   int i;
864
865   for (i = 0; i < nComps; ++i) {
866     decodeLow[i] = rangeMin[i];
867     decodeRange[i] = rangeMax[i] - rangeMin[i];
868   }
869 #endif
870 }
871
872 //------------------------------------------------------------------------
873 // GfxIndexedColorSpace
874 //------------------------------------------------------------------------
875
876 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
877                                            int indexHighA) {
878   base = baseA;
879   indexHigh = indexHighA;
880   lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(),
881                               sizeof(Guchar));
882 }
883
884 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
885   delete base;
886   gfree(lookup);
887 }
888
889 GfxColorSpace *GfxIndexedColorSpace::copy() {
890   GfxIndexedColorSpace *cs;
891
892   cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
893   memcpy(cs->lookup, lookup,
894          (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
895   return cs;
896 }
897
898 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
899   GfxIndexedColorSpace *cs;
900   GfxColorSpace *baseA;
901   int indexHighA;
902   Object obj1;
903   int x;
904   char *s;
905   int n, i, j;
906
907   if (arr->getLength() != 4) {
908     error(-1, "Bad Indexed color space");
909     goto err1;
910   }
911   arr->get(1, &obj1);
912   if (!(baseA = GfxColorSpace::parse(&obj1))) {
913     error(-1, "Bad Indexed color space (base color space)");
914     goto err2;
915   }
916   obj1.free();
917   if (!arr->get(2, &obj1)->isInt()) {
918     error(-1, "Bad Indexed color space (hival)");
919     delete baseA;
920     goto err2;
921   }
922   indexHighA = obj1.getInt();
923   if (indexHighA < 0 || indexHighA > 255) {
924     // the PDF spec requires indexHigh to be in [0,255] -- allowing
925     // values larger than 255 creates a security hole: if nComps *
926     // indexHigh is greater than 2^31, the loop below may overwrite
927     // past the end of the array
928     error(-1, "Bad Indexed color space (invalid indexHigh value)");
929     delete baseA;
930     goto err2;
931   }
932   obj1.free();
933   cs = new GfxIndexedColorSpace(baseA, indexHighA);
934   arr->get(3, &obj1);
935   n = baseA->getNComps();
936   if (obj1.isStream()) {
937     obj1.streamReset();
938     for (i = 0; i <= indexHighA; ++i) {
939       for (j = 0; j < n; ++j) {
940         if ((x = obj1.streamGetChar()) == EOF) {
941           error(-1, "Bad Indexed color space (lookup table stream too short)");
942           goto err3;
943         }
944         cs->lookup[i*n + j] = (Guchar)x;
945       }
946     }
947     obj1.streamClose();
948   } else if (obj1.isString()) {
949     if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
950       error(-1, "Bad Indexed color space (lookup table string too short)");
951       goto err3;
952     }
953     s = obj1.getString()->getCString();
954     for (i = 0; i <= indexHighA; ++i) {
955       for (j = 0; j < n; ++j) {
956         cs->lookup[i*n + j] = (Guchar)*s++;
957       }
958     }
959   } else {
960     error(-1, "Bad Indexed color space (lookup table)");
961     goto err3;
962   }
963   obj1.free();
964   return cs;
965
966  err3:
967   delete cs;
968  err2:
969   obj1.free();
970  err1:
971   return NULL;
972 }
973
974 GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
975                                                GfxColor *baseColor) {
976   Guchar *p;
977   double low[gfxColorMaxComps], range[gfxColorMaxComps];
978   int n, i;
979
980   n = base->getNComps();
981   base->getDefaultRanges(low, range, indexHigh);
982   p = &lookup[(int)(colToDbl(color->c[0]) + 0.5) * n];
983   for (i = 0; i < n; ++i) {
984     baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]);
985   }
986   return baseColor;
987 }
988
989 void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
990   GfxColor color2;
991
992   base->getGray(mapColorToBase(color, &color2), gray);
993 }
994
995 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
996   GfxColor color2;
997
998   base->getRGB(mapColorToBase(color, &color2), rgb);
999 }
1000
1001 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1002   GfxColor color2;
1003
1004   base->getCMYK(mapColorToBase(color, &color2), cmyk);
1005 }
1006
1007 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
1008                                             double *decodeRange,
1009                                             int maxImgPixel) {
1010   decodeLow[0] = 0;
1011   decodeRange[0] = maxImgPixel;
1012 }
1013
1014 //------------------------------------------------------------------------
1015 // GfxSeparationColorSpace
1016 //------------------------------------------------------------------------
1017
1018 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
1019                                                  GfxColorSpace *altA,
1020                                                  Function *funcA) {
1021   name = nameA;
1022   alt = altA;
1023   func = funcA;
1024 }
1025
1026 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
1027   delete name;
1028   delete alt;
1029   delete func;
1030 }
1031
1032 GfxColorSpace *GfxSeparationColorSpace::copy() {
1033   return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
1034 }
1035
1036 //~ handle the 'All' and 'None' colorants
1037 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
1038   GfxSeparationColorSpace *cs;
1039   GString *nameA;
1040   GfxColorSpace *altA;
1041   Function *funcA;
1042   Object obj1;
1043
1044   if (arr->getLength() != 4) {
1045     error(-1, "Bad Separation color space");
1046     goto err1;
1047   }
1048   if (!arr->get(1, &obj1)->isName()) {
1049     error(-1, "Bad Separation color space (name)");
1050     goto err2;
1051   }
1052   nameA = new GString(obj1.getName());
1053   obj1.free();
1054   arr->get(2, &obj1);
1055   if (!(altA = GfxColorSpace::parse(&obj1))) {
1056     error(-1, "Bad Separation color space (alternate color space)");
1057     goto err3;
1058   }
1059   obj1.free();
1060   arr->get(3, &obj1);
1061   if (!(funcA = Function::parse(&obj1))) {
1062     goto err4;
1063   }
1064   obj1.free();
1065   cs = new GfxSeparationColorSpace(nameA, altA, funcA);
1066   return cs;
1067
1068  err4:
1069   delete altA;
1070  err3:
1071   delete nameA;
1072  err2:
1073   obj1.free();
1074  err1:
1075   return NULL;
1076 }
1077
1078 void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) {
1079   double x;
1080   double c[gfxColorMaxComps];
1081   GfxColor color2;
1082   int i;
1083
1084   x = colToDbl(color->c[0]);
1085   func->transform(&x, c);
1086   for (i = 0; i < alt->getNComps(); ++i) {
1087     color2.c[i] = dblToCol(c[i]);
1088   }
1089   alt->getGray(&color2, gray);
1090 }
1091
1092 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1093   double x;
1094   double c[gfxColorMaxComps];
1095   GfxColor color2;
1096   int i;
1097
1098   x = colToDbl(color->c[0]);
1099   func->transform(&x, c);
1100   for (i = 0; i < alt->getNComps(); ++i) {
1101     color2.c[i] = dblToCol(c[i]);
1102   }
1103   alt->getRGB(&color2, rgb);
1104 }
1105
1106 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1107   double x;
1108   double c[gfxColorMaxComps];
1109   GfxColor color2;
1110   int i;
1111
1112   x = colToDbl(color->c[0]);
1113   func->transform(&x, c);
1114   for (i = 0; i < alt->getNComps(); ++i) {
1115     color2.c[i] = dblToCol(c[i]);
1116   }
1117   alt->getCMYK(&color2, cmyk);
1118 }
1119
1120 //------------------------------------------------------------------------
1121 // GfxDeviceNColorSpace
1122 //------------------------------------------------------------------------
1123
1124 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1125                                            GfxColorSpace *altA,
1126                                            Function *funcA) {
1127   nComps = nCompsA;
1128   alt = altA;
1129   func = funcA;
1130 }
1131
1132 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1133   int i;
1134
1135   for (i = 0; i < nComps; ++i) {
1136     delete names[i];
1137   }
1138   delete alt;
1139   delete func;
1140 }
1141
1142 GfxColorSpace *GfxDeviceNColorSpace::copy() {
1143   GfxDeviceNColorSpace *cs;
1144   int i;
1145
1146   cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
1147   for (i = 0; i < nComps; ++i) {
1148     cs->names[i] = names[i]->copy();
1149   }
1150   return cs;
1151 }
1152
1153 //~ handle the 'None' colorant
1154 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1155   GfxDeviceNColorSpace *cs;
1156   int nCompsA;
1157   GString *namesA[gfxColorMaxComps];
1158   GfxColorSpace *altA;
1159   Function *funcA;
1160   Object obj1, obj2;
1161   int i;
1162
1163   if (arr->getLength() != 4 && arr->getLength() != 5) {
1164     error(-1, "Bad DeviceN color space");
1165     goto err1;
1166   }
1167   if (!arr->get(1, &obj1)->isArray()) {
1168     error(-1, "Bad DeviceN color space (names)");
1169     goto err2;
1170   }
1171   nCompsA = obj1.arrayGetLength();
1172   if (nCompsA > gfxColorMaxComps) {
1173     error(-1, "DeviceN color space with too many (%d > %d) components",
1174           nCompsA, gfxColorMaxComps);
1175     nCompsA = gfxColorMaxComps;
1176   }
1177   for (i = 0; i < nCompsA; ++i) {
1178     if (!obj1.arrayGet(i, &obj2)->isName()) {
1179       error(-1, "Bad DeviceN color space (names)");
1180       obj2.free();
1181       goto err2;
1182     }
1183     namesA[i] = new GString(obj2.getName());
1184     obj2.free();
1185   }
1186   obj1.free();
1187   arr->get(2, &obj1);
1188   if (!(altA = GfxColorSpace::parse(&obj1))) {
1189     error(-1, "Bad DeviceN color space (alternate color space)");
1190     goto err3;
1191   }
1192   obj1.free();
1193   arr->get(3, &obj1);
1194   if (!(funcA = Function::parse(&obj1))) {
1195     goto err4;
1196   }
1197   obj1.free();
1198   cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1199   for (i = 0; i < nCompsA; ++i) {
1200     cs->names[i] = namesA[i];
1201   }
1202   return cs;
1203
1204  err4:
1205   delete altA;
1206  err3:
1207   for (i = 0; i < nCompsA; ++i) {
1208     delete namesA[i];
1209   }
1210  err2:
1211   obj1.free();
1212  err1:
1213   return NULL;
1214 }
1215
1216 void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) {
1217   double x[gfxColorMaxComps], c[gfxColorMaxComps];
1218   GfxColor color2;
1219   int i;
1220
1221   for (i = 0; i < nComps; ++i) {
1222     x[i] = colToDbl(color->c[i]);
1223   }
1224   func->transform(x, c);
1225   for (i = 0; i < alt->getNComps(); ++i) {
1226     color2.c[i] = dblToCol(c[i]);
1227   }
1228   alt->getGray(&color2, gray);
1229 }
1230
1231 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1232   double x[gfxColorMaxComps], c[gfxColorMaxComps];
1233   GfxColor color2;
1234   int i;
1235
1236   for (i = 0; i < nComps; ++i) {
1237     x[i] = colToDbl(color->c[i]);
1238   }
1239   func->transform(x, c);
1240   for (i = 0; i < alt->getNComps(); ++i) {
1241     color2.c[i] = dblToCol(c[i]);
1242   }
1243   alt->getRGB(&color2, rgb);
1244 }
1245
1246 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1247   double x[gfxColorMaxComps], c[gfxColorMaxComps];
1248   GfxColor color2;
1249   int i;
1250
1251   for (i = 0; i < nComps; ++i) {
1252     x[i] = colToDbl(color->c[i]);
1253   }
1254   func->transform(x, c);
1255   for (i = 0; i < alt->getNComps(); ++i) {
1256     color2.c[i] = dblToCol(c[i]);
1257   }
1258   alt->getCMYK(&color2, cmyk);
1259 }
1260
1261 //------------------------------------------------------------------------
1262 // GfxPatternColorSpace
1263 //------------------------------------------------------------------------
1264
1265 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1266   under = underA;
1267 }
1268
1269 GfxPatternColorSpace::~GfxPatternColorSpace() {
1270   if (under) {
1271     delete under;
1272   }
1273 }
1274
1275 GfxColorSpace *GfxPatternColorSpace::copy() {
1276   return new GfxPatternColorSpace(under ? under->copy() :
1277                                           (GfxColorSpace *)NULL);
1278 }
1279
1280 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1281   GfxPatternColorSpace *cs;
1282   GfxColorSpace *underA;
1283   Object obj1;
1284
1285   if (arr->getLength() != 1 && arr->getLength() != 2) {
1286     error(-1, "Bad Pattern color space");
1287     return NULL;
1288   }
1289   underA = NULL;
1290   if (arr->getLength() == 2) {
1291     arr->get(1, &obj1);
1292     if (!(underA = GfxColorSpace::parse(&obj1))) {
1293       error(-1, "Bad Pattern color space (underlying color space)");
1294       obj1.free();
1295       return NULL;
1296     }
1297     obj1.free();
1298   }
1299   cs = new GfxPatternColorSpace(underA);
1300   return cs;
1301 }
1302
1303 void GfxPatternColorSpace::getGray(GfxColor *color, GfxGray *gray) {
1304   *gray = 0;
1305 }
1306
1307 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1308   rgb->r = rgb->g = rgb->b = 0;
1309 }
1310
1311 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1312   cmyk->c = cmyk->m = cmyk->y = 0;
1313   cmyk->k = 1;
1314 }
1315
1316 //------------------------------------------------------------------------
1317 // Pattern
1318 //------------------------------------------------------------------------
1319
1320 GfxPattern::GfxPattern(int typeA) {
1321   type = typeA;
1322 }
1323
1324 GfxPattern::~GfxPattern() {
1325 }
1326
1327 GfxPattern *GfxPattern::parse(Object *obj) {
1328   GfxPattern *pattern;
1329   Object obj1;
1330
1331   if (obj->isDict()) {
1332     obj->dictLookup("PatternType", &obj1);
1333   } else if (obj->isStream()) {
1334     obj->streamGetDict()->lookup("PatternType", &obj1);
1335   } else {
1336     return NULL;
1337   }
1338   pattern = NULL;
1339   if (obj1.isInt() && obj1.getInt() == 1) {
1340     pattern = GfxTilingPattern::parse(obj);
1341   } else if (obj1.isInt() && obj1.getInt() == 2) {
1342     pattern = GfxShadingPattern::parse(obj);
1343   }
1344   obj1.free();
1345   return pattern;
1346 }
1347
1348 //------------------------------------------------------------------------
1349 // GfxTilingPattern
1350 //------------------------------------------------------------------------
1351
1352 GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
1353   GfxTilingPattern *pat;
1354   Dict *dict;
1355   int paintTypeA, tilingTypeA;
1356   double bboxA[4], matrixA[6];
1357   double xStepA, yStepA;
1358   Object resDictA;
1359   Object obj1, obj2;
1360   int i;
1361
1362   if (!patObj->isStream()) {
1363     return NULL;
1364   }
1365   dict = patObj->streamGetDict();
1366
1367   if (dict->lookup("PaintType", &obj1)->isInt()) {
1368     paintTypeA = obj1.getInt();
1369   } else {
1370     paintTypeA = 1;
1371     error(-1, "Invalid or missing PaintType in pattern");
1372   }
1373   obj1.free();
1374   if (dict->lookup("TilingType", &obj1)->isInt()) {
1375     tilingTypeA = obj1.getInt();
1376   } else {
1377     tilingTypeA = 1;
1378     error(-1, "Invalid or missing TilingType in pattern");
1379   }
1380   obj1.free();
1381   bboxA[0] = bboxA[1] = 0;
1382   bboxA[2] = bboxA[3] = 1;
1383   if (dict->lookup("BBox", &obj1)->isArray() &&
1384       obj1.arrayGetLength() == 4) {
1385     for (i = 0; i < 4; ++i) {
1386       if (obj1.arrayGet(i, &obj2)->isNum()) {
1387         bboxA[i] = obj2.getNum();
1388       }
1389       obj2.free();
1390     }
1391   } else {
1392     error(-1, "Invalid or missing BBox in pattern");
1393   }
1394   obj1.free();
1395   if (dict->lookup("XStep", &obj1)->isNum()) {
1396     xStepA = obj1.getNum();
1397   } else {
1398     xStepA = 1;
1399     error(-1, "Invalid or missing XStep in pattern");
1400   }
1401   obj1.free();
1402   if (dict->lookup("YStep", &obj1)->isNum()) {
1403     yStepA = obj1.getNum();
1404   } else {
1405     yStepA = 1;
1406     error(-1, "Invalid or missing YStep in pattern");
1407   }
1408   obj1.free();
1409   if (!dict->lookup("Resources", &resDictA)->isDict()) {
1410     resDictA.free();
1411     resDictA.initNull();
1412     error(-1, "Invalid or missing Resources in pattern");
1413   }
1414   matrixA[0] = 1; matrixA[1] = 0;
1415   matrixA[2] = 0; matrixA[3] = 1;
1416   matrixA[4] = 0; matrixA[5] = 0;
1417   if (dict->lookup("Matrix", &obj1)->isArray() &&
1418       obj1.arrayGetLength() == 6) {
1419     for (i = 0; i < 6; ++i) {
1420       if (obj1.arrayGet(i, &obj2)->isNum()) {
1421         matrixA[i] = obj2.getNum();
1422       }
1423       obj2.free();
1424     }
1425   }
1426   obj1.free();
1427
1428   pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
1429                              &resDictA, matrixA, patObj);
1430   resDictA.free();
1431   return pat;
1432 }
1433
1434 GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
1435                                    double *bboxA, double xStepA, double yStepA,
1436                                    Object *resDictA, double *matrixA,
1437                                    Object *contentStreamA):
1438   GfxPattern(1)
1439 {
1440   int i;
1441
1442   paintType = paintTypeA;
1443   tilingType = tilingTypeA;
1444   for (i = 0; i < 4; ++i) {
1445     bbox[i] = bboxA[i];
1446   }
1447   xStep = xStepA;
1448   yStep = yStepA;
1449   resDictA->copy(&resDict);
1450   for (i = 0; i < 6; ++i) {
1451     matrix[i] = matrixA[i];
1452   }
1453   contentStreamA->copy(&contentStream);
1454 }
1455
1456 GfxTilingPattern::~GfxTilingPattern() {
1457   resDict.free();
1458   contentStream.free();
1459 }
1460
1461 GfxPattern *GfxTilingPattern::copy() {
1462   return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
1463                               &resDict, matrix, &contentStream);
1464 }
1465
1466 //------------------------------------------------------------------------
1467 // GfxShadingPattern
1468 //------------------------------------------------------------------------
1469
1470 GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
1471   Dict *dict;
1472   GfxShading *shadingA;
1473   double matrixA[6];
1474   Object obj1, obj2;
1475   int i;
1476
1477   if (!patObj->isDict()) {
1478     return NULL;
1479   }
1480   dict = patObj->getDict();
1481
1482   dict->lookup("Shading", &obj1);
1483   shadingA = GfxShading::parse(&obj1);
1484   obj1.free();
1485   if (!shadingA) {
1486     return NULL;
1487   }
1488
1489   matrixA[0] = 1; matrixA[1] = 0;
1490   matrixA[2] = 0; matrixA[3] = 1;
1491   matrixA[4] = 0; matrixA[5] = 0;
1492   if (dict->lookup("Matrix", &obj1)->isArray() &&
1493       obj1.arrayGetLength() == 6) {
1494     for (i = 0; i < 6; ++i) {
1495       if (obj1.arrayGet(i, &obj2)->isNum()) {
1496         matrixA[i] = obj2.getNum();
1497       }
1498       obj2.free();
1499     }
1500   }
1501   obj1.free();
1502
1503   return new GfxShadingPattern(shadingA, matrixA);
1504 }
1505
1506 GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
1507   GfxPattern(2)
1508 {
1509   int i;
1510
1511   shading = shadingA;
1512   for (i = 0; i < 6; ++i) {
1513     matrix[i] = matrixA[i];
1514   }
1515 }
1516
1517 GfxShadingPattern::~GfxShadingPattern() {
1518   delete shading;
1519 }
1520
1521 GfxPattern *GfxShadingPattern::copy() {
1522   return new GfxShadingPattern(shading->copy(), matrix);
1523 }
1524
1525 //------------------------------------------------------------------------
1526 // GfxShading
1527 //------------------------------------------------------------------------
1528
1529 GfxShading::GfxShading(int typeA) {
1530   type = typeA;
1531   colorSpace = NULL;
1532 }
1533
1534 GfxShading::GfxShading(GfxShading *shading) {
1535   int i;
1536
1537   type = shading->type;
1538   colorSpace = shading->colorSpace->copy();
1539   for (i = 0; i < gfxColorMaxComps; ++i) {
1540     background.c[i] = shading->background.c[i];
1541   }
1542   hasBackground = shading->hasBackground;
1543   xMin = shading->xMin;
1544   yMin = shading->yMin;
1545   xMax = shading->xMax;
1546   yMax = shading->yMax;
1547   hasBBox = shading->hasBBox;
1548 }
1549
1550 GfxShading::~GfxShading() {
1551   if (colorSpace) {
1552     delete colorSpace;
1553   }
1554 }
1555
1556 GfxShading *GfxShading::parse(Object *obj) {
1557   GfxShading *shading;
1558   Dict *dict;
1559   int typeA;
1560   Object obj1;
1561
1562   if (obj->isDict()) {
1563     dict = obj->getDict();
1564   } else if (obj->isStream()) {
1565     dict = obj->streamGetDict();
1566   } else {
1567     return NULL;
1568   }
1569
1570   if (!dict->lookup("ShadingType", &obj1)->isInt()) {
1571     error(-1, "Invalid ShadingType in shading dictionary");
1572     obj1.free();
1573     return NULL;
1574   }
1575   typeA = obj1.getInt();
1576   obj1.free();
1577
1578   switch (typeA) {
1579   case 1:
1580     shading = GfxFunctionShading::parse(dict);
1581     break;
1582   case 2:
1583     shading = GfxAxialShading::parse(dict);
1584     break;
1585   case 3:
1586     shading = GfxRadialShading::parse(dict);
1587     break;
1588   case 4:
1589     if (obj->isStream()) {
1590       shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream());
1591     } else {
1592       error(-1, "Invalid Type 4 shading object");
1593       goto err1;
1594     }
1595     break;
1596   case 5:
1597     if (obj->isStream()) {
1598       shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream());
1599     } else {
1600       error(-1, "Invalid Type 5 shading object");
1601       goto err1;
1602     }
1603     break;
1604   case 6:
1605     if (obj->isStream()) {
1606       shading = GfxPatchMeshShading::parse(6, dict, obj->getStream());
1607     } else {
1608       error(-1, "Invalid Type 6 shading object");
1609       goto err1;
1610     }
1611     break;
1612   case 7:
1613     if (obj->isStream()) {
1614       shading = GfxPatchMeshShading::parse(7, dict, obj->getStream());
1615     } else {
1616       error(-1, "Invalid Type 7 shading object");
1617       goto err1;
1618     }
1619     break;
1620   default:
1621     error(-1, "Unimplemented shading type %d", typeA);
1622     goto err1;
1623   }
1624
1625   return shading;
1626
1627  err1:
1628   return NULL;
1629 }
1630
1631 GBool GfxShading::init(Dict *dict) {
1632   Object obj1, obj2;
1633   int i;
1634
1635   dict->lookup("ColorSpace", &obj1);
1636   if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
1637     error(-1, "Bad color space in shading dictionary");
1638     obj1.free();
1639     return gFalse;
1640   }
1641   obj1.free();
1642
1643   for (i = 0; i < gfxColorMaxComps; ++i) {
1644     background.c[i] = 0;
1645   }
1646   hasBackground = gFalse;
1647   if (dict->lookup("Background", &obj1)->isArray()) {
1648     if (obj1.arrayGetLength() == colorSpace->getNComps()) {
1649       hasBackground = gTrue;
1650       for (i = 0; i < colorSpace->getNComps(); ++i) {
1651         background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum());
1652         obj2.free();
1653       }
1654     } else {
1655       error(-1, "Bad Background in shading dictionary");
1656     }
1657   }
1658   obj1.free();
1659
1660   xMin = yMin = xMax = yMax = 0;
1661   hasBBox = gFalse;
1662   if (dict->lookup("BBox", &obj1)->isArray()) {
1663     if (obj1.arrayGetLength() == 4) {
1664       hasBBox = gTrue;
1665       xMin = obj1.arrayGet(0, &obj2)->getNum();
1666       obj2.free();
1667       yMin = obj1.arrayGet(1, &obj2)->getNum();
1668       obj2.free();
1669       xMax = obj1.arrayGet(2, &obj2)->getNum();
1670       obj2.free();
1671       yMax = obj1.arrayGet(3, &obj2)->getNum();
1672       obj2.free();
1673     } else {
1674       error(-1, "Bad BBox in shading dictionary");
1675     }
1676   }
1677   obj1.free();
1678
1679   return gTrue;
1680 }
1681
1682 //------------------------------------------------------------------------
1683 // GfxFunctionShading
1684 //------------------------------------------------------------------------
1685
1686 GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
1687                                        double x1A, double y1A,
1688                                        double *matrixA,
1689                                        Function **funcsA, int nFuncsA):
1690   GfxShading(1)
1691 {
1692   int i;
1693
1694   x0 = x0A;
1695   y0 = y0A;
1696   x1 = x1A;
1697   y1 = y1A;
1698   for (i = 0; i < 6; ++i) {
1699     matrix[i] = matrixA[i];
1700   }
1701   nFuncs = nFuncsA;
1702   for (i = 0; i < nFuncs; ++i) {
1703     funcs[i] = funcsA[i];
1704   }
1705 }
1706
1707 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
1708   GfxShading(shading)
1709 {
1710   int i;
1711
1712   x0 = shading->x0;
1713   y0 = shading->y0;
1714   x1 = shading->x1;
1715   y1 = shading->y1;
1716   for (i = 0; i < 6; ++i) {
1717     matrix[i] = shading->matrix[i];
1718   }
1719   nFuncs = shading->nFuncs;
1720   for (i = 0; i < nFuncs; ++i) {
1721     funcs[i] = shading->funcs[i]->copy();
1722   }
1723 }
1724
1725 GfxFunctionShading::~GfxFunctionShading() {
1726   int i;
1727
1728   for (i = 0; i < nFuncs; ++i) {
1729     delete funcs[i];
1730   }
1731 }
1732
1733 GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
1734   GfxFunctionShading *shading;
1735   double x0A, y0A, x1A, y1A;
1736   double matrixA[6];
1737   Function *funcsA[gfxColorMaxComps];
1738   int nFuncsA;
1739   Object obj1, obj2;
1740   int i;
1741
1742   x0A = y0A = 0;
1743   x1A = y1A = 1;
1744   if (dict->lookup("Domain", &obj1)->isArray() &&
1745       obj1.arrayGetLength() == 4) {
1746     x0A = obj1.arrayGet(0, &obj2)->getNum();
1747     obj2.free();
1748     y0A = obj1.arrayGet(1, &obj2)->getNum();
1749     obj2.free();
1750     x1A = obj1.arrayGet(2, &obj2)->getNum();
1751     obj2.free();
1752     y1A = obj1.arrayGet(3, &obj2)->getNum();
1753     obj2.free();
1754   }
1755   obj1.free();
1756
1757   matrixA[0] = 1; matrixA[1] = 0;
1758   matrixA[2] = 0; matrixA[3] = 1;
1759   matrixA[4] = 0; matrixA[5] = 0;
1760   if (dict->lookup("Matrix", &obj1)->isArray() &&
1761       obj1.arrayGetLength() == 6) {
1762     matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
1763     obj2.free();
1764     matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
1765     obj2.free();
1766     matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
1767     obj2.free();
1768     matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
1769     obj2.free();
1770     matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
1771     obj2.free();
1772     matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
1773     obj2.free();
1774   }
1775   obj1.free();
1776
1777   dict->lookup("Function", &obj1);
1778   if (obj1.isArray()) {
1779     nFuncsA = obj1.arrayGetLength();
1780     if (nFuncsA > gfxColorMaxComps) {
1781       error(-1, "Invalid Function array in shading dictionary");
1782       goto err1;
1783     }
1784     for (i = 0; i < nFuncsA; ++i) {
1785       obj1.arrayGet(i, &obj2);
1786       if (!(funcsA[i] = Function::parse(&obj2))) {
1787         goto err2;
1788       }
1789       obj2.free();
1790     }
1791   } else {
1792     nFuncsA = 1;
1793     if (!(funcsA[0] = Function::parse(&obj1))) {
1794       goto err1;
1795     }
1796   }
1797   obj1.free();
1798
1799   shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
1800                                    funcsA, nFuncsA);
1801   if (!shading->init(dict)) {
1802     delete shading;
1803     return NULL;
1804   }
1805   return shading;
1806
1807  err2:
1808   obj2.free();
1809  err1:
1810   obj1.free();
1811   return NULL;
1812 }
1813
1814 GfxShading *GfxFunctionShading::copy() {
1815   return new GfxFunctionShading(this);
1816 }
1817
1818 void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
1819   double in[2], out[gfxColorMaxComps];
1820   int i;
1821
1822   // NB: there can be one function with n outputs or n functions with
1823   // one output each (where n = number of color components)
1824   for (i = 0; i < gfxColorMaxComps; ++i) {
1825     out[i] = 0;
1826   }
1827   in[0] = x;
1828   in[1] = y;
1829   for (i = 0; i < nFuncs; ++i) {
1830     funcs[i]->transform(in, &out[i]);
1831   }
1832   for (i = 0; i < gfxColorMaxComps; ++i) {
1833     color->c[i] = dblToCol(out[i]);
1834   }
1835 }
1836
1837 //------------------------------------------------------------------------
1838 // GfxAxialShading
1839 //------------------------------------------------------------------------
1840
1841 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1842                                  double x1A, double y1A,
1843                                  double t0A, double t1A,
1844                                  Function **funcsA, int nFuncsA,
1845                                  GBool extend0A, GBool extend1A):
1846   GfxShading(2)
1847 {
1848   int i;
1849
1850   x0 = x0A;
1851   y0 = y0A;
1852   x1 = x1A;
1853   y1 = y1A;
1854   t0 = t0A;
1855   t1 = t1A;
1856   nFuncs = nFuncsA;
1857   for (i = 0; i < nFuncs; ++i) {
1858     funcs[i] = funcsA[i];
1859   }
1860   extend0 = extend0A;
1861   extend1 = extend1A;
1862 }
1863
1864 GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
1865   GfxShading(shading)
1866 {
1867   int i;
1868
1869   x0 = shading->x0;
1870   y0 = shading->y0;
1871   x1 = shading->x1;
1872   y1 = shading->y1;
1873   t0 = shading->t0;
1874   y1 = shading->t1;
1875   nFuncs = shading->nFuncs;
1876   for (i = 0; i < nFuncs; ++i) {
1877     funcs[i] = shading->funcs[i]->copy();
1878   }
1879   extend0 = shading->extend0;
1880   extend1 = shading->extend1;
1881 }
1882
1883 GfxAxialShading::~GfxAxialShading() {
1884   int i;
1885
1886   for (i = 0; i < nFuncs; ++i) {
1887     delete funcs[i];
1888   }
1889 }
1890
1891 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1892   GfxAxialShading *shading;
1893   double x0A, y0A, x1A, y1A;
1894   double t0A, t1A;
1895   Function *funcsA[gfxColorMaxComps];
1896   int nFuncsA;
1897   GBool extend0A, extend1A;
1898   Object obj1, obj2;
1899   int i;
1900
1901   x0A = y0A = x1A = y1A = 0;
1902   if (dict->lookup("Coords", &obj1)->isArray() &&
1903       obj1.arrayGetLength() == 4) {
1904     x0A = obj1.arrayGet(0, &obj2)->getNum();
1905     obj2.free();
1906     y0A = obj1.arrayGet(1, &obj2)->getNum();
1907     obj2.free();
1908     x1A = obj1.arrayGet(2, &obj2)->getNum();
1909     obj2.free();
1910     y1A = obj1.arrayGet(3, &obj2)->getNum();
1911     obj2.free();
1912   } else {
1913     error(-1, "Missing or invalid Coords in shading dictionary");
1914     goto err1;
1915   }
1916   obj1.free();
1917
1918   t0A = 0;
1919   t1A = 1;
1920   if (dict->lookup("Domain", &obj1)->isArray() &&
1921       obj1.arrayGetLength() == 2) {
1922     t0A = obj1.arrayGet(0, &obj2)->getNum();
1923     obj2.free();
1924     t1A = obj1.arrayGet(1, &obj2)->getNum();
1925     obj2.free();
1926   }
1927   obj1.free();
1928
1929   dict->lookup("Function", &obj1);
1930   if (obj1.isArray()) {
1931     nFuncsA = obj1.arrayGetLength();
1932     if (nFuncsA > gfxColorMaxComps) {
1933       error(-1, "Invalid Function array in shading dictionary");
1934       goto err1;
1935     }
1936     for (i = 0; i < nFuncsA; ++i) {
1937       obj1.arrayGet(i, &obj2);
1938       if (!(funcsA[i] = Function::parse(&obj2))) {
1939         obj1.free();
1940         obj2.free();
1941         goto err1;
1942       }
1943       obj2.free();
1944     }
1945   } else {
1946     nFuncsA = 1;
1947     if (!(funcsA[0] = Function::parse(&obj1))) {
1948       obj1.free();
1949       goto err1;
1950     }
1951   }
1952   obj1.free();
1953
1954   extend0A = extend1A = gFalse;
1955   if (dict->lookup("Extend", &obj1)->isArray() &&
1956       obj1.arrayGetLength() == 2) {
1957     extend0A = obj1.arrayGet(0, &obj2)->getBool();
1958     obj2.free();
1959     extend1A = obj1.arrayGet(1, &obj2)->getBool();
1960     obj2.free();
1961   }
1962   obj1.free();
1963
1964   shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1965                                 funcsA, nFuncsA, extend0A, extend1A);
1966   if (!shading->init(dict)) {
1967     delete shading;
1968     return NULL;
1969   }
1970   return shading;
1971
1972  err1:
1973   return NULL;
1974 }
1975
1976 GfxShading *GfxAxialShading::copy() {
1977   return new GfxAxialShading(this);
1978 }
1979
1980 void GfxAxialShading::getColor(double t, GfxColor *color) {
1981   double out[gfxColorMaxComps];
1982   int i;
1983
1984   // NB: there can be one function with n outputs or n functions with
1985   // one output each (where n = number of color components)
1986   for (i = 0; i < gfxColorMaxComps; ++i) {
1987     out[i] = 0;
1988   }
1989   for (i = 0; i < nFuncs; ++i) {
1990     funcs[i]->transform(&t, &out[i]);
1991   }
1992   for (i = 0; i < gfxColorMaxComps; ++i) {
1993     color->c[i] = dblToCol(out[i]);
1994   }
1995 }
1996
1997 //------------------------------------------------------------------------
1998 // GfxRadialShading
1999 //------------------------------------------------------------------------
2000
2001 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
2002                                    double x1A, double y1A, double r1A,
2003                                    double t0A, double t1A,
2004                                    Function **funcsA, int nFuncsA,
2005                                    GBool extend0A, GBool extend1A):
2006   GfxShading(3)
2007 {
2008   int i;
2009
2010   x0 = x0A;
2011   y0 = y0A;
2012   r0 = r0A;
2013   x1 = x1A;
2014   y1 = y1A;
2015   r1 = r1A;
2016   t0 = t0A;
2017   t1 = t1A;
2018   nFuncs = nFuncsA;
2019   for (i = 0; i < nFuncs; ++i) {
2020     funcs[i] = funcsA[i];
2021   }
2022   extend0 = extend0A;
2023   extend1 = extend1A;
2024 }
2025
2026 GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
2027   GfxShading(shading)
2028 {
2029   int i;
2030
2031   x0 = shading->x0;
2032   y0 = shading->y0;
2033   r0 = shading->r0;
2034   x1 = shading->x1;
2035   y1 = shading->y1;
2036   r1 = shading->r1;
2037   t0 = shading->t0;
2038   y1 = shading->t1;
2039   nFuncs = shading->nFuncs;
2040   for (i = 0; i < nFuncs; ++i) {
2041     funcs[i] = shading->funcs[i]->copy();
2042   }
2043   extend0 = shading->extend0;
2044   extend1 = shading->extend1;
2045 }
2046
2047 GfxRadialShading::~GfxRadialShading() {
2048   int i;
2049
2050   for (i = 0; i < nFuncs; ++i) {
2051     delete funcs[i];
2052   }
2053 }
2054
2055 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
2056   GfxRadialShading *shading;
2057   double x0A, y0A, r0A, x1A, y1A, r1A;
2058   double t0A, t1A;
2059   Function *funcsA[gfxColorMaxComps];
2060   int nFuncsA;
2061   GBool extend0A, extend1A;
2062   Object obj1, obj2;
2063   int i;
2064
2065   x0A = y0A = r0A = x1A = y1A = r1A = 0;
2066   if (dict->lookup("Coords", &obj1)->isArray() &&
2067       obj1.arrayGetLength() == 6) {
2068     x0A = obj1.arrayGet(0, &obj2)->getNum();
2069     obj2.free();
2070     y0A = obj1.arrayGet(1, &obj2)->getNum();
2071     obj2.free();
2072     r0A = obj1.arrayGet(2, &obj2)->getNum();
2073     obj2.free();
2074     x1A = obj1.arrayGet(3, &obj2)->getNum();
2075     obj2.free();
2076     y1A = obj1.arrayGet(4, &obj2)->getNum();
2077     obj2.free();
2078     r1A = obj1.arrayGet(5, &obj2)->getNum();
2079     obj2.free();
2080   } else {
2081     error(-1, "Missing or invalid Coords in shading dictionary");
2082     goto err1;
2083   }
2084   obj1.free();
2085
2086   t0A = 0;
2087   t1A = 1;
2088   if (dict->lookup("Domain", &obj1)->isArray() &&
2089       obj1.arrayGetLength() == 2) {
2090     t0A = obj1.arrayGet(0, &obj2)->getNum();
2091     obj2.free();
2092     t1A = obj1.arrayGet(1, &obj2)->getNum();
2093     obj2.free();
2094   }
2095   obj1.free();
2096
2097   dict->lookup("Function", &obj1);
2098   if (obj1.isArray()) {
2099     nFuncsA = obj1.arrayGetLength();
2100     if (nFuncsA > gfxColorMaxComps) {
2101       error(-1, "Invalid Function array in shading dictionary");
2102       goto err1;
2103     }
2104     for (i = 0; i < nFuncsA; ++i) {
2105       obj1.arrayGet(i, &obj2);
2106       if (!(funcsA[i] = Function::parse(&obj2))) {
2107         obj1.free();
2108         obj2.free();
2109         goto err1;
2110       }
2111       obj2.free();
2112     }
2113   } else {
2114     nFuncsA = 1;
2115     if (!(funcsA[0] = Function::parse(&obj1))) {
2116       obj1.free();
2117       goto err1;
2118     }
2119   }
2120   obj1.free();
2121
2122   extend0A = extend1A = gFalse;
2123   if (dict->lookup("Extend", &obj1)->isArray() &&
2124       obj1.arrayGetLength() == 2) {
2125     extend0A = obj1.arrayGet(0, &obj2)->getBool();
2126     obj2.free();
2127     extend1A = obj1.arrayGet(1, &obj2)->getBool();
2128     obj2.free();
2129   }
2130   obj1.free();
2131
2132   shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
2133                                  funcsA, nFuncsA, extend0A, extend1A);
2134   if (!shading->init(dict)) {
2135     delete shading;
2136     return NULL;
2137   }
2138   return shading;
2139
2140  err1:
2141   return NULL;
2142 }
2143
2144 GfxShading *GfxRadialShading::copy() {
2145   return new GfxRadialShading(this);
2146 }
2147
2148 void GfxRadialShading::getColor(double t, GfxColor *color) {
2149   double out[gfxColorMaxComps];
2150   int i;
2151
2152   // NB: there can be one function with n outputs or n functions with
2153   // one output each (where n = number of color components)
2154   for (i = 0; i < gfxColorMaxComps; ++i) {
2155     out[i] = 0;
2156   }
2157   for (i = 0; i < nFuncs; ++i) {
2158     funcs[i]->transform(&t, &out[i]);
2159   }
2160   for (i = 0; i < gfxColorMaxComps; ++i) {
2161     color->c[i] = dblToCol(out[i]);
2162   }
2163 }
2164
2165 //------------------------------------------------------------------------
2166 // GfxShadingBitBuf
2167 //------------------------------------------------------------------------
2168
2169 class GfxShadingBitBuf {
2170 public:
2171
2172   GfxShadingBitBuf(Stream *strA);
2173   ~GfxShadingBitBuf();
2174   GBool getBits(int n, Guint *val);
2175   void flushBits();
2176
2177 private:
2178
2179   Stream *str;
2180   int bitBuf;
2181   int nBits;
2182 };
2183
2184 GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) {
2185   str = strA;
2186   str->reset();
2187   bitBuf = 0;
2188   nBits = 0;
2189 }
2190
2191 GfxShadingBitBuf::~GfxShadingBitBuf() {
2192   str->close();
2193 }
2194
2195 GBool GfxShadingBitBuf::getBits(int n, Guint *val) {
2196   int x;
2197
2198   if (nBits >= n) {
2199     x = (bitBuf >> (nBits - n)) & ((1 << n) - 1);
2200     nBits -= n;
2201   } else {
2202     x = 0;
2203     if (nBits > 0) {
2204       x = bitBuf & ((1 << nBits) - 1);
2205       n -= nBits;
2206       nBits = 0;
2207     }
2208     while (n > 0) {
2209       if ((bitBuf = str->getChar()) == EOF) {
2210         nBits = 0;
2211         return gFalse;
2212       }
2213       if (n >= 8) {
2214         x = (x << 8) | bitBuf;
2215         n -= 8;
2216       } else {
2217         x = (x << n) | (bitBuf >> (8 - n));
2218         nBits = 8 - n;
2219         n = 0;
2220       }
2221     }
2222   }
2223   *val = x;
2224   return gTrue;
2225 }
2226
2227 void GfxShadingBitBuf::flushBits() {
2228   bitBuf = 0;
2229   nBits = 0;
2230 }
2231
2232 //------------------------------------------------------------------------
2233 // GfxGouraudTriangleShading
2234 //------------------------------------------------------------------------
2235
2236 GfxGouraudTriangleShading::GfxGouraudTriangleShading(
2237                                int typeA,
2238                                GfxGouraudVertex *verticesA, int nVerticesA,
2239                                int (*trianglesA)[3], int nTrianglesA,
2240                                Function **funcsA, int nFuncsA):
2241   GfxShading(typeA)
2242 {
2243   int i;
2244
2245   vertices = verticesA;
2246   nVertices = nVerticesA;
2247   triangles = trianglesA;
2248   nTriangles = nTrianglesA;
2249   nFuncs = nFuncsA;
2250   for (i = 0; i < nFuncs; ++i) {
2251     funcs[i] = funcsA[i];
2252   }
2253 }
2254
2255 GfxGouraudTriangleShading::GfxGouraudTriangleShading(
2256                                GfxGouraudTriangleShading *shading):
2257   GfxShading(shading)
2258 {
2259   int i;
2260
2261   nVertices = shading->nVertices;
2262   vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex));
2263   memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex));
2264   nTriangles = shading->nTriangles;
2265   triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int));
2266   memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int));
2267   nFuncs = shading->nFuncs;
2268   for (i = 0; i < nFuncs; ++i) {
2269     funcs[i] = shading->funcs[i]->copy();
2270   }
2271 }
2272
2273 GfxGouraudTriangleShading::~GfxGouraudTriangleShading() {
2274   int i;
2275
2276   gfree(vertices);
2277   gfree(triangles);
2278   for (i = 0; i < nFuncs; ++i) {
2279     delete funcs[i];
2280   }
2281 }
2282
2283 GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA,
2284                                                             Dict *dict,
2285                                                             Stream *str) {
2286   GfxGouraudTriangleShading *shading;
2287   Function *funcsA[gfxColorMaxComps];
2288   int nFuncsA;
2289   int coordBits, compBits, flagBits, vertsPerRow, nRows;
2290   double xMin, xMax, yMin, yMax;
2291   double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
2292   double xMul, yMul;
2293   double cMul[gfxColorMaxComps];
2294   GfxGouraudVertex *verticesA;
2295   int (*trianglesA)[3];
2296   int nComps, nVerticesA, nTrianglesA, vertSize, triSize;
2297   Guint x, y, flag;
2298   Guint c[gfxColorMaxComps];
2299   GfxShadingBitBuf *bitBuf;
2300   Object obj1, obj2;
2301   int i, j, k, state;
2302
2303   if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
2304     coordBits = obj1.getInt();
2305   } else {
2306     error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
2307     goto err2;
2308   }
2309   obj1.free();
2310   if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
2311     compBits = obj1.getInt();
2312   } else {
2313     error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
2314     goto err2;
2315   }
2316   obj1.free();
2317   flagBits = vertsPerRow = 0; // make gcc happy
2318   if (typeA == 4) {
2319     if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
2320       flagBits = obj1.getInt();
2321     } else {
2322       error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
2323       goto err2;
2324     }
2325     obj1.free();
2326   } else {
2327     if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
2328       vertsPerRow = obj1.getInt();
2329     } else {
2330       error(-1, "Missing or invalid VerticesPerRow in shading dictionary");
2331       goto err2;
2332     }
2333     obj1.free();
2334   }
2335   if (dict->lookup("Decode", &obj1)->isArray() &&
2336       obj1.arrayGetLength() >= 6) {
2337     xMin = obj1.arrayGet(0, &obj2)->getNum();
2338     obj2.free();
2339     xMax = obj1.arrayGet(1, &obj2)->getNum();
2340     obj2.free();
2341     xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
2342     yMin = obj1.arrayGet(2, &obj2)->getNum();
2343     obj2.free();
2344     yMax = obj1.arrayGet(3, &obj2)->getNum();
2345     obj2.free();
2346     yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
2347     for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
2348       cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
2349       obj2.free();
2350       cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
2351       obj2.free();
2352       cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
2353     }
2354     nComps = i;
2355   } else {
2356     error(-1, "Missing or invalid Decode array in shading dictionary");
2357     goto err2;
2358   }
2359   obj1.free();
2360
2361   if (!dict->lookup("Function", &obj1)->isNull()) {
2362     if (obj1.isArray()) {
2363       nFuncsA = obj1.arrayGetLength();
2364       if (nFuncsA > gfxColorMaxComps) {
2365         error(-1, "Invalid Function array in shading dictionary");
2366         goto err1;
2367       }
2368       for (i = 0; i < nFuncsA; ++i) {
2369         obj1.arrayGet(i, &obj2);
2370         if (!(funcsA[i] = Function::parse(&obj2))) {
2371           obj1.free();
2372           obj2.free();
2373           goto err1;
2374         }
2375         obj2.free();
2376       }
2377     } else {
2378       nFuncsA = 1;
2379       if (!(funcsA[0] = Function::parse(&obj1))) {
2380         obj1.free();
2381         goto err1;
2382       }
2383     }
2384   } else {
2385     nFuncsA = 0;
2386   }
2387   obj1.free();
2388
2389   nVerticesA = nTrianglesA = 0;
2390   verticesA = NULL;
2391   trianglesA = NULL;
2392   vertSize = triSize = 0;
2393   state = 0;
2394   flag = 0; // make gcc happy
2395   bitBuf = new GfxShadingBitBuf(str);
2396   while (1) {
2397     if (typeA == 4) {
2398       if (!bitBuf->getBits(flagBits, &flag)) {
2399         break;
2400       }
2401     }
2402     if (!bitBuf->getBits(coordBits, &x) ||
2403         !bitBuf->getBits(coordBits, &y)) {
2404       break;
2405     }
2406     for (i = 0; i < nComps; ++i) {
2407       if (!bitBuf->getBits(compBits, &c[i])) {
2408         break;
2409       }
2410     }
2411     if (i < nComps) {
2412       break;
2413     }
2414     if (nVerticesA == vertSize) {
2415       vertSize = (vertSize == 0) ? 16 : 2 * vertSize;
2416       verticesA = (GfxGouraudVertex *)
2417                       greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex));
2418     }
2419     verticesA[nVerticesA].x = xMin + xMul * (double)x;
2420     verticesA[nVerticesA].y = yMin + yMul * (double)y;
2421     for (i = 0; i < nComps; ++i) {
2422       verticesA[nVerticesA].color.c[i] =
2423           dblToCol(cMin[i] + cMul[i] * (double)c[i]);
2424     }
2425     ++nVerticesA;
2426     bitBuf->flushBits();
2427     if (typeA == 4) {
2428       if (state == 0 || state == 1) {
2429         ++state;
2430       } else if (state == 2 || flag > 0) {
2431         if (nTrianglesA == triSize) {
2432           triSize = (triSize == 0) ? 16 : 2 * triSize;
2433           trianglesA = (int (*)[3])
2434                            greallocn(trianglesA, triSize * 3, sizeof(int));
2435         }
2436         if (state == 2) {
2437           trianglesA[nTrianglesA][0] = nVerticesA - 3;
2438           trianglesA[nTrianglesA][1] = nVerticesA - 2;
2439           trianglesA[nTrianglesA][2] = nVerticesA - 1;
2440           ++state;
2441         } else if (flag == 1) {
2442           trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1];
2443           trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
2444           trianglesA[nTrianglesA][2] = nVerticesA - 1;
2445         } else { // flag == 2
2446           trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0];
2447           trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
2448           trianglesA[nTrianglesA][2] = nVerticesA - 1;
2449         }
2450         ++nTrianglesA;
2451       } else { // state == 3 && flag == 0
2452         state = 1;
2453       }
2454     }
2455   }
2456   delete bitBuf;
2457   if (typeA == 5) {
2458     nRows = nVerticesA / vertsPerRow;
2459     nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1);
2460     trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int));
2461     k = 0;
2462     for (i = 0; i < nRows - 1; ++i) {
2463       for (j = 0; j < vertsPerRow - 1; ++j) {
2464         trianglesA[k][0] = i * vertsPerRow + j;
2465         trianglesA[k][1] = i * vertsPerRow + j+1;
2466         trianglesA[k][2] = (i+1) * vertsPerRow + j;
2467         ++k;
2468         trianglesA[k][0] = i * vertsPerRow + j+1;
2469         trianglesA[k][1] = (i+1) * vertsPerRow + j;
2470         trianglesA[k][2] = (i+1) * vertsPerRow + j+1;
2471         ++k;
2472       }
2473     }
2474   }
2475
2476   shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA,
2477                                           trianglesA, nTrianglesA,
2478                                           funcsA, nFuncsA);
2479   if (!shading->init(dict)) {
2480     delete shading;
2481     return NULL;
2482   }
2483   return shading;
2484
2485  err2:
2486   obj1.free();
2487  err1:
2488   return NULL;
2489 }
2490
2491 GfxShading *GfxGouraudTriangleShading::copy() {
2492   return new GfxGouraudTriangleShading(this);
2493 }
2494
2495 void GfxGouraudTriangleShading::getTriangle(
2496                                     int i,
2497                                     double *x0, double *y0, GfxColor *color0,
2498                                     double *x1, double *y1, GfxColor *color1,
2499                                     double *x2, double *y2, GfxColor *color2) {
2500   double in;
2501   double out[gfxColorMaxComps];
2502   int v, j;
2503
2504   v = triangles[i][0];
2505   *x0 = vertices[v].x;
2506   *y0 = vertices[v].y;
2507   if (nFuncs > 0) {
2508     in = colToDbl(vertices[v].color.c[0]);
2509     for (j = 0; j < nFuncs; ++j) {
2510       funcs[j]->transform(&in, &out[j]);
2511     }
2512     for (j = 0; j < gfxColorMaxComps; ++j) {
2513       color0->c[j] = dblToCol(out[j]);
2514     }
2515   } else {
2516     *color0 = vertices[v].color;
2517   }
2518   v = triangles[i][1];
2519   *x1 = vertices[v].x;
2520   *y1 = vertices[v].y;
2521   if (nFuncs > 0) {
2522     in = colToDbl(vertices[v].color.c[0]);
2523     for (j = 0; j < nFuncs; ++j) {
2524       funcs[j]->transform(&in, &out[j]);
2525     }
2526     for (j = 0; j < gfxColorMaxComps; ++j) {
2527       color1->c[j] = dblToCol(out[j]);
2528     }
2529   } else {
2530     *color1 = vertices[v].color;
2531   }
2532   v = triangles[i][2];
2533   *x2 = vertices[v].x;
2534   *y2 = vertices[v].y;
2535   if (nFuncs > 0) {
2536     in = colToDbl(vertices[v].color.c[0]);
2537     for (j = 0; j < nFuncs; ++j) {
2538       funcs[j]->transform(&in, &out[j]);
2539     }
2540     for (j = 0; j < gfxColorMaxComps; ++j) {
2541       color2->c[j] = dblToCol(out[j]);
2542     }
2543   } else {
2544     *color2 = vertices[v].color;
2545   }
2546 }
2547
2548 //------------------------------------------------------------------------
2549 // GfxPatchMeshShading
2550 //------------------------------------------------------------------------
2551
2552 GfxPatchMeshShading::GfxPatchMeshShading(int typeA,
2553                                          GfxPatch *patchesA, int nPatchesA,
2554                                          Function **funcsA, int nFuncsA):
2555   GfxShading(typeA)
2556 {
2557   int i;
2558
2559   patches = patchesA;
2560   nPatches = nPatchesA;
2561   nFuncs = nFuncsA;
2562   for (i = 0; i < nFuncs; ++i) {
2563     funcs[i] = funcsA[i];
2564   }
2565 }
2566
2567 GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading):
2568   GfxShading(shading)
2569 {
2570   int i;
2571
2572   nPatches = shading->nPatches;
2573   patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch));
2574   memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch));
2575   nFuncs = shading->nFuncs;
2576   for (i = 0; i < nFuncs; ++i) {
2577     funcs[i] = shading->funcs[i]->copy();
2578   }
2579 }
2580
2581 GfxPatchMeshShading::~GfxPatchMeshShading() {
2582   int i;
2583
2584   gfree(patches);
2585   for (i = 0; i < nFuncs; ++i) {
2586     delete funcs[i];
2587   }
2588 }
2589
2590 GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict,
2591                                                 Stream *str) {
2592   GfxPatchMeshShading *shading;
2593   Function *funcsA[gfxColorMaxComps];
2594   int nFuncsA;
2595   int coordBits, compBits, flagBits;
2596   double xMin, xMax, yMin, yMax;
2597   double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
2598   double xMul, yMul;
2599   double cMul[gfxColorMaxComps];
2600   GfxPatch *patchesA, *p;
2601   int nComps, nPatchesA, patchesSize, nPts, nColors;
2602   Guint flag;
2603   double x[16], y[16];
2604   Guint xi, yi;
2605   GfxColorComp c[4][gfxColorMaxComps];
2606   Guint ci[4];
2607   GfxShadingBitBuf *bitBuf;
2608   Object obj1, obj2;
2609   int i, j;
2610
2611   if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
2612     coordBits = obj1.getInt();
2613   } else {
2614     error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
2615     goto err2;
2616   }
2617   obj1.free();
2618   if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
2619     compBits = obj1.getInt();
2620   } else {
2621     error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
2622     goto err2;
2623   }
2624   obj1.free();
2625   if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
2626     flagBits = obj1.getInt();
2627   } else {
2628     error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
2629     goto err2;
2630   }
2631   obj1.free();
2632   if (dict->lookup("Decode", &obj1)->isArray() &&
2633       obj1.arrayGetLength() >= 6) {
2634     xMin = obj1.arrayGet(0, &obj2)->getNum();
2635     obj2.free();
2636     xMax = obj1.arrayGet(1, &obj2)->getNum();
2637     obj2.free();
2638     xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
2639     yMin = obj1.arrayGet(2, &obj2)->getNum();
2640     obj2.free();
2641     yMax = obj1.arrayGet(3, &obj2)->getNum();
2642     obj2.free();
2643     yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
2644     for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
2645       cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
2646       obj2.free();
2647       cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
2648       obj2.free();
2649       cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
2650     }
2651     nComps = i;
2652   } else {
2653     error(-1, "Missing or invalid Decode array in shading dictionary");
2654     goto err2;
2655   }
2656   obj1.free();
2657
2658   if (!dict->lookup("Function", &obj1)->isNull()) {
2659     if (obj1.isArray()) {
2660       nFuncsA = obj1.arrayGetLength();
2661       if (nFuncsA > gfxColorMaxComps) {
2662         error(-1, "Invalid Function array in shading dictionary");
2663         goto err1;
2664       }
2665       for (i = 0; i < nFuncsA; ++i) {
2666         obj1.arrayGet(i, &obj2);
2667         if (!(funcsA[i] = Function::parse(&obj2))) {
2668           obj1.free();
2669           obj2.free();
2670           goto err1;
2671         }
2672         obj2.free();
2673       }
2674     } else {
2675       nFuncsA = 1;
2676       if (!(funcsA[0] = Function::parse(&obj1))) {
2677         obj1.free();
2678         goto err1;
2679       }
2680     }
2681   } else {
2682     nFuncsA = 0;
2683   }
2684   obj1.free();
2685
2686   nPatchesA = 0;
2687   patchesA = NULL;
2688   patchesSize = 0;
2689   bitBuf = new GfxShadingBitBuf(str);
2690   while (1) {
2691     if (!bitBuf->getBits(flagBits, &flag)) {
2692       break;
2693     }
2694     if (typeA == 6) {
2695       switch (flag) {
2696       case 0: nPts = 12; nColors = 4; break;
2697       case 1:
2698       case 2:
2699       case 3:
2700       default: nPts =  8; nColors = 2; break;
2701       }
2702     } else {
2703       switch (flag) {
2704       case 0: nPts = 16; nColors = 4; break;
2705       case 1:
2706       case 2:
2707       case 3:
2708       default: nPts = 12; nColors = 2; break;
2709       }
2710     }
2711     for (i = 0; i < nPts; ++i) {
2712       if (!bitBuf->getBits(coordBits, &xi) ||
2713           !bitBuf->getBits(coordBits, &yi)) {
2714         break;
2715       }
2716       x[i] = xMin + xMul * (double)xi;
2717       y[i] = yMin + yMul * (double)yi;
2718     }
2719     if (i < nPts) {
2720       break;
2721     }
2722     for (i = 0; i < nColors; ++i) {
2723       for (j = 0; j < nComps; ++j) {
2724         if (!bitBuf->getBits(compBits, &ci[j])) {
2725           break;
2726         }
2727         c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]);
2728       }
2729       if (j < nComps) {
2730         break;
2731       }
2732     }
2733     if (i < nColors) {
2734       break;
2735     }
2736     if (nPatchesA == patchesSize) {
2737       patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize;
2738       patchesA = (GfxPatch *)greallocn(patchesA,
2739                                        patchesSize, sizeof(GfxPatch));
2740     }
2741     p = &patchesA[nPatchesA];
2742     if (typeA == 6) {
2743       switch (flag) {
2744       case 0:
2745         p->x[0][0] = x[0];
2746         p->y[0][0] = y[0];
2747         p->x[0][1] = x[1];
2748         p->y[0][1] = y[1];
2749         p->x[0][2] = x[2];
2750         p->y[0][2] = y[2];
2751         p->x[0][3] = x[3];
2752         p->y[0][3] = y[3];
2753         p->x[1][3] = x[4];
2754         p->y[1][3] = y[4];
2755         p->x[2][3] = x[5];
2756         p->y[2][3] = y[5];
2757         p->x[3][3] = x[6];
2758         p->y[3][3] = y[6];
2759         p->x[3][2] = x[7];
2760         p->y[3][2] = y[7];
2761         p->x[3][1] = x[8];
2762         p->y[3][1] = y[8];
2763         p->x[3][0] = x[9];
2764         p->y[3][0] = y[9];
2765         p->x[2][0] = x[10];
2766         p->y[2][0] = y[10];
2767         p->x[1][0] = x[11];
2768         p->y[1][0] = y[11];
2769         for (j = 0; j < nComps; ++j) {
2770           p->color[0][0].c[j] = c[0][j];
2771           p->color[0][1].c[j] = c[1][j];
2772           p->color[1][1].c[j] = c[2][j];
2773           p->color[1][0].c[j] = c[3][j];
2774         }
2775         break;
2776       case 1:
2777         p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
2778         p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
2779         p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
2780         p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
2781         p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
2782         p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
2783         p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
2784         p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
2785         p->x[1][3] = x[0];
2786         p->y[1][3] = y[0];
2787         p->x[2][3] = x[1];
2788         p->y[2][3] = y[1];
2789         p->x[3][3] = x[2];
2790         p->y[3][3] = y[2];
2791         p->x[3][2] = x[3];
2792         p->y[3][2] = y[3];
2793         p->x[3][1] = x[4];
2794         p->y[3][1] = y[4];
2795         p->x[3][0] = x[5];
2796         p->y[3][0] = y[5];
2797         p->x[2][0] = x[6];
2798         p->y[2][0] = y[6];
2799         p->x[1][0] = x[7];
2800         p->y[1][0] = y[7];
2801         for (j = 0; j < nComps; ++j) {
2802           p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
2803           p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
2804           p->color[1][1].c[j] = c[0][j];
2805           p->color[1][0].c[j] = c[1][j];
2806         }
2807         break;
2808       case 2:
2809         p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
2810         p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
2811         p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
2812         p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
2813         p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
2814         p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
2815         p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
2816         p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
2817         p->x[1][3] = x[0];
2818         p->y[1][3] = y[0];
2819         p->x[2][3] = x[1];
2820         p->y[2][3] = y[1];
2821         p->x[3][3] = x[2];
2822         p->y[3][3] = y[2];
2823         p->x[3][2] = x[3];
2824         p->y[3][2] = y[3];
2825         p->x[3][1] = x[4];
2826         p->y[3][1] = y[4];
2827         p->x[3][0] = x[5];
2828         p->y[3][0] = y[5];
2829         p->x[2][0] = x[6];
2830         p->y[2][0] = y[6];
2831         p->x[1][0] = x[7];
2832         p->y[1][0] = y[7];
2833         for (j = 0; j < nComps; ++j) {
2834           p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
2835           p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
2836           p->color[1][1].c[j] = c[0][j];
2837           p->color[1][0].c[j] = c[1][j];
2838         }
2839         break;
2840       case 3:
2841         p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
2842         p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
2843         p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
2844         p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
2845         p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
2846         p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
2847         p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
2848         p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
2849         p->x[1][3] = x[0];
2850         p->y[1][3] = y[0];
2851         p->x[2][3] = x[1];
2852         p->y[2][3] = y[1];
2853         p->x[3][3] = x[2];
2854         p->y[3][3] = y[2];
2855         p->x[3][2] = x[3];
2856         p->y[3][2] = y[3];
2857         p->x[3][1] = x[4];
2858         p->y[3][1] = y[4];
2859         p->x[3][0] = x[5];
2860         p->y[3][0] = y[5];
2861         p->x[2][0] = x[6];
2862         p->y[2][0] = y[6];
2863         p->x[1][0] = x[7];
2864         p->y[1][0] = y[7];
2865         for (j = 0; j < nComps; ++j) {
2866           p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
2867           p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
2868           p->color[1][1].c[j] = c[0][j];
2869           p->color[1][0].c[j] = c[1][j];
2870         }
2871         break;
2872       }
2873     } else {
2874       switch (flag) {
2875       case 0:
2876         p->x[0][0] = x[0];
2877         p->y[0][0] = y[0];
2878         p->x[0][1] = x[1];
2879         p->y[0][1] = y[1];
2880         p->x[0][2] = x[2];
2881         p->y[0][2] = y[2];
2882         p->x[0][3] = x[3];
2883         p->y[0][3] = y[3];
2884         p->x[1][3] = x[4];
2885         p->y[1][3] = y[4];
2886         p->x[2][3] = x[5];
2887         p->y[2][3] = y[5];
2888         p->x[3][3] = x[6];
2889         p->y[3][3] = y[6];
2890         p->x[3][2] = x[7];
2891         p->y[3][2] = y[7];
2892         p->x[3][1] = x[8];
2893         p->y[3][1] = y[8];
2894         p->x[3][0] = x[9];
2895         p->y[3][0] = y[9];
2896         p->x[2][0] = x[10];
2897         p->y[2][0] = y[10];
2898         p->x[1][0] = x[11];
2899         p->y[1][0] = y[11];
2900         p->x[1][1] = x[12];
2901         p->y[1][1] = y[12];
2902         p->x[1][2] = x[13];
2903         p->y[1][2] = y[13];
2904         p->x[2][2] = x[14];
2905         p->y[2][2] = y[14];
2906         p->x[2][1] = x[15];
2907         p->y[2][1] = y[15];
2908         for (j = 0; j < nComps; ++j) {
2909           p->color[0][0].c[j] = c[0][j];
2910           p->color[0][1].c[j] = c[1][j];
2911           p->color[1][1].c[j] = c[2][j];
2912           p->color[1][0].c[j] = c[3][j];
2913         }
2914         break;
2915       case 1:
2916         p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
2917         p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
2918         p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
2919         p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
2920         p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
2921         p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
2922         p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
2923         p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
2924         p->x[1][3] = x[0];
2925         p->y[1][3] = y[0];
2926         p->x[2][3] = x[1];
2927         p->y[2][3] = y[1];
2928         p->x[3][3] = x[2];
2929         p->y[3][3] = y[2];
2930         p->x[3][2] = x[3];
2931         p->y[3][2] = y[3];
2932         p->x[3][1] = x[4];
2933         p->y[3][1] = y[4];
2934         p->x[3][0] = x[5];
2935         p->y[3][0] = y[5];
2936         p->x[2][0] = x[6];
2937         p->y[2][0] = y[6];
2938         p->x[1][0] = x[7];
2939         p->y[1][0] = y[7];
2940         p->x[1][1] = x[8];
2941         p->y[1][1] = y[8];
2942         p->x[1][2] = x[9];
2943         p->y[1][2] = y[9];
2944         p->x[2][2] = x[10];
2945         p->y[2][2] = y[10];
2946         p->x[2][1] = x[11];
2947         p->y[2][1] = y[11];
2948         for (j = 0; j < nComps; ++j) {
2949           p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
2950           p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
2951           p->color[1][1].c[j] = c[0][j];
2952           p->color[1][0].c[j] = c[1][j];
2953         }
2954         break;
2955       case 2:
2956         p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
2957         p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
2958         p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
2959         p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
2960         p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
2961         p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
2962         p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
2963         p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
2964         p->x[1][3] = x[0];
2965         p->y[1][3] = y[0];
2966         p->x[2][3] = x[1];
2967         p->y[2][3] = y[1];
2968         p->x[3][3] = x[2];
2969         p->y[3][3] = y[2];
2970         p->x[3][2] = x[3];
2971         p->y[3][2] = y[3];
2972         p->x[3][1] = x[4];
2973         p->y[3][1] = y[4];
2974         p->x[3][0] = x[5];
2975         p->y[3][0] = y[5];
2976         p->x[2][0] = x[6];
2977         p->y[2][0] = y[6];
2978         p->x[1][0] = x[7];
2979         p->y[1][0] = y[7];
2980         p->x[1][1] = x[8];
2981         p->y[1][1] = y[8];
2982         p->x[1][2] = x[9];
2983         p->y[1][2] = y[9];
2984         p->x[2][2] = x[10];
2985         p->y[2][2] = y[10];
2986         p->x[2][1] = x[11];
2987         p->y[2][1] = y[11];
2988         for (j = 0; j < nComps; ++j) {
2989           p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
2990           p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
2991           p->color[1][1].c[j] = c[0][j];
2992           p->color[1][0].c[j] = c[1][j];
2993         }
2994         break;
2995       case 3:
2996         p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
2997         p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
2998         p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
2999         p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
3000         p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
3001         p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
3002         p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
3003         p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
3004         p->x[1][3] = x[0];
3005         p->y[1][3] = y[0];
3006         p->x[2][3] = x[1];
3007         p->y[2][3] = y[1];
3008         p->x[3][3] = x[2];
3009         p->y[3][3] = y[2];
3010         p->x[3][2] = x[3];
3011         p->y[3][2] = y[3];
3012         p->x[3][1] = x[4];
3013         p->y[3][1] = y[4];
3014         p->x[3][0] = x[5];
3015         p->y[3][0] = y[5];
3016         p->x[2][0] = x[6];
3017         p->y[2][0] = y[6];
3018         p->x[1][0] = x[7];
3019         p->y[1][0] = y[7];
3020         p->x[1][1] = x[8];
3021         p->y[1][1] = y[8];
3022         p->x[1][2] = x[9];
3023         p->y[1][2] = y[9];
3024         p->x[2][2] = x[10];
3025         p->y[2][2] = y[10];
3026         p->x[2][1] = x[11];
3027         p->y[2][1] = y[11];
3028         for (j = 0; j < nComps; ++j) {
3029           p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
3030           p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
3031           p->color[1][1].c[j] = c[0][j];
3032           p->color[1][0].c[j] = c[1][j];
3033         }
3034         break;
3035       }
3036     }
3037     ++nPatchesA;
3038     bitBuf->flushBits();
3039   }
3040   delete bitBuf;
3041
3042   if (typeA == 6) {
3043     for (i = 0; i < nPatchesA; ++i) {
3044       p = &patchesA[i];
3045       p->x[1][1] = (-4 * p->x[0][0]
3046                     +6 * (p->x[0][1] + p->x[1][0])
3047                     -2 * (p->x[0][3] + p->x[3][0])
3048                     +3 * (p->x[3][1] + p->x[1][3])
3049                     - p->x[3][3]) / 9;
3050       p->y[1][1] = (-4 * p->y[0][0]
3051                     +6 * (p->y[0][1] + p->y[1][0])
3052                     -2 * (p->y[0][3] + p->y[3][0])
3053                     +3 * (p->y[3][1] + p->y[1][3])
3054                     - p->y[3][3]) / 9;
3055       p->x[1][2] = (-4 * p->x[0][3]
3056                     +6 * (p->x[0][2] + p->x[1][3])
3057                     -2 * (p->x[0][0] + p->x[3][3])
3058                     +3 * (p->x[3][2] + p->x[1][0])
3059                     - p->x[3][0]) / 9;
3060       p->y[1][2] = (-4 * p->y[0][3]
3061                     +6 * (p->y[0][2] + p->y[1][3])
3062                     -2 * (p->y[0][0] + p->y[3][3])
3063                     +3 * (p->y[3][2] + p->y[1][0])
3064                     - p->y[3][0]) / 9;
3065       p->x[2][1] = (-4 * p->x[3][0]
3066                     +6 * (p->x[3][1] + p->x[2][0])
3067                     -2 * (p->x[3][3] + p->x[0][0])
3068                     +3 * (p->x[0][1] + p->x[2][3])
3069                     - p->x[0][3]) / 9;
3070       p->y[2][1] = (-4 * p->y[3][0]
3071                     +6 * (p->y[3][1] + p->y[2][0])
3072                     -2 * (p->y[3][3] + p->y[0][0])
3073                     +3 * (p->y[0][1] + p->y[2][3])
3074                     - p->y[0][3]) / 9;
3075       p->x[2][2] = (-4 * p->x[3][3]
3076                     +6 * (p->x[3][2] + p->x[2][3])
3077                     -2 * (p->x[3][0] + p->x[0][3])
3078                     +3 * (p->x[0][2] + p->x[2][0])
3079                     - p->x[0][0]) / 9;
3080       p->y[2][2] = (-4 * p->y[3][3]
3081                     +6 * (p->y[3][2] + p->y[2][3])
3082                     -2 * (p->y[3][0] + p->y[0][3])
3083                     +3 * (p->y[0][2] + p->y[2][0])
3084                     - p->y[0][0]) / 9;
3085     }
3086   }
3087
3088   shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA,
3089                                     funcsA, nFuncsA);
3090   if (!shading->init(dict)) {
3091     delete shading;
3092     return NULL;
3093   }
3094   return shading;
3095
3096  err2:
3097   obj1.free();
3098  err1:
3099   return NULL;
3100 }
3101
3102 GfxShading *GfxPatchMeshShading::copy() {
3103   return new GfxPatchMeshShading(this);
3104 }
3105
3106 //------------------------------------------------------------------------
3107 // GfxImageColorMap
3108 //------------------------------------------------------------------------
3109
3110 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
3111                                    GfxColorSpace *colorSpaceA) {
3112   GfxIndexedColorSpace *indexedCS;
3113   GfxSeparationColorSpace *sepCS;
3114   int maxPixel, indexHigh;
3115   int maxPixelForAlloc;
3116   Guchar *lookup2;
3117   Function *sepFunc;
3118   Object obj;
3119   double x[gfxColorMaxComps];
3120   double y[gfxColorMaxComps];
3121   int i, j, k;
3122
3123   ok = gTrue;
3124
3125   // bits per component and color space
3126   bits = bitsA;
3127   maxPixel = (1 << bits) - 1;
3128   maxPixelForAlloc = (1 << (bits>8?bits:8));
3129   colorSpace = colorSpaceA;
3130
3131   // get decode map
3132   if (decode->isNull()) {
3133     nComps = colorSpace->getNComps();
3134     colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
3135   } else if (decode->isArray()) {
3136     nComps = decode->arrayGetLength() / 2;
3137     if (nComps != colorSpace->getNComps()) {
3138       goto err1;
3139     }
3140     for (i = 0; i < nComps; ++i) {
3141       decode->arrayGet(2*i, &obj);
3142       if (!obj.isNum()) {
3143         goto err2;
3144       }
3145       decodeLow[i] = obj.getNum();
3146       obj.free();
3147       decode->arrayGet(2*i+1, &obj);
3148       if (!obj.isNum()) {
3149         goto err2;
3150       }
3151       decodeRange[i] = obj.getNum() - decodeLow[i];
3152       obj.free();
3153     }
3154   } else {
3155     goto err1;
3156   }
3157
3158   // Construct a lookup table -- this stores pre-computed decoded
3159   // values for each component, i.e., the result of applying the
3160   // decode mapping to each possible image pixel component value.
3161   //
3162   // Optimization: for Indexed and Separation color spaces (which have
3163   // only one component), we store color values in the lookup table
3164   // rather than component values.
3165   for (k = 0; k < gfxColorMaxComps; ++k) {
3166     lookup[k] = NULL;
3167   }
3168   colorSpace2 = NULL;
3169   nComps2 = 0;
3170   if (colorSpace->getMode() == csIndexed) {
3171     // Note that indexHigh may not be the same as maxPixel --
3172     // Distiller will remove unused palette entries, resulting in
3173     // indexHigh < maxPixel.
3174     indexedCS = (GfxIndexedColorSpace *)colorSpace;
3175     colorSpace2 = indexedCS->getBase();
3176     indexHigh = indexedCS->getIndexHigh();
3177     nComps2 = colorSpace2->getNComps();
3178     lookup2 = indexedCS->getLookup();
3179     colorSpace2->getDefaultRanges(x, y, indexHigh);
3180     for (k = 0; k < nComps2; ++k) {
3181       lookup[k] = (GfxColorComp *)gmallocn(maxPixelForAlloc + 1,
3182                                            sizeof(GfxColorComp));
3183       for (i = 0; i <= maxPixel; ++i) {
3184         j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
3185         if (j < 0) {
3186           j = 0;
3187         } else if (j > indexHigh) {
3188           j = indexHigh;
3189         }
3190         lookup[k][i] =
3191             dblToCol(x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]);
3192       }
3193     }
3194   } else if (colorSpace->getMode() == csSeparation) {
3195     sepCS = (GfxSeparationColorSpace *)colorSpace;
3196     colorSpace2 = sepCS->getAlt();
3197     nComps2 = colorSpace2->getNComps();
3198     sepFunc = sepCS->getFunc();
3199     for (k = 0; k < nComps2; ++k) {
3200       lookup[k] = (GfxColorComp *)gmallocn(maxPixelForAlloc + 1,
3201                                            sizeof(GfxColorComp));
3202       for (i = 0; i <= maxPixel; ++i) {
3203         x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
3204         sepFunc->transform(x, y);
3205         lookup[k][i] = dblToCol(y[k]);
3206       }
3207     }
3208   } else {
3209     for (k = 0; k < nComps; ++k) {
3210       lookup[k] = (GfxColorComp *)gmallocn(maxPixelForAlloc + 1,
3211                                            sizeof(GfxColorComp));
3212       for (i = 0; i <= maxPixel; ++i) {
3213         lookup[k][i] = dblToCol(decodeLow[k] +
3214                                 (i * decodeRange[k]) / maxPixel);
3215       }
3216     }
3217   }
3218
3219   return;
3220
3221  err2:
3222   obj.free();
3223  err1:
3224   ok = gFalse;
3225 }
3226
3227 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
3228   int n, i, k;
3229
3230   colorSpace = colorMap->colorSpace->copy();
3231   bits = colorMap->bits;
3232   nComps = colorMap->nComps;
3233   nComps2 = colorMap->nComps2;
3234   colorSpace2 = NULL;
3235   for (k = 0; k < gfxColorMaxComps; ++k) {
3236     lookup[k] = NULL;
3237   }
3238   n = 1 << bits;
3239   if (colorSpace->getMode() == csIndexed) {
3240     colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
3241     for (k = 0; k < nComps2; ++k) {
3242       lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
3243       memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
3244     }
3245   } else if (colorSpace->getMode() == csSeparation) {
3246     colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
3247     for (k = 0; k < nComps2; ++k) {
3248       lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
3249       memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
3250     }
3251   } else {
3252     for (k = 0; k < nComps; ++k) {
3253       lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
3254       memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
3255     }
3256   }
3257   for (i = 0; i < nComps; ++i) {
3258     decodeLow[i] = colorMap->decodeLow[i];
3259     decodeRange[i] = colorMap->decodeRange[i];
3260   }
3261   ok = gTrue;
3262 }
3263
3264 GfxImageColorMap::~GfxImageColorMap() {
3265   int i;
3266
3267   delete colorSpace;
3268   for (i = 0; i < gfxColorMaxComps; ++i) {
3269     gfree(lookup[i]);
3270   }
3271 }
3272
3273 void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) {
3274   GfxColor color;
3275   int i;
3276
3277   if (colorSpace2) {
3278     for (i = 0; i < nComps2; ++i) {
3279       color.c[i] = lookup[i][x[0]];
3280     }
3281     colorSpace2->getGray(&color, gray);
3282   } else {
3283     for (i = 0; i < nComps; ++i) {
3284       color.c[i] = lookup[i][x[i]];
3285     }
3286     colorSpace->getGray(&color, gray);
3287   }
3288 }
3289
3290 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
3291   GfxColor color;
3292   int i;
3293
3294   if (colorSpace2) {
3295     for (i = 0; i < nComps2; ++i) {
3296       color.c[i] = lookup[i][x[0]];
3297     }
3298     colorSpace2->getRGB(&color, rgb);
3299   } else {
3300     for (i = 0; i < nComps; ++i) {
3301       color.c[i] = lookup[i][x[i]];
3302     }
3303     colorSpace->getRGB(&color, rgb);
3304   }
3305 }
3306
3307 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
3308   GfxColor color;
3309   int i;
3310
3311   if (colorSpace2) {
3312     for (i = 0; i < nComps2; ++i) {
3313       color.c[i] = lookup[i][x[0]];
3314     }
3315     colorSpace2->getCMYK(&color, cmyk);
3316   } else {
3317     for (i = 0; i < nComps; ++i) {
3318       color.c[i] = lookup[i][x[i]];
3319     }
3320     colorSpace->getCMYK(&color, cmyk);
3321   }
3322 }
3323
3324 void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
3325   int maxPixel, i;
3326
3327   maxPixel = (1 << bits) - 1;
3328   for (i = 0; i < nComps; ++i) {
3329     color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel);
3330   }
3331 }
3332
3333 //------------------------------------------------------------------------
3334 // GfxSubpath and GfxPath
3335 //------------------------------------------------------------------------
3336
3337 GfxSubpath::GfxSubpath(double x1, double y1) {
3338   size = 16;
3339   x = (double *)gmallocn(size, sizeof(double));
3340   y = (double *)gmallocn(size, sizeof(double));
3341   curve = (GBool *)gmallocn(size, sizeof(GBool));
3342   n = 1;
3343   x[0] = x1;
3344   y[0] = y1;
3345   curve[0] = gFalse;
3346   closed = gFalse;
3347 }
3348
3349 GfxSubpath::~GfxSubpath() {
3350   gfree(x);
3351   gfree(y);
3352   gfree(curve);
3353 }
3354
3355 // Used for copy().
3356 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
3357   size = subpath->size;
3358   n = subpath->n;
3359   x = (double *)gmallocn(size, sizeof(double));
3360   y = (double *)gmallocn(size, sizeof(double));
3361   curve = (GBool *)gmallocn(size, sizeof(GBool));
3362   memcpy(x, subpath->x, n * sizeof(double));
3363   memcpy(y, subpath->y, n * sizeof(double));
3364   memcpy(curve, subpath->curve, n * sizeof(GBool));
3365   closed = subpath->closed;
3366 }
3367
3368 void GfxSubpath::lineTo(double x1, double y1) {
3369   if (n >= size) {
3370     size += 16;
3371     x = (double *)greallocn(x, size, sizeof(double));
3372     y = (double *)greallocn(y, size, sizeof(double));
3373     curve = (GBool *)greallocn(curve, size, sizeof(GBool));
3374   }
3375   x[n] = x1;
3376   y[n] = y1;
3377   curve[n] = gFalse;
3378   ++n;
3379 }
3380
3381 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
3382                          double x3, double y3) {
3383   if (n+3 > size) {
3384     size += 16;
3385     x = (double *)greallocn(x, size, sizeof(double));
3386     y = (double *)greallocn(y, size, sizeof(double));
3387     curve = (GBool *)greallocn(curve, size, sizeof(GBool));
3388   }
3389   x[n] = x1;
3390   y[n] = y1;
3391   x[n+1] = x2;
3392   y[n+1] = y2;
3393   x[n+2] = x3;
3394   y[n+2] = y3;
3395   curve[n] = curve[n+1] = gTrue;
3396   curve[n+2] = gFalse;
3397   n += 3;
3398 }
3399
3400 void GfxSubpath::close() {
3401   if (x[n-1] != x[0] || y[n-1] != y[0]) {
3402     lineTo(x[0], y[0]);
3403   }
3404   closed = gTrue;
3405 }
3406
3407 void GfxSubpath::offset(double dx, double dy) {
3408   int i;
3409
3410   for (i = 0; i < n; ++i) {
3411     x[i] += dx;
3412     y[i] += dy;
3413   }
3414 }
3415
3416 GfxPath::GfxPath() {
3417   justMoved = gFalse;
3418   size = 16;
3419   n = 0;
3420   firstX = firstY = 0;
3421   subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
3422 }
3423
3424 GfxPath::~GfxPath() {
3425   int i;
3426
3427   for (i = 0; i < n; ++i)
3428     delete subpaths[i];
3429   gfree(subpaths);
3430 }
3431
3432 // Used for copy().
3433 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
3434                  GfxSubpath **subpaths1, int n1, int size1) {
3435   int i;
3436
3437   justMoved = justMoved1;
3438   firstX = firstX1;
3439   firstY = firstY1;
3440   size = size1;
3441   n = n1;
3442   subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
3443   for (i = 0; i < n; ++i)
3444     subpaths[i] = subpaths1[i]->copy();
3445 }
3446
3447 void GfxPath::moveTo(double x, double y) {
3448   justMoved = gTrue;
3449   firstX = x;
3450   firstY = y;
3451 }
3452
3453 void GfxPath::lineTo(double x, double y) {
3454   if (justMoved) {
3455     if (n >= size) {
3456       size += 16;
3457       subpaths = (GfxSubpath **)
3458                    greallocn(subpaths, size, sizeof(GfxSubpath *));
3459     }
3460     subpaths[n] = new GfxSubpath(firstX, firstY);
3461     ++n;
3462     justMoved = gFalse;
3463   }
3464   subpaths[n-1]->lineTo(x, y);
3465 }
3466
3467 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
3468              double x3, double y3) {
3469   if (justMoved) {
3470     if (n >= size) {
3471       size += 16;
3472       subpaths = (GfxSubpath **)
3473                    greallocn(subpaths, size, sizeof(GfxSubpath *));
3474     }
3475     subpaths[n] = new GfxSubpath(firstX, firstY);
3476     ++n;
3477     justMoved = gFalse;
3478   }
3479   subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
3480 }
3481
3482 void GfxPath::close() {
3483   // this is necessary to handle the pathological case of
3484   // moveto/closepath/clip, which defines an empty clipping region
3485   if (justMoved) {
3486     if (n >= size) {
3487       size += 16;
3488       subpaths = (GfxSubpath **)
3489                    greallocn(subpaths, size, sizeof(GfxSubpath *));
3490     }
3491     subpaths[n] = new GfxSubpath(firstX, firstY);
3492     ++n;
3493     justMoved = gFalse;
3494   }
3495   subpaths[n-1]->close();
3496 }
3497
3498 void GfxPath::append(GfxPath *path) {
3499   int i;
3500
3501   if (n + path->n > size) {
3502     size = n + path->n;
3503     subpaths = (GfxSubpath **)
3504                  greallocn(subpaths, size, sizeof(GfxSubpath *));
3505   }
3506   for (i = 0; i < path->n; ++i) {
3507     subpaths[n++] = path->subpaths[i]->copy();
3508   }
3509   justMoved = gFalse;
3510 }
3511
3512 void GfxPath::offset(double dx, double dy) {
3513   int i;
3514
3515   for (i = 0; i < n; ++i) {
3516     subpaths[i]->offset(dx, dy);
3517   }
3518 }
3519
3520 //------------------------------------------------------------------------
3521 // GfxState
3522 //------------------------------------------------------------------------
3523
3524 GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
3525                    int rotateA, GBool upsideDown) {
3526   double kx, ky;
3527
3528   rotate = rotateA;
3529   px1 = pageBox->x1;
3530   py1 = pageBox->y1;
3531   px2 = pageBox->x2;
3532   py2 = pageBox->y2;
3533   kx = hDPI / 72.0;
3534   ky = vDPI / 72.0;
3535   if (rotate == 90) {
3536     ctm[0] = 0;
3537     ctm[1] = upsideDown ? ky : -ky;
3538     ctm[2] = kx;
3539     ctm[3] = 0;
3540     ctm[4] = -kx * py1;
3541     ctm[5] = ky * (upsideDown ? -px1 : px2);
3542     pageWidth = kx * (py2 - py1);
3543     pageHeight = ky * (px2 - px1);
3544   } else if (rotate == 180) {
3545     ctm[0] = -kx;
3546     ctm[1] = 0;
3547     ctm[2] = 0;
3548     ctm[3] = upsideDown ? ky : -ky;
3549     ctm[4] = kx * px2;
3550     ctm[5] = ky * (upsideDown ? -py1 : py2);
3551     pageWidth = kx * (px2 - px1);
3552     pageHeight = ky * (py2 - py1);
3553   } else if (rotate == 270) {
3554     ctm[0] = 0;
3555     ctm[1] = upsideDown ? -ky : ky;
3556     ctm[2] = -kx;
3557     ctm[3] = 0;
3558     ctm[4] = kx * py2;
3559     ctm[5] = ky * (upsideDown ? px2 : -px1);
3560     pageWidth = kx * (py2 - py1);
3561     pageHeight = ky * (px2 - px1);
3562   } else {
3563     ctm[0] = kx;
3564     ctm[1] = 0;
3565     ctm[2] = 0;
3566     ctm[3] = upsideDown ? -ky : ky;
3567     ctm[4] = -kx * px1;
3568     ctm[5] = ky * (upsideDown ? py2 : -py1);
3569     pageWidth = kx * (px2 - px1);
3570     pageHeight = ky * (py2 - py1);
3571   }
3572
3573   fillColorSpace = new GfxDeviceGrayColorSpace();
3574   strokeColorSpace = new GfxDeviceGrayColorSpace();
3575   fillColor.c[0] = 0;
3576   strokeColor.c[0] = 0;
3577   fillPattern = NULL;
3578   strokePattern = NULL;
3579   blendMode = gfxBlendNormal;
3580   fillOpacity = 1;
3581   strokeOpacity = 1;
3582   fillOverprint = gFalse;
3583   strokeOverprint = gFalse;
3584
3585   lineWidth = 1;
3586   lineDash = NULL;
3587   lineDashLength = 0;
3588   lineDashStart = 0;
3589   flatness = 1;
3590   lineJoin = 0;
3591   lineCap = 0;
3592   miterLimit = 10;
3593
3594   font = NULL;
3595   fontSize = 0;
3596   textMat[0] = 1; textMat[1] = 0;
3597   textMat[2] = 0; textMat[3] = 1;
3598   textMat[4] = 0; textMat[5] = 0;
3599   charSpace = 0;
3600   wordSpace = 0;
3601   horizScaling = 1;
3602   leading = 0;
3603   rise = 0;
3604   render = 0;
3605
3606   path = new GfxPath();
3607   curX = curY = 0;
3608   lineX = lineY = 0;
3609
3610   clipXMin = 0;
3611   clipYMin = 0;
3612   clipXMax = pageWidth;
3613   clipYMax = pageHeight;
3614
3615   saved = NULL;
3616 }
3617
3618 GfxState::~GfxState() {
3619   if (fillColorSpace) {
3620     delete fillColorSpace;
3621   }
3622   if (strokeColorSpace) {
3623     delete strokeColorSpace;
3624   }
3625   if (fillPattern) {
3626     delete fillPattern;
3627   }
3628   if (strokePattern) {
3629     delete strokePattern;
3630   }
3631   gfree(lineDash);
3632   if (path) {
3633     // this gets set to NULL by restore()
3634     delete path;
3635   }
3636   if (saved) {
3637     delete saved;
3638   }
3639 }
3640
3641 // Used for copy();
3642 GfxState::GfxState(GfxState *state) {
3643   memcpy(this, state, sizeof(GfxState));
3644   if (fillColorSpace) {
3645     fillColorSpace = state->fillColorSpace->copy();
3646   }
3647   if (strokeColorSpace) {
3648     strokeColorSpace = state->strokeColorSpace->copy();
3649   }
3650   if (fillPattern) {
3651     fillPattern = state->fillPattern->copy();
3652   }
3653   if (strokePattern) {
3654     strokePattern = state->strokePattern->copy();
3655   }
3656   if (lineDashLength > 0) {
3657     lineDash = (double *)gmallocn(lineDashLength, sizeof(double));
3658     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
3659   }
3660   saved = NULL;
3661 }
3662
3663 void GfxState::setPath(GfxPath *pathA) {
3664   delete path;
3665   path = pathA;
3666 }
3667
3668 void GfxState::getUserClipBBox(double *xMin, double *yMin,
3669                                double *xMax, double *yMax) {
3670   double ictm[6];
3671   double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
3672
3673   // invert the CTM
3674   det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
3675   ictm[0] = ctm[3] * det;
3676   ictm[1] = -ctm[1] * det;
3677   ictm[2] = -ctm[2] * det;
3678   ictm[3] = ctm[0] * det;
3679   ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
3680   ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
3681
3682   // transform all four corners of the clip bbox; find the min and max
3683   // x and y values
3684   xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
3685   yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
3686   tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
3687   ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
3688   if (tx < xMin1) {
3689     xMin1 = tx;
3690   } else if (tx > xMax1) {
3691     xMax1 = tx;
3692   }
3693   if (ty < yMin1) {
3694     yMin1 = ty;
3695   } else if (ty > yMax1) {
3696     yMax1 = ty;
3697   }
3698   tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
3699   ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
3700   if (tx < xMin1) {
3701     xMin1 = tx;
3702   } else if (tx > xMax1) {
3703     xMax1 = tx;
3704   }
3705   if (ty < yMin1) {
3706     yMin1 = ty;
3707   } else if (ty > yMax1) {
3708     yMax1 = ty;
3709   }
3710   tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
3711   ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
3712   if (tx < xMin1) {
3713     xMin1 = tx;
3714   } else if (tx > xMax1) {
3715     xMax1 = tx;
3716   }
3717   if (ty < yMin1) {
3718     yMin1 = ty;
3719   } else if (ty > yMax1) {
3720     yMax1 = ty;
3721   }
3722
3723   *xMin = xMin1;
3724   *yMin = yMin1;
3725   *xMax = xMax1;
3726   *yMax = yMax1;
3727 }
3728
3729 double GfxState::transformWidth(double w) {
3730   double x, y;
3731
3732   x = ctm[0] + ctm[2];
3733   y = ctm[1] + ctm[3];
3734   return w * sqrt(0.5 * (x * x + y * y));
3735 }
3736
3737 double GfxState::getTransformedFontSize() {
3738   double x1, y1, x2, y2;
3739
3740   x1 = textMat[2] * fontSize;
3741   y1 = textMat[3] * fontSize;
3742   x2 = ctm[0] * x1 + ctm[2] * y1;
3743   y2 = ctm[1] * x1 + ctm[3] * y1;
3744   return sqrt(x2 * x2 + y2 * y2);
3745 }
3746
3747 void GfxState::getFontTransMat(double *m11, double *m12,
3748                                double *m21, double *m22) {
3749   *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
3750   *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
3751   *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
3752   *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
3753 }
3754
3755 void GfxState::setCTM(double a, double b, double c,
3756                       double d, double e, double f) {
3757   int i;
3758
3759   ctm[0] = a;
3760   ctm[1] = b;
3761   ctm[2] = c;
3762   ctm[3] = d;
3763   ctm[4] = e;
3764   ctm[5] = f;
3765
3766   // avoid FP exceptions on badly messed up PDF files
3767   for (i = 0; i < 6; ++i) {
3768     if (ctm[i] > 1e10) {
3769       ctm[i] = 1e10;
3770     } else if (ctm[i] < -1e10) {
3771       ctm[i] = -1e10;
3772     }
3773   }
3774 }
3775
3776 void GfxState::concatCTM(double a, double b, double c,
3777                          double d, double e, double f) {
3778   double a1 = ctm[0];
3779   double b1 = ctm[1];
3780   double c1 = ctm[2];
3781   double d1 = ctm[3];
3782   int i;
3783
3784   ctm[0] = a * a1 + b * c1;
3785   ctm[1] = a * b1 + b * d1;
3786   ctm[2] = c * a1 + d * c1;
3787   ctm[3] = c * b1 + d * d1;
3788   ctm[4] = e * a1 + f * c1 + ctm[4];
3789   ctm[5] = e * b1 + f * d1 + ctm[5];
3790
3791   // avoid FP exceptions on badly messed up PDF files
3792   for (i = 0; i < 6; ++i) {
3793     if (ctm[i] > 1e10) {
3794       ctm[i] = 1e10;
3795     } else if (ctm[i] < -1e10) {
3796       ctm[i] = -1e10;
3797     }
3798   }
3799 }
3800
3801 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
3802   if (fillColorSpace) {
3803     delete fillColorSpace;
3804   }
3805   fillColorSpace = colorSpace;
3806 }
3807
3808 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
3809   if (strokeColorSpace) {
3810     delete strokeColorSpace;
3811   }
3812   strokeColorSpace = colorSpace;
3813 }
3814
3815 void GfxState::setFillPattern(GfxPattern *pattern) {
3816   if (fillPattern) {
3817     delete fillPattern;
3818   }
3819   fillPattern = pattern;
3820 }
3821
3822 void GfxState::setStrokePattern(GfxPattern *pattern) {
3823   if (strokePattern) {
3824     delete strokePattern;
3825   }
3826   strokePattern = pattern;
3827 }
3828
3829 void GfxState::setLineDash(double *dash, int length, double start) {
3830   if (lineDash)
3831     gfree(lineDash);
3832   lineDash = dash;
3833   lineDashLength = length;
3834   lineDashStart = start;
3835 }
3836
3837 void GfxState::clearPath() {
3838   delete path;
3839   path = new GfxPath();
3840 }
3841
3842 void GfxState::clip() {
3843   double xMin, yMin, xMax, yMax, x, y;
3844   GfxSubpath *subpath;
3845   int i, j;
3846
3847   xMin = xMax = yMin = yMax = 0; // make gcc happy
3848   for (i = 0; i < path->getNumSubpaths(); ++i) {
3849     subpath = path->getSubpath(i);
3850     for (j = 0; j < subpath->getNumPoints(); ++j) {
3851       transform(subpath->getX(j), subpath->getY(j), &x, &y);
3852       if (i == 0 && j == 0) {
3853         xMin = xMax = x;
3854         yMin = yMax = y;
3855       } else {
3856         if (x < xMin) {
3857           xMin = x;
3858         } else if (x > xMax) {
3859           xMax = x;
3860         }
3861         if (y < yMin) {
3862           yMin = y;
3863         } else if (y > yMax) {
3864           yMax = y;
3865         }
3866       }
3867     }
3868   }
3869   if (xMin > clipXMin) {
3870     clipXMin = xMin;
3871   }
3872   if (yMin > clipYMin) {
3873     clipYMin = yMin;
3874   }
3875   if (xMax < clipXMax) {
3876     clipXMax = xMax;
3877   }
3878   if (yMax < clipYMax) {
3879     clipYMax = yMax;
3880   }
3881 }
3882
3883 void GfxState::textShift(double tx, double ty) {
3884   double dx, dy;
3885
3886   textTransformDelta(tx, ty, &dx, &dy);
3887   curX += dx;
3888   curY += dy;
3889 }
3890
3891 void GfxState::shift(double dx, double dy) {
3892   curX += dx;
3893   curY += dy;
3894 }
3895
3896 GfxState *GfxState::save() {
3897   GfxState *newState;
3898
3899   newState = copy();
3900   newState->saved = this;
3901   return newState;
3902 }
3903
3904 GfxState *GfxState::restore() {
3905   GfxState *oldState;
3906
3907   if (saved) {
3908     oldState = saved;
3909
3910     // these attributes aren't saved/restored by the q/Q operators
3911     oldState->path = path;
3912     oldState->curX = curX;
3913     oldState->curY = curY;
3914     oldState->lineX = lineX;
3915     oldState->lineY = lineY;
3916
3917     path = NULL;
3918     saved = NULL;
3919     delete this;
3920
3921   } else {
3922     oldState = this;
3923   }
3924
3925   return oldState;
3926 }
3927
3928 GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) {
3929   Object obj2;
3930   int i, j;
3931
3932   if (obj->isName()) {
3933     for (i = 0; i < nGfxBlendModeNames; ++i) {
3934       if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) {
3935         *mode = gfxBlendModeNames[i].mode;
3936         return gTrue;
3937       }
3938     }
3939     return gFalse;
3940   } else if (obj->isArray()) {
3941     for (i = 0; i < obj->arrayGetLength(); ++i) {
3942       obj->arrayGet(i, &obj2);
3943       if (!obj2.isName()) {
3944         obj2.free();
3945         return gFalse;
3946       }
3947       for (j = 0; j < nGfxBlendModeNames; ++j) {
3948         if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) {
3949           obj2.free();
3950           *mode = gfxBlendModeNames[j].mode;
3951           return gTrue;
3952         }
3953       }
3954       obj2.free();
3955     }
3956     *mode = gfxBlendNormal;
3957     return gTrue;
3958   } else {
3959     return gFalse;
3960   }
3961 }