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

Last change on this file since 461 was 461, checked in by Silvan Scherrer, 11 years ago

poppler update to 0.14.2

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