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

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

First import

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