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

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

PDF plugin: Poppler library updated to version 0.10.2

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