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

Last change on this file since 250 was 250, checked in by Eugene Romanenko, 13 years ago

PDF plugin: poppler library updated to version 0.8.3

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