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