b7afdae623b68e38e0ea5de23737b03d422afd82
[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 || !func->isOk()) {
916     goto err4;
917   }
918   cs = new GfxSeparationColorSpace(name, alt, func);
919   return cs;
920
921  err4:
922   if(func)
923     delete func;
924   delete alt;
925  err3:
926   delete name;
927  err2:
928   obj1.free();
929  err1:
930   return NULL;
931 }
932
933 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
934   GfxColor color2;
935
936   func->transform(color->c, color2.c);
937   alt->getGray(&color2, gray);
938 }
939
940 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
941   GfxColor color2;
942
943   func->transform(color->c, color2.c);
944   alt->getRGB(&color2, rgb);
945 }
946
947 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
948   GfxColor color2;
949
950   func->transform(color->c, color2.c);
951   alt->getCMYK(&color2, cmyk);
952 }
953
954 //------------------------------------------------------------------------
955 // GfxDeviceNColorSpace
956 //------------------------------------------------------------------------
957
958 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nComps,
959                                            GfxColorSpace *alt,
960                                            Function *func) {
961   this->nComps = nComps;
962   this->alt = alt;
963   this->func = func;
964 }
965
966 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
967   int i;
968
969   for (i = 0; i < nComps; ++i) {
970     delete names[i];
971   }
972   delete alt;
973   delete func;
974 }
975
976 GfxColorSpace *GfxDeviceNColorSpace::copy() {
977   GfxDeviceNColorSpace *cs;
978   int i;
979
980   cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
981   for (i = 0; i < nComps; ++i) {
982     cs->names[i] = names[i]->copy();
983   }
984   return cs;
985 }
986
987 //~ handle the 'None' colorant
988 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
989   GfxDeviceNColorSpace *cs;
990   int nComps;
991   GString *names[gfxColorMaxComps];
992   GfxColorSpace *alt;
993   Function *func;
994   Object obj1, obj2;
995   int i;
996
997   if (arr->getLength() != 4 && arr->getLength() != 5) {
998     error(-1, "Bad DeviceN color space");
999     goto err1;
1000   }
1001   if (!arr->get(1, &obj1)->isArray()) {
1002     error(-1, "Bad DeviceN color space (names)");
1003     goto err2;
1004   }
1005   nComps = obj1.arrayGetLength();
1006   for (i = 0; i < nComps; ++i) {
1007     if (!obj1.arrayGet(i, &obj2)->isName()) {
1008       error(-1, "Bad DeviceN color space (names)");
1009       obj2.free();
1010       goto err2;
1011     }
1012     names[i] = new GString(obj2.getName());
1013     obj2.free();
1014   }
1015   obj1.free();
1016   arr->get(2, &obj1);
1017   if (!(alt = GfxColorSpace::parse(&obj1))) {
1018     error(-1, "Bad DeviceN color space (alternate color space)");
1019     goto err3;
1020   }
1021   obj1.free();
1022   func = Function::parse(arr->get(3, &obj1));
1023   obj1.free();
1024   if (!func->isOk()) {
1025     goto err4;
1026   }
1027   cs = new GfxDeviceNColorSpace(nComps, alt, func);
1028   for (i = 0; i < nComps; ++i) {
1029     cs->names[i] = names[i];
1030   }
1031   return cs;
1032
1033  err4:
1034   delete func;
1035   delete alt;
1036  err3:
1037   for (i = 0; i < nComps; ++i) {
1038     delete names[i];
1039   }
1040  err2:
1041   obj1.free();
1042  err1:
1043   return NULL;
1044 }
1045
1046 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1047   GfxColor color2;
1048
1049   func->transform(color->c, color2.c);
1050   alt->getGray(&color2, gray);
1051 }
1052
1053 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1054   GfxColor color2;
1055
1056   func->transform(color->c, color2.c);
1057   alt->getRGB(&color2, rgb);
1058 }
1059
1060 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1061   GfxColor color2;
1062
1063   func->transform(color->c, color2.c);
1064   alt->getCMYK(&color2, cmyk);
1065 }
1066
1067 //------------------------------------------------------------------------
1068 // GfxPatternColorSpace
1069 //------------------------------------------------------------------------
1070
1071 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *under) {
1072   this->under = under;
1073 }
1074
1075 GfxPatternColorSpace::~GfxPatternColorSpace() {
1076   if (under) {
1077     delete under;
1078   }
1079 }
1080
1081 GfxColorSpace *GfxPatternColorSpace::copy() {
1082   return new GfxPatternColorSpace(under ? under->copy() :
1083                                           (GfxColorSpace *)NULL);
1084 }
1085
1086 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1087   GfxPatternColorSpace *cs;
1088   GfxColorSpace *under;
1089   Object obj1;
1090
1091   if (arr->getLength() != 1 && arr->getLength() != 2) {
1092     error(-1, "Bad Pattern color space");
1093     return NULL;
1094   }
1095   under = NULL;
1096   if (arr->getLength() == 2) {
1097     arr->get(1, &obj1);
1098     if (!(under = GfxColorSpace::parse(&obj1))) {
1099       error(-1, "Bad Pattern color space (underlying color space)");
1100       obj1.free();
1101       return NULL;
1102     }
1103     obj1.free();
1104   }
1105   cs = new GfxPatternColorSpace(under);
1106   return cs;
1107 }
1108
1109 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1110   *gray = 0;
1111 }
1112
1113 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1114   rgb->r = rgb->g = rgb->b = 0;
1115 }
1116
1117 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1118   cmyk->c = cmyk->m = cmyk->y = 0;
1119   cmyk->k = 1;
1120 }
1121
1122 //------------------------------------------------------------------------
1123 // Pattern
1124 //------------------------------------------------------------------------
1125
1126 GfxPattern::GfxPattern(int type) {
1127   this->type = type;
1128 }
1129
1130 GfxPattern::~GfxPattern() {
1131 }
1132
1133 GfxPattern *GfxPattern::parse(Object *obj) {
1134   GfxPattern *pattern;
1135   Dict *dict;
1136   Object obj1;
1137
1138   pattern = NULL;
1139   if (obj->isStream()) {
1140     dict = obj->streamGetDict();
1141     dict->lookup("PatternType", &obj1);
1142     if (obj1.isInt() && obj1.getInt() == 1) {
1143       pattern = new GfxTilingPattern(dict, obj);
1144     }
1145     obj1.free();
1146   }
1147   return pattern;
1148 }
1149
1150 //------------------------------------------------------------------------
1151 // GfxTilingPattern
1152 //------------------------------------------------------------------------
1153
1154 GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
1155   GfxPattern(1)
1156 {
1157   Object obj1, obj2;
1158   int i;
1159
1160   if (streamDict->lookup("PaintType", &obj1)->isInt()) {
1161     paintType = obj1.getInt();
1162   } else {
1163     paintType = 1;
1164     error(-1, "Invalid or missing PaintType in pattern");
1165   }
1166   obj1.free();
1167   if (streamDict->lookup("TilingType", &obj1)->isInt()) {
1168     tilingType = obj1.getInt();
1169   } else {
1170     tilingType = 1;
1171     error(-1, "Invalid or missing TilingType in pattern");
1172   }
1173   obj1.free();
1174   bbox[0] = bbox[1] = 0;
1175   bbox[2] = bbox[3] = 1;
1176   if (streamDict->lookup("BBox", &obj1)->isArray() &&
1177       obj1.arrayGetLength() == 4) {
1178     for (i = 0; i < 4; ++i) {
1179       if (obj1.arrayGet(i, &obj2)->isNum()) {
1180         bbox[i] = obj2.getNum();
1181       }
1182       obj2.free();
1183     }
1184   } else {
1185     error(-1, "Invalid or missing BBox in pattern");
1186   }
1187   obj1.free();
1188   if (streamDict->lookup("XStep", &obj1)->isNum()) {
1189     xStep = obj1.getNum();
1190   } else {
1191     xStep = 1;
1192     error(-1, "Invalid or missing XStep in pattern");
1193   }
1194   obj1.free();
1195   if (streamDict->lookup("YStep", &obj1)->isNum()) {
1196     yStep = obj1.getNum();
1197   } else {
1198     yStep = 1;
1199     error(-1, "Invalid or missing YStep in pattern");
1200   }
1201   obj1.free();
1202   if (!streamDict->lookup("Resources", &resDict)->isDict()) {
1203     resDict.free();
1204     resDict.initNull();
1205     error(-1, "Invalid or missing Resources in pattern");
1206   }
1207   matrix[0] = 1; matrix[1] = 0;
1208   matrix[2] = 0; matrix[3] = 1;
1209   matrix[4] = 0; matrix[5] = 0;
1210   if (streamDict->lookup("Matrix", &obj1)->isArray() &&
1211       obj1.arrayGetLength() == 6) {
1212     for (i = 0; i < 6; ++i) {
1213       if (obj1.arrayGet(i, &obj2)->isNum()) {
1214         matrix[i] = obj2.getNum();
1215       }
1216       obj2.free();
1217     }
1218   }
1219   obj1.free();
1220   stream->copy(&contentStream);
1221 }
1222
1223 GfxTilingPattern::~GfxTilingPattern() {
1224   resDict.free();
1225   contentStream.free();
1226 }
1227
1228 GfxPattern *GfxTilingPattern::copy() {
1229   return new GfxTilingPattern(this);
1230 }
1231
1232 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
1233   GfxPattern(1)
1234 {
1235   memcpy(this, pat, sizeof(GfxTilingPattern));
1236   pat->resDict.copy(&resDict);
1237   pat->contentStream.copy(&contentStream);
1238 }
1239
1240 //------------------------------------------------------------------------
1241 // Function
1242 //------------------------------------------------------------------------
1243
1244 Function::Function() {
1245 }
1246
1247 Function::~Function() {
1248 }
1249
1250 Function *Function::parse(Object *funcObj) {
1251   Function *func;
1252   Dict *dict;
1253   int funcType;
1254   Object obj1;
1255
1256   if (funcObj->isStream()) {
1257     dict = funcObj->streamGetDict();
1258   } else if (funcObj->isDict()) {
1259     dict = funcObj->getDict();
1260   } else {
1261     error(-1, "Expected function dictionary or stream");
1262     return NULL;
1263   }
1264
1265   if (!dict->lookup("FunctionType", &obj1)->isInt()) {
1266     error(-1, "Function type is missing or wrong type");
1267     obj1.free();
1268     return NULL;
1269   }
1270   funcType = obj1.getInt();
1271   obj1.free();
1272
1273   if (funcType == 0) {
1274     func = new SampledFunction(funcObj, dict);
1275   } else if (funcType == 2) {
1276     func = new ExponentialFunction(funcObj, dict);
1277   } else {
1278     error(-1, "Unimplemented function type");
1279     return NULL;
1280   }
1281   if (!func->isOk()) {
1282     delete func;
1283     return NULL;
1284   }
1285
1286   return func;
1287 }
1288
1289 GBool Function::init(Dict *dict) {
1290   Object obj1, obj2;
1291   int i;
1292
1293   //----- Domain
1294   if (!dict->lookup("Domain", &obj1)->isArray()) {
1295     error(-1, "Function is missing domain");
1296     goto err2;
1297   }
1298   m = obj1.arrayGetLength() / 2;
1299   if (m > funcMaxInputs) {
1300     error(-1, "Functions with more than %d inputs are unsupported",
1301           funcMaxInputs);
1302     goto err2;
1303   }
1304   for (i = 0; i < m; ++i) {
1305     obj1.arrayGet(2*i, &obj2);
1306     if (!obj2.isNum()) {
1307       error(-1, "Illegal value in function domain array");
1308       goto err1;
1309     }
1310     domain[i][0] = obj2.getNum();
1311     obj2.free();
1312     obj1.arrayGet(2*i+1, &obj2);
1313     if (!obj2.isNum()) {
1314       error(-1, "Illegal value in function domain array");
1315       goto err1;
1316     }
1317     domain[i][1] = obj2.getNum();
1318     obj2.free();
1319   }
1320   obj1.free();
1321
1322   //----- Range
1323   hasRange = gFalse;
1324   n = 0;
1325   if (dict->lookup("Range", &obj1)->isArray()) {
1326     hasRange = gTrue;
1327     n = obj1.arrayGetLength() / 2;
1328     if (n > funcMaxOutputs) {
1329       error(-1, "Functions with more than %d outputs are unsupported",
1330             funcMaxOutputs);
1331       goto err2;
1332     }
1333     for (i = 0; i < n; ++i) {
1334       obj1.arrayGet(2*i, &obj2);
1335       if (!obj2.isNum()) {
1336         error(-1, "Illegal value in function range array");
1337         goto err1;
1338       }
1339       range[i][0] = obj2.getNum();
1340       obj2.free();
1341       obj1.arrayGet(2*i+1, &obj2);
1342       if (!obj2.isNum()) {
1343         error(-1, "Illegal value in function range array");
1344         goto err1;
1345       }
1346       range[i][1] = obj2.getNum();
1347       obj2.free();
1348     }
1349     obj1.free();
1350   }
1351
1352   return gTrue;
1353
1354  err1:
1355   obj2.free();
1356  err2:
1357   obj1.free();
1358   return gFalse;
1359 }
1360
1361 //------------------------------------------------------------------------
1362 // SampledFunction
1363 //------------------------------------------------------------------------
1364
1365 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
1366   Stream *str;
1367   int nSamples, sampleBits;
1368   double sampleMul;
1369   Object obj1, obj2;
1370   Guint buf, bitMask;
1371   int bits;
1372   int s;
1373   int i;
1374
1375   samples = NULL;
1376   ok = gFalse;
1377
1378   //----- initialize the generic stuff
1379   if (!init(dict)) {
1380     goto err1;
1381   }
1382   if (!hasRange) {
1383     error(-1, "Type 0 function is missing range");
1384     goto err1;
1385   }
1386
1387   //----- get the stream
1388   if (!funcObj->isStream()) {
1389     error(-1, "Type 0 function isn't a stream");
1390     goto err1;
1391   }
1392   str = funcObj->getStream();
1393
1394   //----- Size
1395   if (!dict->lookup("Size", &obj1)->isArray() ||
1396       obj1.arrayGetLength() != m) {
1397     error(-1, "Function has missing or invalid size array");
1398     goto err2;
1399   }
1400   for (i = 0; i < m; ++i) {
1401     obj1.arrayGet(i, &obj2);
1402     if (!obj2.isInt()) {
1403       error(-1, "Illegal value in function size array");
1404       goto err3;
1405     }
1406     sampleSize[i] = obj2.getInt();
1407     obj2.free();
1408   }
1409   obj1.free();
1410
1411   //----- BitsPerSample
1412   if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
1413     error(-1, "Function has missing or invalid BitsPerSample");
1414     goto err2;
1415   }
1416   sampleBits = obj1.getInt();
1417   sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
1418   obj1.free();
1419
1420   //----- Encode
1421   if (dict->lookup("Encode", &obj1)->isArray() &&
1422       obj1.arrayGetLength() == 2*m) {
1423     for (i = 0; i < m; ++i) {
1424       obj1.arrayGet(2*i, &obj2);
1425       if (!obj2.isNum()) {
1426         error(-1, "Illegal value in function encode array");
1427         goto err3;
1428       }
1429       encode[i][0] = obj2.getNum();
1430       obj2.free();
1431       obj1.arrayGet(2*i+1, &obj2);
1432       if (!obj2.isNum()) {
1433         error(-1, "Illegal value in function encode array");
1434         goto err3;
1435       }
1436       encode[i][1] = obj2.getNum();
1437       obj2.free();
1438     }
1439   } else {
1440     for (i = 0; i < m; ++i) {
1441       encode[i][0] = 0;
1442       encode[i][1] = sampleSize[i] - 1;
1443     }
1444   }
1445   obj1.free();
1446
1447   //----- Decode
1448   if (dict->lookup("Decode", &obj1)->isArray() &&
1449       obj1.arrayGetLength() == 2*n) {
1450     for (i = 0; i < n; ++i) {
1451       obj1.arrayGet(2*i, &obj2);
1452       if (!obj2.isNum()) {
1453         error(-1, "Illegal value in function decode array");
1454         goto err3;
1455       }
1456       decode[i][0] = obj2.getNum();
1457       obj2.free();
1458       obj1.arrayGet(2*i+1, &obj2);
1459       if (!obj2.isNum()) {
1460         error(-1, "Illegal value in function decode array");
1461         goto err3;
1462       }
1463       decode[i][1] = obj2.getNum();
1464       obj2.free();
1465     }
1466   } else {
1467     for (i = 0; i < n; ++i) {
1468       decode[i][0] = range[i][0];
1469       decode[i][1] = range[i][1];
1470     }
1471   }
1472   obj1.free();
1473
1474   //----- samples
1475   nSamples = n;
1476   for (i = 0; i < m; ++i)
1477     nSamples *= sampleSize[i];
1478   samples = (double *)gmalloc(nSamples * sizeof(double));
1479   buf = 0;
1480   bits = 0;
1481   bitMask = (1 << sampleBits) - 1;
1482   str->reset();
1483   for (i = 0; i < nSamples; ++i) {
1484     if (sampleBits == 8) {
1485       s = str->getChar();
1486     } else if (sampleBits == 16) {
1487       s = str->getChar();
1488       s = (s << 8) + str->getChar();
1489     } else if (sampleBits == 32) {
1490       s = str->getChar();
1491       s = (s << 8) + str->getChar();
1492       s = (s << 8) + str->getChar();
1493       s = (s << 8) + str->getChar();
1494     } else {
1495       while (bits < sampleBits) {
1496         buf = (buf << 8) | (str->getChar() & 0xff);
1497         bits += 8;
1498       }
1499       s = (buf >> (bits - sampleBits)) & bitMask;
1500       bits -= sampleBits;
1501     }
1502     samples[i] = (double)s * sampleMul;
1503   }
1504   str->close();
1505
1506   ok = gTrue;
1507   return;
1508
1509  err3:
1510   obj2.free();
1511  err2:
1512   obj1.free();
1513  err1:
1514   return;
1515 }
1516
1517 SampledFunction::~SampledFunction() {
1518   if (samples) {
1519     gfree(samples);
1520   }
1521 }
1522
1523 SampledFunction::SampledFunction(SampledFunction *func) {
1524   int nSamples, i;
1525
1526   memcpy(this, func, sizeof(SampledFunction));
1527
1528   nSamples = n;
1529   for (i = 0; i < m; ++i) {
1530     nSamples *= sampleSize[i];
1531   }
1532   samples = (double *)gmalloc(nSamples * sizeof(double));
1533   memcpy(samples, func->samples, nSamples * sizeof(double));
1534 }
1535
1536 void SampledFunction::transform(double *in, double *out) {
1537   double e[4];
1538   double s;
1539   double x0, x1;
1540   int e0, e1;
1541   double efrac;
1542   int i;
1543
1544   // map input values into sample array
1545   for (i = 0; i < m; ++i) {
1546     e[i] = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
1547            (encode[i][1] - encode[i][0]) + encode[i][0];
1548     if (e[i] < 0) {
1549       e[i] = 0;
1550     } else if (e[i] > sampleSize[i] - 1) {
1551       e[i] = sampleSize[i] - 1;
1552     }
1553   }
1554
1555   for (i = 0; i < n; ++i) {
1556
1557     // m-linear interpolation
1558     // (only m=1 is currently supported)
1559     e0 = (int)floor(e[0]);
1560     e1 = (int)ceil(e[0]);
1561     efrac = e[0] - e0;
1562     x0 = samples[e0 * n + i];
1563     x1 = samples[e1 * n + i];
1564     s = (1 - efrac) * x0 + efrac * x1;
1565
1566     // map output values to range
1567     out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0];
1568     if (out[i] < range[i][0]) {
1569       out[i] = range[i][0];
1570     } else if (out[i] > range[i][1]) {
1571       out[i] = range[i][1];
1572     }
1573   }
1574 }
1575
1576 //------------------------------------------------------------------------
1577 // ExponentialFunction
1578 //------------------------------------------------------------------------
1579
1580 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
1581   Object obj1, obj2;
1582   GBool hasN;
1583   int i;
1584
1585   ok = gFalse;
1586   hasN = gFalse;
1587
1588   //----- initialize the generic stuff
1589   if (!init(dict)) {
1590     goto err1;
1591   }
1592   if (m != 1) {
1593     error(-1, "Exponential function with more than one input");
1594     goto err1;
1595   }
1596
1597   //----- default values
1598   for (i = 0; i < funcMaxOutputs; ++i) {
1599     c0[i] = 0;
1600     c1[i] = 1;
1601   }
1602
1603   //----- C0
1604   if (dict->lookup("C0", &obj1)->isArray()) {
1605     if (!hasN) {
1606       n = obj1.arrayGetLength();
1607     } else if (obj1.arrayGetLength() != n) {
1608       error(-1, "Function's C0 array is wrong length");
1609       goto err2;
1610     }
1611     for (i = 0; i < n; ++i) {
1612       obj1.arrayGet(i, &obj2);
1613       if (!obj2.isNum()) {
1614         error(-1, "Illegal value in function C0 array");
1615         goto err3;
1616       }
1617       c0[i] = obj2.getNum();
1618       obj2.free();
1619     }
1620     obj1.free();
1621   }
1622
1623   //----- C1
1624   if (dict->lookup("C1", &obj1)->isArray()) {
1625     if (!hasN) {
1626       n = obj1.arrayGetLength();
1627     } else if (obj1.arrayGetLength() != n) {
1628       error(-1, "Function's C1 array is wrong length");
1629       goto err2;
1630     }
1631     for (i = 0; i < n; ++i) {
1632       obj1.arrayGet(i, &obj2);
1633       if (!obj2.isNum()) {
1634         error(-1, "Illegal value in function C1 array");
1635         goto err3;
1636       }
1637       c1[i] = obj2.getNum();
1638       obj2.free();
1639     }
1640     obj1.free();
1641   }
1642
1643   //----- N (exponent)
1644   if (!dict->lookup("N", &obj1)->isNum()) {
1645     error(-1, "Function has missing or invalid N");
1646     goto err2;
1647   }
1648   e = obj1.getNum();
1649   obj1.free();
1650
1651   ok = gTrue;
1652   return;
1653
1654  err3:
1655   obj2.free();
1656  err2:
1657   obj1.free();
1658  err1:
1659   return;
1660 }
1661
1662 ExponentialFunction::~ExponentialFunction() {
1663 }
1664
1665 ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
1666   memcpy(this, func, sizeof(ExponentialFunction));
1667 }
1668
1669 void ExponentialFunction::transform(double *in, double *out) {
1670   double x;
1671   int i;
1672
1673   if (in[0] < domain[0][0]) {
1674     x = domain[0][0];
1675   } else if (in[0] > domain[0][1]) {
1676     x = domain[0][1];
1677   } else {
1678     x = in[0];
1679   }
1680   for (i = 0; i < n; ++i) {
1681     out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
1682     if (hasRange) {
1683       if (out[i] < range[i][0]) {
1684         out[i] = range[i][0];
1685       } else if (out[i] > range[i][1]) {
1686         out[i] = range[i][1];
1687       }
1688     }
1689   }
1690   return;
1691 }
1692
1693 //------------------------------------------------------------------------
1694 // GfxImageColorMap
1695 //------------------------------------------------------------------------
1696
1697 GfxImageColorMap::GfxImageColorMap(int bits, Object *decode,
1698                                    GfxColorSpace *colorSpace) {
1699   GfxIndexedColorSpace *indexedCS;
1700   GfxSeparationColorSpace *sepCS;
1701   int maxPixel, indexHigh;
1702   Guchar *lookup2;
1703   Function *sepFunc;
1704   Object obj;
1705   double x;
1706   double y[gfxColorMaxComps];
1707   int i, j, k;
1708
1709   ok = gTrue;
1710
1711   // bits per component and color space
1712   this->bits = bits;
1713   maxPixel = (1 << bits) - 1;
1714   this->colorSpace = colorSpace;
1715
1716   // get decode map
1717   if (decode->isNull()) {
1718     nComps = colorSpace->getNComps();
1719     colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
1720   } else if (decode->isArray()) {
1721     nComps = decode->arrayGetLength() / 2;
1722     if (nComps != colorSpace->getNComps()) {
1723       goto err1;
1724     }
1725     for (i = 0; i < nComps; ++i) {
1726       decode->arrayGet(2*i, &obj);
1727       if (!obj.isNum()) {
1728         goto err2;
1729       }
1730       decodeLow[i] = obj.getNum();
1731       obj.free();
1732       decode->arrayGet(2*i+1, &obj);
1733       if (!obj.isNum()) {
1734         goto err2;
1735       }
1736       decodeRange[i] = obj.getNum() - decodeLow[i];
1737       obj.free();
1738     }
1739   } else {
1740     goto err1;
1741   }
1742
1743 #if 0 //~
1744   // handle the case where fewer than 2^n palette entries of an n-bit
1745   // indexed color space are populated (this happens, e.g., in files
1746   // optimized by Distiller)
1747   if (colorSpace->getMode() == csIndexed) {
1748     i = ((GfxIndexedColorSpace *)colorSpace)->getIndexHigh();
1749     if (i < maxPixel) {
1750       maxPixel = i;
1751     }
1752   }
1753 #endif
1754
1755   // Construct a lookup table -- this stores pre-computed decoded
1756   // values for each component, i.e., the result of applying the
1757   // decode mapping to each possible image pixel component value.
1758   //
1759   // Optimization: for Indexed and Separation color spaces (which have
1760   // only one component), we store color values in the lookup table
1761   // rather than component values.
1762   colorSpace2 = NULL;
1763   nComps2 = 0;
1764   if (colorSpace->getMode() == csIndexed) {
1765     // Note that indexHigh may not be the same as maxPixel --
1766     // Distiller will remove unused palette entries, resulting in
1767     // indexHigh < maxPixel.
1768     indexedCS = (GfxIndexedColorSpace *)colorSpace;
1769     colorSpace2 = indexedCS->getBase();
1770     indexHigh = indexedCS->getIndexHigh();
1771     nComps2 = colorSpace2->getNComps();
1772     lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double));
1773     lookup2 = indexedCS->getLookup();
1774     for (i = 0; i <= indexHigh; ++i) {
1775       j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5);
1776       for (k = 0; k < nComps2; ++k) {
1777         lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0;
1778       }
1779     }
1780   } else if (colorSpace->getMode() == csSeparation) {
1781     sepCS = (GfxSeparationColorSpace *)colorSpace;
1782     colorSpace2 = sepCS->getAlt();
1783     nComps2 = colorSpace2->getNComps();
1784     lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
1785     sepFunc = sepCS->getFunc();
1786     for (i = 0; i <= maxPixel; ++i) {
1787       x = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
1788       sepFunc->transform(&x, y);
1789       for (k = 0; k < nComps2; ++k) {
1790         lookup[i*nComps2 + k] = y[k];
1791       }
1792     }
1793   } else {
1794     lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
1795     for (i = 0; i <= maxPixel; ++i) {
1796       for (k = 0; k < nComps; ++k) {
1797         lookup[i*nComps + k] = decodeLow[k] +
1798                                  (i * decodeRange[k]) / maxPixel;
1799       }
1800     }
1801   }
1802
1803   return;
1804
1805  err2:
1806   obj.free();
1807  err1:
1808   ok = gFalse;
1809 }
1810
1811 GfxImageColorMap::~GfxImageColorMap() {
1812   delete colorSpace;
1813   gfree(lookup);
1814 }
1815
1816 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
1817   GfxColor color;
1818   double *p;
1819   int i;
1820
1821   if (colorSpace2) {
1822     p = &lookup[x[0] * nComps2];
1823     for (i = 0; i < nComps2; ++i) {
1824       color.c[i] = *p++;
1825     }
1826     colorSpace2->getGray(&color, gray);
1827   } else {
1828     for (i = 0; i < nComps; ++i) {
1829       color.c[i] = lookup[x[i] * nComps + i];
1830     }
1831     colorSpace->getGray(&color, gray);
1832   }
1833 }
1834
1835 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
1836   GfxColor color;
1837   double *p;
1838   int i;
1839
1840   if (colorSpace2) {
1841     p = &lookup[x[0] * nComps2];
1842     for (i = 0; i < nComps2; ++i) {
1843       color.c[i] = *p++;
1844     }
1845     colorSpace2->getRGB(&color, rgb);
1846   } else {
1847     for (i = 0; i < nComps; ++i) {
1848       color.c[i] = lookup[x[i] * nComps + i];
1849     }
1850     colorSpace->getRGB(&color, rgb);
1851   }
1852 }
1853
1854 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
1855   GfxColor color;
1856   double *p;
1857   int i;
1858
1859   if (colorSpace2) {
1860     p = &lookup[x[0] * nComps2];
1861     for (i = 0; i < nComps2; ++i) {
1862       color.c[i] = *p++;
1863     }
1864     colorSpace2->getCMYK(&color, cmyk);
1865   } else {
1866     for (i = 0; i < nComps; ++i) {
1867       color.c[i] = lookup[x[i] * nComps + i];
1868     }
1869     colorSpace->getCMYK(&color, cmyk);
1870   }
1871 }
1872
1873 //------------------------------------------------------------------------
1874 // GfxSubpath and GfxPath
1875 //------------------------------------------------------------------------
1876
1877 GfxSubpath::GfxSubpath(double x1, double y1) {
1878   size = 16;
1879   x = (double *)gmalloc(size * sizeof(double));
1880   y = (double *)gmalloc(size * sizeof(double));
1881   curve = (GBool *)gmalloc(size * sizeof(GBool));
1882   n = 1;
1883   x[0] = x1;
1884   y[0] = y1;
1885   curve[0] = gFalse;
1886   closed = gFalse;
1887 }
1888
1889 GfxSubpath::~GfxSubpath() {
1890   gfree(x);
1891   gfree(y);
1892   gfree(curve);
1893 }
1894
1895 // Used for copy().
1896 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
1897   size = subpath->size;
1898   n = subpath->n;
1899   x = (double *)gmalloc(size * sizeof(double));
1900   y = (double *)gmalloc(size * sizeof(double));
1901   curve = (GBool *)gmalloc(size * sizeof(GBool));
1902   memcpy(x, subpath->x, n * sizeof(double));
1903   memcpy(y, subpath->y, n * sizeof(double));
1904   memcpy(curve, subpath->curve, n * sizeof(GBool));
1905   closed = subpath->closed;
1906 }
1907
1908 void GfxSubpath::lineTo(double x1, double y1) {
1909   if (n >= size) {
1910     size += 16;
1911     x = (double *)grealloc(x, size * sizeof(double));
1912     y = (double *)grealloc(y, size * sizeof(double));
1913     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1914   }
1915   x[n] = x1;
1916   y[n] = y1;
1917   curve[n] = gFalse;
1918   ++n;
1919 }
1920
1921 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
1922                          double x3, double y3) {
1923   if (n+3 > size) {
1924     size += 16;
1925     x = (double *)grealloc(x, size * sizeof(double));
1926     y = (double *)grealloc(y, size * sizeof(double));
1927     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1928   }
1929   x[n] = x1;
1930   y[n] = y1;
1931   x[n+1] = x2;
1932   y[n+1] = y2;
1933   x[n+2] = x3;
1934   y[n+2] = y3;
1935   curve[n] = curve[n+1] = gTrue;
1936   curve[n+2] = gFalse;
1937   n += 3;
1938 }
1939
1940 void GfxSubpath::close() {
1941   if (x[n-1] != x[0] || y[n-1] != y[0]) {
1942     lineTo(x[0], y[0]);
1943   }
1944   closed = gTrue;
1945 }
1946
1947 GfxPath::GfxPath() {
1948   justMoved = gFalse;
1949   size = 16;
1950   n = 0;
1951   firstX = firstY = 0;
1952   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1953 }
1954
1955 GfxPath::~GfxPath() {
1956   int i;
1957
1958   for (i = 0; i < n; ++i)
1959     delete subpaths[i];
1960   gfree(subpaths);
1961 }
1962
1963 // Used for copy().
1964 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
1965                  GfxSubpath **subpaths1, int n1, int size1) {
1966   int i;
1967
1968   justMoved = justMoved1;
1969   firstX = firstX1;
1970   firstY = firstY1;
1971   size = size1;
1972   n = n1;
1973   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1974   for (i = 0; i < n; ++i)
1975     subpaths[i] = subpaths1[i]->copy();
1976 }
1977
1978 void GfxPath::moveTo(double x, double y) {
1979   justMoved = gTrue;
1980   firstX = x;
1981   firstY = y;
1982 }
1983
1984 void GfxPath::lineTo(double x, double y) {
1985   if (justMoved) {
1986     if (n >= size) {
1987       size += 16;
1988       subpaths = (GfxSubpath **)
1989                    grealloc(subpaths, size * sizeof(GfxSubpath *));
1990     }
1991     subpaths[n] = new GfxSubpath(firstX, firstY);
1992     ++n;
1993     justMoved = gFalse;
1994   }
1995   subpaths[n-1]->lineTo(x, y);
1996 }
1997
1998 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
1999              double x3, double y3) {
2000   if (justMoved) {
2001     if (n >= size) {
2002       size += 16;
2003       subpaths = (GfxSubpath **)
2004                    grealloc(subpaths, size * sizeof(GfxSubpath *));
2005     }
2006     subpaths[n] = new GfxSubpath(firstX, firstY);
2007     ++n;
2008     justMoved = gFalse;
2009   }
2010   subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
2011 }
2012
2013
2014 //------------------------------------------------------------------------
2015 // GfxState
2016 //------------------------------------------------------------------------
2017
2018 GfxState::GfxState(double dpi, double px1a, double py1a,
2019                    double px2a, double py2a, int rotate, GBool upsideDown) {
2020   double k;
2021
2022   px1 = px1a;
2023   py1 = py1a;
2024   px2 = px2a;
2025   py2 = py2a;
2026   k = dpi / 72.0;
2027   if (rotate == 90) {
2028     ctm[0] = 0;
2029     ctm[1] = upsideDown ? k : -k;
2030     ctm[2] = k;
2031     ctm[3] = 0;
2032     ctm[4] = -k * py1;
2033     ctm[5] = k * (upsideDown ? -px1 : px2);
2034     pageWidth = k * (py2 - py1);
2035     pageHeight = k * (px2 - px1);
2036   } else if (rotate == 180) {
2037     ctm[0] = -k;
2038     ctm[1] = 0;
2039     ctm[2] = 0;
2040     ctm[3] = upsideDown ? k : -k;
2041     ctm[4] = k * px2;
2042     ctm[5] = k * (upsideDown ? -py1 : py2);
2043     pageWidth = k * (px2 - px1);
2044     pageHeight = k * (py2 - py1);
2045   } else if (rotate == 270) {
2046     ctm[0] = 0;
2047     ctm[1] = upsideDown ? -k : k;
2048     ctm[2] = -k;
2049     ctm[3] = 0;
2050     ctm[4] = k * py2;
2051     ctm[5] = k * (upsideDown ? px2 : -px1);
2052     pageWidth = k * (py2 - py1);
2053     pageHeight = k * (px2 - px1);
2054   } else {
2055     ctm[0] = k;
2056     ctm[1] = 0;
2057     ctm[2] = 0;
2058     ctm[3] = upsideDown ? -k : k;
2059     ctm[4] = -k * px1;
2060     ctm[5] = k * (upsideDown ? py2 : -py1);
2061     pageWidth = k * (px2 - px1);
2062     pageHeight = k * (py2 - py1);
2063   }
2064
2065   fillColorSpace = new GfxDeviceGrayColorSpace();
2066   strokeColorSpace = new GfxDeviceGrayColorSpace();
2067   fillColor.c[0] = 0;
2068   strokeColor.c[0] = 0;
2069   fillPattern = NULL;
2070   strokePattern = NULL;
2071   fillOpacity = 1;
2072   strokeOpacity = 1;
2073
2074   lineWidth = 1;
2075   lineDash = NULL;
2076   lineDashLength = 0;
2077   lineDashStart = 0;
2078   flatness = 0;
2079   lineJoin = 0;
2080   lineCap = 0;
2081   miterLimit = 10;
2082
2083   font = NULL;
2084   fontSize = 0;
2085   textMat[0] = 1; textMat[1] = 0;
2086   textMat[2] = 0; textMat[3] = 1;
2087   textMat[4] = 0; textMat[5] = 0;
2088   charSpace = 0;
2089   wordSpace = 0;
2090   horizScaling = 1;
2091   leading = 0;
2092   rise = 0;
2093   render = 0;
2094
2095   path = new GfxPath();
2096   curX = curY = 0;
2097   lineX = lineY = 0;
2098
2099   saved = NULL;
2100 }
2101
2102 GfxState::~GfxState() {
2103   if (fillColorSpace) {
2104     delete fillColorSpace;
2105   }
2106   if (strokeColorSpace) {
2107     delete strokeColorSpace;
2108   }
2109   if (fillPattern) {
2110     delete fillPattern;
2111   }
2112   if (strokePattern) {
2113     delete strokePattern;
2114   }
2115   gfree(lineDash);
2116   delete path;
2117   if (saved) {
2118     delete saved;
2119   }
2120 }
2121
2122 // Used for copy();
2123 GfxState::GfxState(GfxState *state) {
2124   memcpy(this, state, sizeof(GfxState));
2125   if (fillColorSpace) {
2126     fillColorSpace = state->fillColorSpace->copy();
2127   }
2128   if (strokeColorSpace) {
2129     strokeColorSpace = state->strokeColorSpace->copy();
2130   }
2131   if (fillPattern) {
2132     fillPattern = state->fillPattern->copy();
2133   }
2134   if (strokePattern) {
2135     strokePattern = state->strokePattern->copy();
2136   }
2137   if (lineDashLength > 0) {
2138     lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2139     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2140   }
2141   path = state->path->copy();
2142   saved = NULL;
2143 }
2144
2145 double GfxState::transformWidth(double w) {
2146   double x, y;
2147
2148   x = ctm[0] + ctm[2];
2149   y = ctm[1] + ctm[3];
2150   return w * sqrt(0.5 * (x * x + y * y));
2151 }
2152
2153 double GfxState::getTransformedFontSize() {
2154   double x1, y1, x2, y2;
2155
2156   x1 = textMat[2] * fontSize;
2157   y1 = textMat[3] * fontSize;
2158   x2 = ctm[0] * x1 + ctm[2] * y1;
2159   y2 = ctm[1] * x1 + ctm[3] * y1;
2160   return sqrt(x2 * x2 + y2 * y2);
2161 }
2162
2163 void GfxState::getFontTransMat(double *m11, double *m12,
2164                                double *m21, double *m22) {
2165   *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2166   *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2167   *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2168   *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2169 }
2170
2171 void GfxState::setCTM(double a, double b, double c,
2172                       double d, double e, double f) {
2173   ctm[0] = a;
2174   ctm[1] = b;
2175   ctm[2] = c;
2176   ctm[3] = d;
2177   ctm[4] = e;
2178   ctm[5] = f;
2179 }
2180
2181 void GfxState::concatCTM(double a, double b, double c,
2182                          double d, double e, double f) {
2183   double a1 = ctm[0];
2184   double b1 = ctm[1];
2185   double c1 = ctm[2];
2186   double d1 = ctm[3];
2187
2188   ctm[0] = a * a1 + b * c1;
2189   ctm[1] = a * b1 + b * d1;
2190   ctm[2] = c * a1 + d * c1;
2191   ctm[3] = c * b1 + d * d1;
2192   ctm[4] = e * a1 + f * c1 + ctm[4];
2193   ctm[5] = e * b1 + f * d1 + ctm[5];
2194 }
2195
2196 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2197   if (fillColorSpace) {
2198     delete fillColorSpace;
2199   }
2200   fillColorSpace = colorSpace;
2201 }
2202
2203 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2204   if (strokeColorSpace) {
2205     delete strokeColorSpace;
2206   }
2207   strokeColorSpace = colorSpace;
2208 }
2209
2210 void GfxState::setFillPattern(GfxPattern *pattern) {
2211   if (fillPattern) {
2212     delete fillPattern;
2213   }
2214   fillPattern = pattern;
2215 }
2216
2217 void GfxState::setStrokePattern(GfxPattern *pattern) {
2218   if (strokePattern) {
2219     delete strokePattern;
2220   }
2221   strokePattern = pattern;
2222 }
2223
2224 void GfxState::setLineDash(double *dash, int length, double start) {
2225   if (lineDash)
2226     gfree(lineDash);
2227   lineDash = dash;
2228   lineDashLength = length;
2229   lineDashStart = start;
2230 }
2231
2232 void GfxState::clearPath() {
2233   delete path;
2234   path = new GfxPath();
2235 }
2236
2237 void GfxState::textShift(double tx) {
2238   double dx, dy;
2239
2240   textTransformDelta(tx, 0, &dx, &dy);
2241   curX += dx;
2242   curY += dy;
2243 }
2244
2245 void GfxState::textShift(double tx, double ty) {
2246   double dx, dy;
2247
2248   textTransformDelta(tx, ty, &dx, &dy);
2249   curX += dx;
2250   curY += dy;
2251 }
2252
2253 GfxState *GfxState::save() {
2254   GfxState *newState;
2255
2256   newState = copy();
2257   newState->saved = this;
2258   return newState;
2259 }
2260
2261 GfxState *GfxState::restore() {
2262   GfxState *oldState;
2263
2264   if (saved) {
2265     oldState = saved;
2266     saved = NULL;
2267     delete this;
2268   } else {
2269     oldState = this;
2270   }
2271   return oldState;
2272 }