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

Last change on this file since 27 was 27, checked in by Eugene Romanenko, 16 years ago

poppler updated to version 0.5.2, also needed changes to be compatible with new poppler

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