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