source: trunk/poppler/mypoppler/poppler/GfxState.cc @ 134

Last change on this file since 134 was 134, checked in by Eugene Romanenko, 15 years ago

poppler updated to version 0.5.4

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