upgraded to xpdf-3.01pl1 xpdf-3-01
authorkramm <kramm>
Sat, 3 Dec 2005 14:48:56 +0000 (14:48 +0000)
committerkramm <kramm>
Sat, 3 Dec 2005 14:48:56 +0000 (14:48 +0000)
pdf2swf/xpdf/GfxState.cc
pdf2swf/xpdf/GlobalParams.cc
pdf2swf/xpdf/GlobalParams.h
pdf2swf/xpdf/OutputDev.h
pdf2swf/xpdf/Page.cc
pdf2swf/xpdf/Stream.cc
pdf2swf/xpdf/config.h
pdf2swf/xpdf/gfile.cc
pdf2swf/xpdf/gfile.h

index 33c96cc..051c7b6 100644 (file)
 
 #include <stddef.h>
 #include <math.h>
-#include <string.h> // for memcpy()
+#include <string.h>
 #include "gmem.h"
 #include "Error.h"
 #include "Object.h"
 #include "Array.h"
 #include "Page.h"
 #include "GfxState.h"
-#include "cmyk.h"
 
 //------------------------------------------------------------------------
 
+static inline GfxColorComp clip01(GfxColorComp x) {
+  return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x;
+}
+
 static inline double clip01(double x) {
-  return (x < 0) ? 0 : ((x > 1) ? 1 : x);
+  return (x < 0) ? 0 : (x > 1) ? 1 : x;
 }
 
 //------------------------------------------------------------------------
 
+static struct {
+  char *name;
+  GfxBlendMode mode;
+} gfxBlendModeNames[] = {
+  { "Normal",     gfxBlendNormal },
+  { "Compatible", gfxBlendNormal },
+  { "Multiply",   gfxBlendMultiply },
+  { "Screen",     gfxBlendScreen },
+  { "Overlay",    gfxBlendOverlay },
+  { "Darken",     gfxBlendDarken },
+  { "Lighten",    gfxBlendLighten },
+  { "ColorDodge", gfxBlendColorDodge },
+  { "ColorBurn",  gfxBlendColorBurn },
+  { "HardLight",  gfxBlendHardLight },
+  { "SoftLight",  gfxBlendSoftLight },
+  { "Difference", gfxBlendDifference },
+  { "Exclusion",  gfxBlendExclusion },
+  { "Hue",        gfxBlendHue },
+  { "Saturation", gfxBlendSaturation },
+  { "Color",      gfxBlendColor },
+  { "Luminosity", gfxBlendLuminosity }
+};
+
+#define nGfxBlendModeNames \
+          ((int)((sizeof(gfxBlendModeNames) / sizeof(char *))))
+
+//------------------------------------------------------------------------
+
+// NB: This must match the GfxColorSpaceMode enum defined in
+// GfxState.h
 static char *gfxColorSpaceModeNames[] = {
   "DeviceGray",
   "CalGray",
@@ -140,7 +173,7 @@ GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
   return new GfxDeviceGrayColorSpace();
 }
 
-void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
   *gray = clip01(color->c[0]);
 }
 
@@ -150,7 +183,7 @@ void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
 
 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   cmyk->c = cmyk->m = cmyk->y = 0;
-  cmyk->k = clip01(1 - color->c[0]);
+  cmyk->k = clip01(gfxColorComp1 - color->c[0]);
 }
 
 //------------------------------------------------------------------------
@@ -225,7 +258,7 @@ GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
   return cs;
 }
 
-void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
   *gray = clip01(color->c[0]);
 }
 
@@ -235,7 +268,7 @@ void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
 
 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   cmyk->c = cmyk->m = cmyk->y = 0;
-  cmyk->k = clip01(1 - color->c[0]);
+  cmyk->k = clip01(gfxColorComp1 - color->c[0]);
 }
 
 //------------------------------------------------------------------------
@@ -252,10 +285,10 @@ GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
   return new GfxDeviceRGBColorSpace();
 }
 
-void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
-  *gray = clip01(0.299 * color->c[0] +
-                0.587 * color->c[1] +
-                0.114 * color->c[2]);
+void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+  *gray = clip01((GfxColorComp)(0.3  * color->c[0] +
+                               0.59 * color->c[1] +
+                               0.11 * color->c[2] + 0.5));
 }
 
 void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
@@ -265,11 +298,11 @@ void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
 }
 
 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
-  double c, m, y, k;
+  GfxColorComp c, m, y, k;
 
-  c = clip01(1 - color->c[0]);
-  m = clip01(1 - color->c[1]);
-  y = clip01(1 - color->c[2]);
+  c = clip01(gfxColorComp1 - color->c[0]);
+  m = clip01(gfxColorComp1 - color->c[1]);
+  y = clip01(gfxColorComp1 - color->c[2]);
   k = c;
   if (m < k) {
     k = m;
@@ -383,10 +416,10 @@ GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
   return cs;
 }
 
-void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
-  *gray = clip01(0.299 * color->c[0] +
-                0.587 * color->c[1] +
-                0.114 * color->c[2]);
+void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+  *gray = clip01((GfxColorComp)(0.299 * color->c[0] +
+                               0.587 * color->c[1] +
+                               0.114 * color->c[2] + 0.5));
 }
 
 void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
@@ -396,11 +429,11 @@ void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
 }
 
 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
-  double c, m, y, k;
+  GfxColorComp c, m, y, k;
 
-  c = clip01(1 - color->c[0]);
-  m = clip01(1 - color->c[1]);
-  y = clip01(1 - color->c[2]);
+  c = clip01(gfxColorComp1 - color->c[0]);
+  m = clip01(gfxColorComp1 - color->c[1]);
+  y = clip01(gfxColorComp1 - color->c[2]);
   k = c;
   if (m < k) {
     k = m;
@@ -428,51 +461,73 @@ GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
   return new GfxDeviceCMYKColorSpace();
 }
 
-void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
-  *gray = clip01(1 - color->c[3]
-                - 0.299 * color->c[0]
-                - 0.587 * color->c[1]
-                - 0.114 * color->c[2]);
-}
-
-/*void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
-    double c,m,y,k,white;
-    c = color->c[0];
-    m = color->c[1];
-    y = color->c[2];
-    k = color->c[3];
-    white = 1.0 - k;
-    rgb->r = white - (c*white);
-    rgb->g = white - (m*white);
-    rgb->b = white - (y*white);
-}*/
-/*void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
-  double c, m, y, aw, ac, am, ay, ar, ag, ab;
-
-  c = clip01(color->c[0] + color->c[3]);
-  m = clip01(color->c[1] + color->c[3]);
-  y = clip01(color->c[2] + color->c[3]);
-  aw = (1-c) * (1-m) * (1-y);
-  ac = c * (1-m) * (1-y);
-  am = (1-c) * m * (1-y);
-  ay = (1-c) * (1-m) * y;
-  ar = (1-c) * m * y;
-  ag = c * (1-m) * y;
-  ab = c * m * (1-y);
-  rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
-  rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
-  rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag + 0.4863*ab);
-}*/
+void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+  *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3]
+                               - 0.3  * color->c[0]
+                               - 0.59 * color->c[1]
+                               - 0.11 * color->c[2] + 0.5));
+}
+
 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
-    unsigned char r,g,b;
-    float c = color->c[0];
-    float m = color->c[1];
-    float y = color->c[2];
-    float k = color->c[3];
-    convert_cmyk2rgb(c,m,y,k, &r,&g,&b);
-    rgb->r = r/255.0;
-    rgb->g = g/255.0;
-    rgb->b = b/255.0;
+  double c, m, y, k, c1, m1, y1, k1, r, g, b, x;
+
+  c = colToDbl(color->c[0]);
+  m = colToDbl(color->c[1]);
+  y = colToDbl(color->c[2]);
+  k = colToDbl(color->c[3]);
+  c1 = 1 - c;
+  m1 = 1 - m;
+  y1 = 1 - y;
+  k1 = 1 - k;
+  // this is a matrix multiplication, unrolled for performance
+  //                        C M Y K
+  x = c1 * m1 * y1 * k1; // 0 0 0 0
+  r = g = b = x;
+  x = c1 * m1 * y1 * k;  // 0 0 0 1
+  r += 0.1373 * x;
+  g += 0.1216 * x;
+  b += 0.1255 * x;
+  x = c1 * m1 * y  * k1; // 0 0 1 0
+  r += x;
+  g += 0.9490 * x;
+  x = c1 * m1 * y  * k;  // 0 0 1 1
+  r += 0.1098 * x;
+  g += 0.1020 * x;
+  x = c1 * m  * y1 * k1; // 0 1 0 0
+  r += 0.9255 * x;
+  b += 0.5490 * x;
+  x = c1 * m  * y1 * k;  // 0 1 0 1
+  r += 0.1412 * x;
+  x = c1 * m  * y  * k1; // 0 1 1 0
+  r += 0.9294 * x;
+  g += 0.1098 * x;
+  b += 0.1412 * x;
+  x = c1 * m  * y  * k;  // 0 1 1 1
+  r += 0.1333 * x;
+  x = c  * m1 * y1 * k1; // 1 0 0 0
+  g += 0.6784 * x;
+  b += 0.9373 * x;
+  x = c  * m1 * y1 * k;  // 1 0 0 1
+  g += 0.0588 * x;
+  b += 0.1412 * x;
+  x = c  * m1 * y  * k1; // 1 0 1 0
+  g += 0.6510 * x;
+  b += 0.3137 * x;
+  x = c  * m1 * y  * k;  // 1 0 1 1
+  g += 0.0745 * x;
+  x = c  * m  * y1 * k1; // 1 1 0 0
+  r += 0.1804 * x;
+  g += 0.1922 * x;
+  b += 0.5725 * x;
+  x = c  * m  * y1 * k;  // 1 1 0 1
+  b += 0.0078 * x;
+  x = c  * m  * y  * k1; // 1 1 1 0
+  r += 0.2118 * x;
+  g += 0.2119 * x;
+  b += 0.2235 * x;
+  rgb->r = clip01(dblToCol(r));
+  rgb->g = clip01(dblToCol(g));
+  rgb->b = clip01(dblToCol(b));
 }
 
 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
@@ -592,13 +647,13 @@ GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
   return cs;
 }
 
-void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) {
   GfxRGB rgb;
 
   getRGB(color, &rgb);
-  *gray = clip01(0.299 * rgb.r +
-                0.587 * rgb.g +
-                0.114 * rgb.b);
+  *gray = clip01((GfxColorComp)(0.299 * rgb.r +
+                               0.587 * rgb.g +
+                               0.114 * rgb.b + 0.5));
 }
 
 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
@@ -607,8 +662,8 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
   double r, g, b;
 
   // convert L*a*b* to CIE 1931 XYZ color space
-  t1 = (color->c[0] + 16) / 116;
-  t2 = t1 + color->c[1] / 500;
+  t1 = (colToDbl(color->c[0]) + 16) / 116;
+  t2 = t1 + colToDbl(color->c[1]) / 500;
   if (t2 >= (6.0 / 29.0)) {
     X = t2 * t2 * t2;
   } else {
@@ -621,7 +676,7 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
     Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
   }
   Y *= whiteY;
-  t2 = t1 - color->c[2] / 200;
+  t2 = t1 - colToDbl(color->c[2]) / 200;
   if (t2 >= (6.0 / 29.0)) {
     Z = t2 * t2 * t2;
   } else {
@@ -633,19 +688,19 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
   r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
   g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
   b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
-  rgb->r = pow(clip01(r * kr), 0.5);
-  rgb->g = pow(clip01(g * kg), 0.5);
-  rgb->b = pow(clip01(b * kb), 0.5);
+  rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
+  rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
+  rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
 }
 
 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   GfxRGB rgb;
-  double c, m, y, k;
+  GfxColorComp c, m, y, k;
 
   getRGB(color, &rgb);
-  c = clip01(1 - rgb.r);
-  m = clip01(1 - rgb.g);
-  y = clip01(1 - rgb.b);
+  c = clip01(gfxColorComp1 - rgb.r);
+  m = clip01(gfxColorComp1 - rgb.g);
+  y = clip01(gfxColorComp1 - rgb.b);
   k = c;
   if (m < k) {
     k = m;
@@ -730,6 +785,11 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
   }
   nCompsA = obj2.getInt();
   obj2.free();
+  if (nCompsA > gfxColorMaxComps) {
+    error(-1, "ICCBased color space with too many (%d > %d) components",
+         nCompsA, gfxColorMaxComps);
+    nCompsA = gfxColorMaxComps;
+  }
   if (dict->lookup("Alternate", &obj2)->isNull() ||
       !(altA = GfxColorSpace::parse(&obj2))) {
     switch (nCompsA) {
@@ -767,7 +827,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
   return cs;
 }
 
-void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
   alt->getGray(color, gray);
 }
 
@@ -804,8 +864,8 @@ GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
                                           int indexHighA) {
   base = baseA;
   indexHigh = indexHighA;
-  lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
-                            sizeof(Guchar));
+  lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(),
+                             sizeof(Guchar));
 }
 
 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
@@ -906,14 +966,14 @@ GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
 
   n = base->getNComps();
   base->getDefaultRanges(low, range, indexHigh);
-  p = &lookup[(int)(color->c[0] + 0.5) * n];
+  p = &lookup[(int)(colToDbl(color->c[0]) + 0.5) * n];
   for (i = 0; i < n; ++i) {
-    baseColor->c[i] = low[i] + (p[i] / 255.0) * range[i];
+    baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]);
   }
   return baseColor;
 }
 
-void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
   GfxColor color2;
 
   base->getGray(mapColorToBase(color, &color2), gray);
@@ -1002,24 +1062,45 @@ GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
   return NULL;
 }
 
-void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+  double x;
+  double c[gfxColorMaxComps];
   GfxColor color2;
+  int i;
 
-  func->transform(color->c, color2.c);
+  x = colToDbl(color->c[0]);
+  func->transform(&x, c);
+  for (i = 0; i < alt->getNComps(); ++i) {
+    color2.c[i] = dblToCol(c[i]);
+  }
   alt->getGray(&color2, gray);
 }
 
 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+  double x;
+  double c[gfxColorMaxComps];
   GfxColor color2;
+  int i;
 
-  func->transform(color->c, color2.c);
+  x = colToDbl(color->c[0]);
+  func->transform(&x, c);
+  for (i = 0; i < alt->getNComps(); ++i) {
+    color2.c[i] = dblToCol(c[i]);
+  }
   alt->getRGB(&color2, rgb);
 }
 
 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+  double x;
+  double c[gfxColorMaxComps];
   GfxColor color2;
+  int i;
 
-  func->transform(color->c, color2.c);
+  x = colToDbl(color->c[0]);
+  func->transform(&x, c);
+  for (i = 0; i < alt->getNComps(); ++i) {
+    color2.c[i] = dblToCol(c[i]);
+  }
   alt->getCMYK(&color2, cmyk);
 }
 
@@ -1076,7 +1157,7 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
   }
   nCompsA = obj1.arrayGetLength();
   if (nCompsA > gfxColorMaxComps) {
-    error(-1, "DeviceN color space with more than %d > %d components",
+    error(-1, "DeviceN color space with too many (%d > %d) components",
          nCompsA, gfxColorMaxComps);
     nCompsA = gfxColorMaxComps;
   }
@@ -1119,24 +1200,48 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
   return NULL;
 }
 
-void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+  double x[gfxColorMaxComps], c[gfxColorMaxComps];
   GfxColor color2;
+  int i;
 
-  func->transform(color->c, color2.c);
+  for (i = 0; i < nComps; ++i) {
+    x[i] = colToDbl(color->c[i]);
+  }
+  func->transform(x, c);
+  for (i = 0; i < alt->getNComps(); ++i) {
+    color2.c[i] = dblToCol(c[i]);
+  }
   alt->getGray(&color2, gray);
 }
 
 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+  double x[gfxColorMaxComps], c[gfxColorMaxComps];
   GfxColor color2;
+  int i;
 
-  func->transform(color->c, color2.c);
+  for (i = 0; i < nComps; ++i) {
+    x[i] = colToDbl(color->c[i]);
+  }
+  func->transform(x, c);
+  for (i = 0; i < alt->getNComps(); ++i) {
+    color2.c[i] = dblToCol(c[i]);
+  }
   alt->getRGB(&color2, rgb);
 }
 
 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+  double x[gfxColorMaxComps], c[gfxColorMaxComps];
   GfxColor color2;
+  int i;
 
-  func->transform(color->c, color2.c);
+  for (i = 0; i < nComps; ++i) {
+    x[i] = colToDbl(color->c[i]);
+  }
+  func->transform(x, c);
+  for (i = 0; i < alt->getNComps(); ++i) {
+    color2.c[i] = dblToCol(c[i]);
+  }
   alt->getCMYK(&color2, cmyk);
 }
 
@@ -1182,7 +1287,7 @@ GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
   return cs;
 }
 
-void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
+void GfxPatternColorSpace::getGray(GfxColor *color, GfxGray *gray) {
   *gray = 0;
 }
 
@@ -1467,6 +1572,38 @@ GfxShading *GfxShading::parse(Object *obj) {
   case 3:
     shading = GfxRadialShading::parse(dict);
     break;
+  case 4:
+    if (obj->isStream()) {
+      shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream());
+    } else {
+      error(-1, "Invalid Type 4 shading object");
+      goto err1;
+    }
+    break;
+  case 5:
+    if (obj->isStream()) {
+      shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream());
+    } else {
+      error(-1, "Invalid Type 5 shading object");
+      goto err1;
+    }
+    break;
+  case 6:
+    if (obj->isStream()) {
+      shading = GfxPatchMeshShading::parse(6, dict, obj->getStream());
+    } else {
+      error(-1, "Invalid Type 6 shading object");
+      goto err1;
+    }
+    break;
+  case 7:
+    if (obj->isStream()) {
+      shading = GfxPatchMeshShading::parse(7, dict, obj->getStream());
+    } else {
+      error(-1, "Invalid Type 7 shading object");
+      goto err1;
+    }
+    break;
   default:
     error(-1, "Unimplemented shading type %d", typeA);
     goto err1;
@@ -1498,7 +1635,7 @@ GBool GfxShading::init(Dict *dict) {
     if (obj1.arrayGetLength() == colorSpace->getNComps()) {
       hasBackground = gTrue;
       for (i = 0; i < colorSpace->getNComps(); ++i) {
-       background.c[i] = obj1.arrayGet(i, &obj2)->getNum();
+       background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum());
        obj2.free();
       }
     } else {
@@ -1666,13 +1803,21 @@ GfxShading *GfxFunctionShading::copy() {
 }
 
 void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
-  double in[2];
+  double in[2], out[gfxColorMaxComps];
   int i;
 
+  // NB: there can be one function with n outputs or n functions with
+  // one output each (where n = number of color components)
+  for (i = 0; i < gfxColorMaxComps; ++i) {
+    out[i] = 0;
+  }
   in[0] = x;
   in[1] = y;
   for (i = 0; i < nFuncs; ++i) {
-    funcs[i]->transform(in, &color->c[i]);
+    funcs[i]->transform(in, &out[i]);
+  }
+  for (i = 0; i < gfxColorMaxComps; ++i) {
+    color->c[i] = dblToCol(out[i]);
   }
 }
 
@@ -1820,12 +1965,19 @@ GfxShading *GfxAxialShading::copy() {
 }
 
 void GfxAxialShading::getColor(double t, GfxColor *color) {
+  double out[gfxColorMaxComps];
   int i;
 
   // NB: there can be one function with n outputs or n functions with
   // one output each (where n = number of color components)
+  for (i = 0; i < gfxColorMaxComps; ++i) {
+    out[i] = 0;
+  }
   for (i = 0; i < nFuncs; ++i) {
-    funcs[i]->transform(&t, &color->c[i]);
+    funcs[i]->transform(&t, &out[i]);
+  }
+  for (i = 0; i < gfxColorMaxComps; ++i) {
+    color->c[i] = dblToCol(out[i]);
   }
 }
 
@@ -1981,16 +2133,964 @@ GfxShading *GfxRadialShading::copy() {
 }
 
 void GfxRadialShading::getColor(double t, GfxColor *color) {
+  double out[gfxColorMaxComps];
   int i;
 
   // NB: there can be one function with n outputs or n functions with
   // one output each (where n = number of color components)
+  for (i = 0; i < gfxColorMaxComps; ++i) {
+    out[i] = 0;
+  }
   for (i = 0; i < nFuncs; ++i) {
-    funcs[i]->transform(&t, &color->c[i]);
+    funcs[i]->transform(&t, &out[i]);
+  }
+  for (i = 0; i < gfxColorMaxComps; ++i) {
+    color->c[i] = dblToCol(out[i]);
   }
 }
 
 //------------------------------------------------------------------------
+// GfxShadingBitBuf
+//------------------------------------------------------------------------
+
+class GfxShadingBitBuf {
+public:
+
+  GfxShadingBitBuf(Stream *strA);
+  ~GfxShadingBitBuf();
+  GBool getBits(int n, Guint *val);
+  void flushBits();
+
+private:
+
+  Stream *str;
+  int bitBuf;
+  int nBits;
+};
+
+GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) {
+  str = strA;
+  str->reset();
+  bitBuf = 0;
+  nBits = 0;
+}
+
+GfxShadingBitBuf::~GfxShadingBitBuf() {
+  str->close();
+}
+
+GBool GfxShadingBitBuf::getBits(int n, Guint *val) {
+  int x;
+
+  if (nBits >= n) {
+    x = (bitBuf >> (nBits - n)) & ((1 << n) - 1);
+    nBits -= n;
+  } else {
+    x = 0;
+    if (nBits > 0) {
+      x = bitBuf & ((1 << nBits) - 1);
+      n -= nBits;
+      nBits = 0;
+    }
+    while (n > 0) {
+      if ((bitBuf = str->getChar()) == EOF) {
+       nBits = 0;
+       return gFalse;
+      }
+      if (n >= 8) {
+       x = (x << 8) | bitBuf;
+       n -= 8;
+      } else {
+       x = (x << n) | (bitBuf >> (8 - n));
+       nBits = 8 - n;
+       n = 0;
+      }
+    }
+  }
+  *val = x;
+  return gTrue;
+}
+
+void GfxShadingBitBuf::flushBits() {
+  bitBuf = 0;
+  nBits = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxGouraudTriangleShading
+//------------------------------------------------------------------------
+
+GfxGouraudTriangleShading::GfxGouraudTriangleShading(
+                              int typeA,
+                              GfxGouraudVertex *verticesA, int nVerticesA,
+                              int (*trianglesA)[3], int nTrianglesA,
+                              Function **funcsA, int nFuncsA):
+  GfxShading(typeA)
+{
+  int i;
+
+  vertices = verticesA;
+  nVertices = nVerticesA;
+  triangles = trianglesA;
+  nTriangles = nTrianglesA;
+  nFuncs = nFuncsA;
+  for (i = 0; i < nFuncs; ++i) {
+    funcs[i] = funcsA[i];
+  }
+}
+
+GfxGouraudTriangleShading::GfxGouraudTriangleShading(
+                              GfxGouraudTriangleShading *shading):
+  GfxShading(shading)
+{
+  int i;
+
+  nVertices = shading->nVertices;
+  vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex));
+  memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex));
+  nTriangles = shading->nTriangles;
+  triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int));
+  memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int));
+  nFuncs = shading->nFuncs;
+  for (i = 0; i < nFuncs; ++i) {
+    funcs[i] = shading->funcs[i]->copy();
+  }
+}
+
+GfxGouraudTriangleShading::~GfxGouraudTriangleShading() {
+  int i;
+
+  gfree(vertices);
+  gfree(triangles);
+  for (i = 0; i < nFuncs; ++i) {
+    delete funcs[i];
+  }
+}
+
+GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA,
+                                                           Dict *dict,
+                                                           Stream *str) {
+  GfxGouraudTriangleShading *shading;
+  Function *funcsA[gfxColorMaxComps];
+  int nFuncsA;
+  int coordBits, compBits, flagBits, vertsPerRow, nRows;
+  double xMin, xMax, yMin, yMax;
+  double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
+  double xMul, yMul;
+  double cMul[gfxColorMaxComps];
+  GfxGouraudVertex *verticesA;
+  int (*trianglesA)[3];
+  int nComps, nVerticesA, nTrianglesA, vertSize, triSize;
+  Guint x, y, flag;
+  Guint c[gfxColorMaxComps];
+  GfxShadingBitBuf *bitBuf;
+  Object obj1, obj2;
+  int i, j, k, state;
+
+  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+    coordBits = obj1.getInt();
+  } else {
+    error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
+    goto err2;
+  }
+  obj1.free();
+  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+    compBits = obj1.getInt();
+  } else {
+    error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
+    goto err2;
+  }
+  obj1.free();
+  flagBits = vertsPerRow = 0; // make gcc happy
+  if (typeA == 4) {
+    if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+      flagBits = obj1.getInt();
+    } else {
+      error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
+      goto err2;
+    }
+    obj1.free();
+  } else {
+    if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
+      vertsPerRow = obj1.getInt();
+    } else {
+      error(-1, "Missing or invalid VerticesPerRow in shading dictionary");
+      goto err2;
+    }
+    obj1.free();
+  }
+  if (dict->lookup("Decode", &obj1)->isArray() &&
+      obj1.arrayGetLength() >= 6) {
+    xMin = obj1.arrayGet(0, &obj2)->getNum();
+    obj2.free();
+    xMax = obj1.arrayGet(1, &obj2)->getNum();
+    obj2.free();
+    xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
+    yMin = obj1.arrayGet(2, &obj2)->getNum();
+    obj2.free();
+    yMax = obj1.arrayGet(3, &obj2)->getNum();
+    obj2.free();
+    yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
+    for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
+      cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
+      obj2.free();
+      cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
+      obj2.free();
+      cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
+    }
+    nComps = i;
+  } else {
+    error(-1, "Missing or invalid Decode array in shading dictionary");
+    goto err2;
+  }
+  obj1.free();
+
+  if (!dict->lookup("Function", &obj1)->isNull()) {
+    if (obj1.isArray()) {
+      nFuncsA = obj1.arrayGetLength();
+      if (nFuncsA > gfxColorMaxComps) {
+       error(-1, "Invalid Function array in shading dictionary");
+       goto err1;
+      }
+      for (i = 0; i < nFuncsA; ++i) {
+       obj1.arrayGet(i, &obj2);
+       if (!(funcsA[i] = Function::parse(&obj2))) {
+         obj1.free();
+         obj2.free();
+         goto err1;
+       }
+       obj2.free();
+      }
+    } else {
+      nFuncsA = 1;
+      if (!(funcsA[0] = Function::parse(&obj1))) {
+       obj1.free();
+       goto err1;
+      }
+    }
+  } else {
+    nFuncsA = 0;
+  }
+  obj1.free();
+
+  nVerticesA = nTrianglesA = 0;
+  verticesA = NULL;
+  trianglesA = NULL;
+  vertSize = triSize = 0;
+  state = 0;
+  flag = 0; // make gcc happy
+  bitBuf = new GfxShadingBitBuf(str);
+  while (1) {
+    if (typeA == 4) {
+      if (!bitBuf->getBits(flagBits, &flag)) {
+       break;
+      }
+    }
+    if (!bitBuf->getBits(coordBits, &x) ||
+       !bitBuf->getBits(coordBits, &y)) {
+      break;
+    }
+    for (i = 0; i < nComps; ++i) {
+      if (!bitBuf->getBits(compBits, &c[i])) {
+       break;
+      }
+    }
+    if (i < nComps) {
+      break;
+    }
+    if (nVerticesA == vertSize) {
+      vertSize = (vertSize == 0) ? 16 : 2 * vertSize;
+      verticesA = (GfxGouraudVertex *)
+                     greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex));
+    }
+    verticesA[nVerticesA].x = xMin + xMul * (double)x;
+    verticesA[nVerticesA].y = yMin + yMul * (double)y;
+    for (i = 0; i < nComps; ++i) {
+      verticesA[nVerticesA].color.c[i] =
+         dblToCol(cMin[i] + cMul[i] * (double)c[i]);
+    }
+    ++nVerticesA;
+    bitBuf->flushBits();
+    if (typeA == 4) {
+      if (state == 0 || state == 1) {
+       ++state;
+      } else if (state == 2 || flag > 0) {
+       if (nTrianglesA == triSize) {
+         triSize = (triSize == 0) ? 16 : 2 * triSize;
+         trianglesA = (int (*)[3])
+                          greallocn(trianglesA, triSize * 3, sizeof(int));
+       }
+       if (state == 2) {
+         trianglesA[nTrianglesA][0] = nVerticesA - 3;
+         trianglesA[nTrianglesA][1] = nVerticesA - 2;
+         trianglesA[nTrianglesA][2] = nVerticesA - 1;
+         ++state;
+       } else if (flag == 1) {
+         trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1];
+         trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
+         trianglesA[nTrianglesA][2] = nVerticesA - 1;
+       } else { // flag == 2
+         trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0];
+         trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
+         trianglesA[nTrianglesA][2] = nVerticesA - 1;
+       }
+       ++nTrianglesA;
+      } else { // state == 3 && flag == 0
+       state = 1;
+      }
+    }
+  }
+  delete bitBuf;
+  if (typeA == 5) {
+    nRows = nVerticesA / vertsPerRow;
+    nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1);
+    trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int));
+    k = 0;
+    for (i = 0; i < nRows - 1; ++i) {
+      for (j = 0; j < vertsPerRow - 1; ++j) {
+       trianglesA[k][0] = i * vertsPerRow + j;
+       trianglesA[k][1] = i * vertsPerRow + j+1;
+       trianglesA[k][2] = (i+1) * vertsPerRow + j;
+       ++k;
+       trianglesA[k][0] = i * vertsPerRow + j+1;
+       trianglesA[k][1] = (i+1) * vertsPerRow + j;
+       trianglesA[k][2] = (i+1) * vertsPerRow + j+1;
+       ++k;
+      }
+    }
+  }
+
+  shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA,
+                                         trianglesA, nTrianglesA,
+                                         funcsA, nFuncsA);
+  if (!shading->init(dict)) {
+    delete shading;
+    return NULL;
+  }
+  return shading;
+
+ err2:
+  obj1.free();
+ err1:
+  return NULL;
+}
+
+GfxShading *GfxGouraudTriangleShading::copy() {
+  return new GfxGouraudTriangleShading(this);
+}
+
+void GfxGouraudTriangleShading::getTriangle(
+                                   int i,
+                                   double *x0, double *y0, GfxColor *color0,
+                                   double *x1, double *y1, GfxColor *color1,
+                                   double *x2, double *y2, GfxColor *color2) {
+  double in;
+  double out[gfxColorMaxComps];
+  int v, j;
+
+  v = triangles[i][0];
+  *x0 = vertices[v].x;
+  *y0 = vertices[v].y;
+  if (nFuncs > 0) {
+    in = colToDbl(vertices[v].color.c[0]);
+    for (j = 0; j < nFuncs; ++j) {
+      funcs[j]->transform(&in, &out[j]);
+    }
+    for (j = 0; j < gfxColorMaxComps; ++j) {
+      color0->c[j] = dblToCol(out[j]);
+    }
+  } else {
+    *color0 = vertices[v].color;
+  }
+  v = triangles[i][1];
+  *x1 = vertices[v].x;
+  *y1 = vertices[v].y;
+  if (nFuncs > 0) {
+    in = colToDbl(vertices[v].color.c[0]);
+    for (j = 0; j < nFuncs; ++j) {
+      funcs[j]->transform(&in, &out[j]);
+    }
+    for (j = 0; j < gfxColorMaxComps; ++j) {
+      color1->c[j] = dblToCol(out[j]);
+    }
+  } else {
+    *color1 = vertices[v].color;
+  }
+  v = triangles[i][2];
+  *x2 = vertices[v].x;
+  *y2 = vertices[v].y;
+  if (nFuncs > 0) {
+    in = colToDbl(vertices[v].color.c[0]);
+    for (j = 0; j < nFuncs; ++j) {
+      funcs[j]->transform(&in, &out[j]);
+    }
+    for (j = 0; j < gfxColorMaxComps; ++j) {
+      color2->c[j] = dblToCol(out[j]);
+    }
+  } else {
+    *color2 = vertices[v].color;
+  }
+}
+
+//------------------------------------------------------------------------
+// GfxPatchMeshShading
+//------------------------------------------------------------------------
+
+GfxPatchMeshShading::GfxPatchMeshShading(int typeA,
+                                        GfxPatch *patchesA, int nPatchesA,
+                                        Function **funcsA, int nFuncsA):
+  GfxShading(typeA)
+{
+  int i;
+
+  patches = patchesA;
+  nPatches = nPatchesA;
+  nFuncs = nFuncsA;
+  for (i = 0; i < nFuncs; ++i) {
+    funcs[i] = funcsA[i];
+  }
+}
+
+GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading):
+  GfxShading(shading)
+{
+  int i;
+
+  nPatches = shading->nPatches;
+  patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch));
+  memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch));
+  nFuncs = shading->nFuncs;
+  for (i = 0; i < nFuncs; ++i) {
+    funcs[i] = shading->funcs[i]->copy();
+  }
+}
+
+GfxPatchMeshShading::~GfxPatchMeshShading() {
+  int i;
+
+  gfree(patches);
+  for (i = 0; i < nFuncs; ++i) {
+    delete funcs[i];
+  }
+}
+
+GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict,
+                                               Stream *str) {
+  GfxPatchMeshShading *shading;
+  Function *funcsA[gfxColorMaxComps];
+  int nFuncsA;
+  int coordBits, compBits, flagBits;
+  double xMin, xMax, yMin, yMax;
+  double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
+  double xMul, yMul;
+  double cMul[gfxColorMaxComps];
+  GfxPatch *patchesA, *p;
+  int nComps, nPatchesA, patchesSize, nPts, nColors;
+  Guint flag;
+  double x[16], y[16];
+  Guint xi, yi;
+  GfxColorComp c[4][gfxColorMaxComps];
+  Guint ci[4];
+  GfxShadingBitBuf *bitBuf;
+  Object obj1, obj2;
+  int i, j;
+
+  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+    coordBits = obj1.getInt();
+  } else {
+    error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
+    goto err2;
+  }
+  obj1.free();
+  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+    compBits = obj1.getInt();
+  } else {
+    error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
+    goto err2;
+  }
+  obj1.free();
+  if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+    flagBits = obj1.getInt();
+  } else {
+    error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
+    goto err2;
+  }
+  obj1.free();
+  if (dict->lookup("Decode", &obj1)->isArray() &&
+      obj1.arrayGetLength() >= 6) {
+    xMin = obj1.arrayGet(0, &obj2)->getNum();
+    obj2.free();
+    xMax = obj1.arrayGet(1, &obj2)->getNum();
+    obj2.free();
+    xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
+    yMin = obj1.arrayGet(2, &obj2)->getNum();
+    obj2.free();
+    yMax = obj1.arrayGet(3, &obj2)->getNum();
+    obj2.free();
+    yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
+    for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
+      cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
+      obj2.free();
+      cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
+      obj2.free();
+      cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
+    }
+    nComps = i;
+  } else {
+    error(-1, "Missing or invalid Decode array in shading dictionary");
+    goto err2;
+  }
+  obj1.free();
+
+  if (!dict->lookup("Function", &obj1)->isNull()) {
+    if (obj1.isArray()) {
+      nFuncsA = obj1.arrayGetLength();
+      if (nFuncsA > gfxColorMaxComps) {
+       error(-1, "Invalid Function array in shading dictionary");
+       goto err1;
+      }
+      for (i = 0; i < nFuncsA; ++i) {
+       obj1.arrayGet(i, &obj2);
+       if (!(funcsA[i] = Function::parse(&obj2))) {
+         obj1.free();
+         obj2.free();
+         goto err1;
+       }
+       obj2.free();
+      }
+    } else {
+      nFuncsA = 1;
+      if (!(funcsA[0] = Function::parse(&obj1))) {
+       obj1.free();
+       goto err1;
+      }
+    }
+  } else {
+    nFuncsA = 0;
+  }
+  obj1.free();
+
+  nPatchesA = 0;
+  patchesA = NULL;
+  patchesSize = 0;
+  bitBuf = new GfxShadingBitBuf(str);
+  while (1) {
+    if (!bitBuf->getBits(flagBits, &flag)) {
+      break;
+    }
+    if (typeA == 6) {
+      switch (flag) {
+      case 0: nPts = 12; nColors = 4; break;
+      case 1:
+      case 2:
+      case 3:
+      default: nPts =  8; nColors = 2; break;
+      }
+    } else {
+      switch (flag) {
+      case 0: nPts = 16; nColors = 4; break;
+      case 1:
+      case 2:
+      case 3:
+      default: nPts = 12; nColors = 2; break;
+      }
+    }
+    for (i = 0; i < nPts; ++i) {
+      if (!bitBuf->getBits(coordBits, &xi) ||
+         !bitBuf->getBits(coordBits, &yi)) {
+       break;
+      }
+      x[i] = xMin + xMul * (double)xi;
+      y[i] = yMin + yMul * (double)yi;
+    }
+    if (i < nPts) {
+      break;
+    }
+    for (i = 0; i < nColors; ++i) {
+      for (j = 0; j < nComps; ++j) {
+       if (!bitBuf->getBits(compBits, &ci[j])) {
+         break;
+       }
+       c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]);
+      }
+      if (j < nComps) {
+       break;
+      }
+    }
+    if (i < nColors) {
+      break;
+    }
+    if (nPatchesA == patchesSize) {
+      patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize;
+      patchesA = (GfxPatch *)greallocn(patchesA,
+                                      patchesSize, sizeof(GfxPatch));
+    }
+    p = &patchesA[nPatchesA];
+    if (typeA == 6) {
+      switch (flag) {
+      case 0:
+       p->x[0][0] = x[0];
+       p->y[0][0] = y[0];
+       p->x[0][1] = x[1];
+       p->y[0][1] = y[1];
+       p->x[0][2] = x[2];
+       p->y[0][2] = y[2];
+       p->x[0][3] = x[3];
+       p->y[0][3] = y[3];
+       p->x[1][3] = x[4];
+       p->y[1][3] = y[4];
+       p->x[2][3] = x[5];
+       p->y[2][3] = y[5];
+       p->x[3][3] = x[6];
+       p->y[3][3] = y[6];
+       p->x[3][2] = x[7];
+       p->y[3][2] = y[7];
+       p->x[3][1] = x[8];
+       p->y[3][1] = y[8];
+       p->x[3][0] = x[9];
+       p->y[3][0] = y[9];
+       p->x[2][0] = x[10];
+       p->y[2][0] = y[10];
+       p->x[1][0] = x[11];
+       p->y[1][0] = y[11];
+       for (j = 0; j < nComps; ++j) {
+         p->color[0][0].c[j] = c[0][j];
+         p->color[0][1].c[j] = c[1][j];
+         p->color[1][1].c[j] = c[2][j];
+         p->color[1][0].c[j] = c[3][j];
+       }
+       break;
+      case 1:
+       p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
+       p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
+       p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
+       p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
+       p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
+       p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
+       p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
+       p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
+       p->x[1][3] = x[0];
+       p->y[1][3] = y[0];
+       p->x[2][3] = x[1];
+       p->y[2][3] = y[1];
+       p->x[3][3] = x[2];
+       p->y[3][3] = y[2];
+       p->x[3][2] = x[3];
+       p->y[3][2] = y[3];
+       p->x[3][1] = x[4];
+       p->y[3][1] = y[4];
+       p->x[3][0] = x[5];
+       p->y[3][0] = y[5];
+       p->x[2][0] = x[6];
+       p->y[2][0] = y[6];
+       p->x[1][0] = x[7];
+       p->y[1][0] = y[7];
+       for (j = 0; j < nComps; ++j) {
+         p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
+         p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+         p->color[1][1].c[j] = c[0][j];
+         p->color[1][0].c[j] = c[1][j];
+       }
+       break;
+      case 2:
+       p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
+       p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
+       p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
+       p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
+       p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
+       p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
+       p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
+       p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
+       p->x[1][3] = x[0];
+       p->y[1][3] = y[0];
+       p->x[2][3] = x[1];
+       p->y[2][3] = y[1];
+       p->x[3][3] = x[2];
+       p->y[3][3] = y[2];
+       p->x[3][2] = x[3];
+       p->y[3][2] = y[3];
+       p->x[3][1] = x[4];
+       p->y[3][1] = y[4];
+       p->x[3][0] = x[5];
+       p->y[3][0] = y[5];
+       p->x[2][0] = x[6];
+       p->y[2][0] = y[6];
+       p->x[1][0] = x[7];
+       p->y[1][0] = y[7];
+       for (j = 0; j < nComps; ++j) {
+         p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+         p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+         p->color[1][1].c[j] = c[0][j];
+         p->color[1][0].c[j] = c[1][j];
+       }
+       break;
+      case 3:
+       p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
+       p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
+       p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
+       p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
+       p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
+       p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
+       p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
+       p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
+       p->x[1][3] = x[0];
+       p->y[1][3] = y[0];
+       p->x[2][3] = x[1];
+       p->y[2][3] = y[1];
+       p->x[3][3] = x[2];
+       p->y[3][3] = y[2];
+       p->x[3][2] = x[3];
+       p->y[3][2] = y[3];
+       p->x[3][1] = x[4];
+       p->y[3][1] = y[4];
+       p->x[3][0] = x[5];
+       p->y[3][0] = y[5];
+       p->x[2][0] = x[6];
+       p->y[2][0] = y[6];
+       p->x[1][0] = x[7];
+       p->y[1][0] = y[7];
+       for (j = 0; j < nComps; ++j) {
+         p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+         p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
+         p->color[1][1].c[j] = c[0][j];
+         p->color[1][0].c[j] = c[1][j];
+       }
+       break;
+      }
+    } else {
+      switch (flag) {
+      case 0:
+       p->x[0][0] = x[0];
+       p->y[0][0] = y[0];
+       p->x[0][1] = x[1];
+       p->y[0][1] = y[1];
+       p->x[0][2] = x[2];
+       p->y[0][2] = y[2];
+       p->x[0][3] = x[3];
+       p->y[0][3] = y[3];
+       p->x[1][3] = x[4];
+       p->y[1][3] = y[4];
+       p->x[2][3] = x[5];
+       p->y[2][3] = y[5];
+       p->x[3][3] = x[6];
+       p->y[3][3] = y[6];
+       p->x[3][2] = x[7];
+       p->y[3][2] = y[7];
+       p->x[3][1] = x[8];
+       p->y[3][1] = y[8];
+       p->x[3][0] = x[9];
+       p->y[3][0] = y[9];
+       p->x[2][0] = x[10];
+       p->y[2][0] = y[10];
+       p->x[1][0] = x[11];
+       p->y[1][0] = y[11];
+       p->x[1][1] = x[12];
+       p->y[1][1] = y[12];
+       p->x[1][2] = x[13];
+       p->y[1][2] = y[13];
+       p->x[2][2] = x[14];
+       p->y[2][2] = y[14];
+       p->x[2][1] = x[15];
+       p->y[2][1] = y[15];
+       for (j = 0; j < nComps; ++j) {
+         p->color[0][0].c[j] = c[0][j];
+         p->color[0][1].c[j] = c[1][j];
+         p->color[1][1].c[j] = c[2][j];
+         p->color[1][0].c[j] = c[3][j];
+       }
+       break;
+      case 1:
+       p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
+       p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
+       p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
+       p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
+       p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
+       p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
+       p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
+       p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
+       p->x[1][3] = x[0];
+       p->y[1][3] = y[0];
+       p->x[2][3] = x[1];
+       p->y[2][3] = y[1];
+       p->x[3][3] = x[2];
+       p->y[3][3] = y[2];
+       p->x[3][2] = x[3];
+       p->y[3][2] = y[3];
+       p->x[3][1] = x[4];
+       p->y[3][1] = y[4];
+       p->x[3][0] = x[5];
+       p->y[3][0] = y[5];
+       p->x[2][0] = x[6];
+       p->y[2][0] = y[6];
+       p->x[1][0] = x[7];
+       p->y[1][0] = y[7];
+       p->x[1][1] = x[8];
+       p->y[1][1] = y[8];
+       p->x[1][2] = x[9];
+       p->y[1][2] = y[9];
+       p->x[2][2] = x[10];
+       p->y[2][2] = y[10];
+       p->x[2][1] = x[11];
+       p->y[2][1] = y[11];
+       for (j = 0; j < nComps; ++j) {
+         p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
+         p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+         p->color[1][1].c[j] = c[0][j];
+         p->color[1][0].c[j] = c[1][j];
+       }
+       break;
+      case 2:
+       p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
+       p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
+       p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
+       p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
+       p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
+       p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
+       p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
+       p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
+       p->x[1][3] = x[0];
+       p->y[1][3] = y[0];
+       p->x[2][3] = x[1];
+       p->y[2][3] = y[1];
+       p->x[3][3] = x[2];
+       p->y[3][3] = y[2];
+       p->x[3][2] = x[3];
+       p->y[3][2] = y[3];
+       p->x[3][1] = x[4];
+       p->y[3][1] = y[4];
+       p->x[3][0] = x[5];
+       p->y[3][0] = y[5];
+       p->x[2][0] = x[6];
+       p->y[2][0] = y[6];
+       p->x[1][0] = x[7];
+       p->y[1][0] = y[7];
+       p->x[1][1] = x[8];
+       p->y[1][1] = y[8];
+       p->x[1][2] = x[9];
+       p->y[1][2] = y[9];
+       p->x[2][2] = x[10];
+       p->y[2][2] = y[10];
+       p->x[2][1] = x[11];
+       p->y[2][1] = y[11];
+       for (j = 0; j < nComps; ++j) {
+         p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+         p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+         p->color[1][1].c[j] = c[0][j];
+         p->color[1][0].c[j] = c[1][j];
+       }
+       break;
+      case 3:
+       p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
+       p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
+       p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
+       p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
+       p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
+       p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
+       p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
+       p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
+       p->x[1][3] = x[0];
+       p->y[1][3] = y[0];
+       p->x[2][3] = x[1];
+       p->y[2][3] = y[1];
+       p->x[3][3] = x[2];
+       p->y[3][3] = y[2];
+       p->x[3][2] = x[3];
+       p->y[3][2] = y[3];
+       p->x[3][1] = x[4];
+       p->y[3][1] = y[4];
+       p->x[3][0] = x[5];
+       p->y[3][0] = y[5];
+       p->x[2][0] = x[6];
+       p->y[2][0] = y[6];
+       p->x[1][0] = x[7];
+       p->y[1][0] = y[7];
+       p->x[1][1] = x[8];
+       p->y[1][1] = y[8];
+       p->x[1][2] = x[9];
+       p->y[1][2] = y[9];
+       p->x[2][2] = x[10];
+       p->y[2][2] = y[10];
+       p->x[2][1] = x[11];
+       p->y[2][1] = y[11];
+       for (j = 0; j < nComps; ++j) {
+         p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+         p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
+         p->color[1][1].c[j] = c[0][j];
+         p->color[1][0].c[j] = c[1][j];
+       }
+       break;
+      }
+    }
+    ++nPatchesA;
+    bitBuf->flushBits();
+  }
+  delete bitBuf;
+
+  if (typeA == 6) {
+    for (i = 0; i < nPatchesA; ++i) {
+      p = &patchesA[i];
+      p->x[1][1] = (-4 * p->x[0][0]
+                   +6 * (p->x[0][1] + p->x[1][0])
+                   -2 * (p->x[0][3] + p->x[3][0])
+                   +3 * (p->x[3][1] + p->x[1][3])
+                   - p->x[3][3]) / 9;
+      p->y[1][1] = (-4 * p->y[0][0]
+                   +6 * (p->y[0][1] + p->y[1][0])
+                   -2 * (p->y[0][3] + p->y[3][0])
+                   +3 * (p->y[3][1] + p->y[1][3])
+                   - p->y[3][3]) / 9;
+      p->x[1][2] = (-4 * p->x[0][3]
+                   +6 * (p->x[0][2] + p->x[1][3])
+                   -2 * (p->x[0][0] + p->x[3][3])
+                   +3 * (p->x[3][2] + p->x[1][0])
+                   - p->x[3][0]) / 9;
+      p->y[1][2] = (-4 * p->y[0][3]
+                   +6 * (p->y[0][2] + p->y[1][3])
+                   -2 * (p->y[0][0] + p->y[3][3])
+                   +3 * (p->y[3][2] + p->y[1][0])
+                   - p->y[3][0]) / 9;
+      p->x[2][1] = (-4 * p->x[3][0]
+                   +6 * (p->x[3][1] + p->x[2][0])
+                   -2 * (p->x[3][3] + p->x[0][0])
+                   +3 * (p->x[0][1] + p->x[2][3])
+                   - p->x[0][3]) / 9;
+      p->y[2][1] = (-4 * p->y[3][0]
+                   +6 * (p->y[3][1] + p->y[2][0])
+                   -2 * (p->y[3][3] + p->y[0][0])
+                   +3 * (p->y[0][1] + p->y[2][3])
+                   - p->y[0][3]) / 9;
+      p->x[2][2] = (-4 * p->x[3][3]
+                   +6 * (p->x[3][2] + p->x[2][3])
+                   -2 * (p->x[3][0] + p->x[0][3])
+                   +3 * (p->x[0][2] + p->x[2][0])
+                   - p->x[0][0]) / 9;
+      p->y[2][2] = (-4 * p->y[3][3]
+                   +6 * (p->y[3][2] + p->y[2][3])
+                   -2 * (p->y[3][0] + p->y[0][3])
+                   +3 * (p->y[0][2] + p->y[2][0])
+                   - p->y[0][0]) / 9;
+    }
+  }
+
+  shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA,
+                                   funcsA, nFuncsA);
+  if (!shading->init(dict)) {
+    delete shading;
+    return NULL;
+  }
+  return shading;
+
+ err2:
+  obj1.free();
+ err1:
+  return NULL;
+}
+
+GfxShading *GfxPatchMeshShading::copy() {
+  return new GfxPatchMeshShading(this);
+}
+
+//------------------------------------------------------------------------
 // GfxImageColorMap
 //------------------------------------------------------------------------
 
@@ -2005,14 +3105,12 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
   double x[gfxColorMaxComps];
   double y[gfxColorMaxComps];
   int i, j, k;
-  int maxPixelForAlloc;
 
   ok = gTrue;
 
   // bits per component and color space
   bits = bitsA;
   maxPixel = (1 << bits) - 1;
-  maxPixelForAlloc = (1 << (bits>8?bits:8));
   colorSpace = colorSpaceA;
 
   // get decode map
@@ -2049,6 +3147,9 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
   // Optimization: for Indexed and Separation color spaces (which have
   // only one component), we store color values in the lookup table
   // rather than component values.
+  for (k = 0; k < gfxColorMaxComps; ++k) {
+    lookup[k] = NULL;
+  }
   colorSpace2 = NULL;
   nComps2 = 0;
   if (colorSpace->getMode() == csIndexed) {
@@ -2059,39 +3160,43 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
     colorSpace2 = indexedCS->getBase();
     indexHigh = indexedCS->getIndexHigh();
     nComps2 = colorSpace2->getNComps();
-    lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
     lookup2 = indexedCS->getLookup();
     colorSpace2->getDefaultRanges(x, y, indexHigh);
-    for (i = 0; i <= maxPixel; ++i) {
-      j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
-      if (j < 0) {
-       j = 0;
-      } else if (j > indexHigh) {
-       j = indexHigh;
-      }
-      for (k = 0; k < nComps2; ++k) {
-       lookup[i*nComps2 + k] = x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k];
+    for (k = 0; k < nComps2; ++k) {
+      lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+                                          sizeof(GfxColorComp));
+      for (i = 0; i <= maxPixel; ++i) {
+       j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
+       if (j < 0) {
+         j = 0;
+       } else if (j > indexHigh) {
+         j = indexHigh;
+       }
+       lookup[k][i] =
+           dblToCol(x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]);
       }
     }
   } else if (colorSpace->getMode() == csSeparation) {
     sepCS = (GfxSeparationColorSpace *)colorSpace;
     colorSpace2 = sepCS->getAlt();
     nComps2 = colorSpace2->getNComps();
-    lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
     sepFunc = sepCS->getFunc();
-    for (i = 0; i <= maxPixel; ++i) {
-      x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
-      sepFunc->transform(x, y);
-      for (k = 0; k < nComps2; ++k) {
-       lookup[i*nComps2 + k] = y[k];
+    for (k = 0; k < nComps2; ++k) {
+      lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+                                          sizeof(GfxColorComp));
+      for (i = 0; i <= maxPixel; ++i) {
+       x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
+       sepFunc->transform(x, y);
+       lookup[k][i] = dblToCol(y[k]);
       }
     }
   } else {
-    lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps * sizeof(double));
-    for (i = 0; i <= maxPixel; ++i) {
-      for (k = 0; k < nComps; ++k) {
-       lookup[i*nComps + k] = decodeLow[k] +
-                                (i * decodeRange[k]) / maxPixel;
+    for (k = 0; k < nComps; ++k) {
+      lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+                                          sizeof(GfxColorComp));
+      for (i = 0; i <= maxPixel; ++i) {
+       lookup[k][i] = dblToCol(decodeLow[k] +
+                               (i * decodeRange[k]) / maxPixel);
       }
     }
   }
@@ -2105,26 +3210,35 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
 }
 
 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
-  int n, i;
+  int n, i, k;
 
   colorSpace = colorMap->colorSpace->copy();
   bits = colorMap->bits;
   nComps = colorMap->nComps;
   nComps2 = colorMap->nComps2;
   colorSpace2 = NULL;
-  lookup = NULL;
+  for (k = 0; k < gfxColorMaxComps; ++k) {
+    lookup[k] = NULL;
+  }
   n = 1 << bits;
   if (colorSpace->getMode() == csIndexed) {
     colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
-    n = n * nComps2 * sizeof(double);
+    for (k = 0; k < nComps2; ++k) {
+      lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+      memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+    }
   } else if (colorSpace->getMode() == csSeparation) {
     colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
-    n = n * nComps2 * sizeof(double);
+    for (k = 0; k < nComps2; ++k) {
+      lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+      memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+    }
   } else {
-    n = n * nComps * sizeof(double);
+    for (k = 0; k < nComps; ++k) {
+      lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+      memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+    }
   }
-  lookup = (double *)gmalloc(n);
-  memcpy(lookup, colorMap->lookup, n);
   for (i = 0; i < nComps; ++i) {
     decodeLow[i] = colorMap->decodeLow[i];
     decodeRange[i] = colorMap->decodeRange[i];
@@ -2133,24 +3247,26 @@ GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
 }
 
 GfxImageColorMap::~GfxImageColorMap() {
+  int i;
+
   delete colorSpace;
-  gfree(lookup);
+  for (i = 0; i < gfxColorMaxComps; ++i) {
+    gfree(lookup[i]);
+  }
 }
 
-void GfxImageColorMap::getGray(Guchar *x, double *gray) {
+void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) {
   GfxColor color;
-  double *p;
   int i;
 
   if (colorSpace2) {
-    p = &lookup[x[0] * nComps2];
     for (i = 0; i < nComps2; ++i) {
-      color.c[i] = *p++;
+      color.c[i] = lookup[i][x[0]];
     }
     colorSpace2->getGray(&color, gray);
   } else {
     for (i = 0; i < nComps; ++i) {
-      color.c[i] = lookup[x[i] * nComps + i];
+      color.c[i] = lookup[i][x[i]];
     }
     colorSpace->getGray(&color, gray);
   }
@@ -2158,18 +3274,16 @@ void GfxImageColorMap::getGray(Guchar *x, double *gray) {
 
 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
   GfxColor color;
-  double *p;
   int i;
 
   if (colorSpace2) {
-    p = &lookup[x[0] * nComps2];
     for (i = 0; i < nComps2; ++i) {
-      color.c[i] = *p++;
+      color.c[i] = lookup[i][x[0]];
     }
     colorSpace2->getRGB(&color, rgb);
   } else {
     for (i = 0; i < nComps; ++i) {
-      color.c[i] = lookup[x[i] * nComps + i];
+      color.c[i] = lookup[i][x[i]];
     }
     colorSpace->getRGB(&color, rgb);
   }
@@ -2177,18 +3291,16 @@ void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
 
 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
   GfxColor color;
-  double *p;
   int i;
 
   if (colorSpace2) {
-    p = &lookup[x[0] * nComps2];
     for (i = 0; i < nComps2; ++i) {
-      color.c[i] = *p++;
+      color.c[i] = lookup[i][x[0]];
     }
     colorSpace2->getCMYK(&color, cmyk);
   } else {
     for (i = 0; i < nComps; ++i) {
-      color.c[i] = lookup[x[i] * nComps + i];
+      color.c[i] = lookup[i][x[i]];
     }
     colorSpace->getCMYK(&color, cmyk);
   }
@@ -2199,7 +3311,7 @@ void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
 
   maxPixel = (1 << bits) - 1;
   for (i = 0; i < nComps; ++i) {
-    color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel;
+    color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel);
   }
 }
 
@@ -2209,9 +3321,9 @@ void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
 
 GfxSubpath::GfxSubpath(double x1, double y1) {
   size = 16;
-  x = (double *)gmalloc(size * sizeof(double));
-  y = (double *)gmalloc(size * sizeof(double));
-  curve = (GBool *)gmalloc(size * sizeof(GBool));
+  x = (double *)gmallocn(size, sizeof(double));
+  y = (double *)gmallocn(size, sizeof(double));
+  curve = (GBool *)gmallocn(size, sizeof(GBool));
   n = 1;
   x[0] = x1;
   y[0] = y1;
@@ -2229,9 +3341,9 @@ GfxSubpath::~GfxSubpath() {
 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
   size = subpath->size;
   n = subpath->n;
-  x = (double *)gmalloc(size * sizeof(double));
-  y = (double *)gmalloc(size * sizeof(double));
-  curve = (GBool *)gmalloc(size * sizeof(GBool));
+  x = (double *)gmallocn(size, sizeof(double));
+  y = (double *)gmallocn(size, sizeof(double));
+  curve = (GBool *)gmallocn(size, sizeof(GBool));
   memcpy(x, subpath->x, n * sizeof(double));
   memcpy(y, subpath->y, n * sizeof(double));
   memcpy(curve, subpath->curve, n * sizeof(GBool));
@@ -2241,9 +3353,9 @@ GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
 void GfxSubpath::lineTo(double x1, double y1) {
   if (n >= size) {
     size += 16;
-    x = (double *)grealloc(x, size * sizeof(double));
-    y = (double *)grealloc(y, size * sizeof(double));
-    curve = (GBool *)grealloc(curve, size * sizeof(GBool));
+    x = (double *)greallocn(x, size, sizeof(double));
+    y = (double *)greallocn(y, size, sizeof(double));
+    curve = (GBool *)greallocn(curve, size, sizeof(GBool));
   }
   x[n] = x1;
   y[n] = y1;
@@ -2255,9 +3367,9 @@ void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
                         double x3, double y3) {
   if (n+3 > size) {
     size += 16;
-    x = (double *)grealloc(x, size * sizeof(double));
-    y = (double *)grealloc(y, size * sizeof(double));
-    curve = (GBool *)grealloc(curve, size * sizeof(GBool));
+    x = (double *)greallocn(x, size, sizeof(double));
+    y = (double *)greallocn(y, size, sizeof(double));
+    curve = (GBool *)greallocn(curve, size, sizeof(GBool));
   }
   x[n] = x1;
   y[n] = y1;
@@ -2291,7 +3403,7 @@ GfxPath::GfxPath() {
   size = 16;
   n = 0;
   firstX = firstY = 0;
-  subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
+  subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
 }
 
 GfxPath::~GfxPath() {
@@ -2312,7 +3424,7 @@ GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
   firstY = firstY1;
   size = size1;
   n = n1;
-  subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
+  subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
   for (i = 0; i < n; ++i)
     subpaths[i] = subpaths1[i]->copy();
 }
@@ -2328,7 +3440,7 @@ void GfxPath::lineTo(double x, double y) {
     if (n >= size) {
       size += 16;
       subpaths = (GfxSubpath **)
-                  grealloc(subpaths, size * sizeof(GfxSubpath *));
+                  greallocn(subpaths, size, sizeof(GfxSubpath *));
     }
     subpaths[n] = new GfxSubpath(firstX, firstY);
     ++n;
@@ -2343,7 +3455,7 @@ void GfxPath::curveTo(double x1, double y1, double x2, double y2,
     if (n >= size) {
       size += 16;
       subpaths = (GfxSubpath **)
-                  grealloc(subpaths, size * sizeof(GfxSubpath *));
+                  greallocn(subpaths, size, sizeof(GfxSubpath *));
     }
     subpaths[n] = new GfxSubpath(firstX, firstY);
     ++n;
@@ -2359,7 +3471,7 @@ void GfxPath::close() {
     if (n >= size) {
       size += 16;
       subpaths = (GfxSubpath **)
-                  grealloc(subpaths, size * sizeof(GfxSubpath *));
+                  greallocn(subpaths, size, sizeof(GfxSubpath *));
     }
     subpaths[n] = new GfxSubpath(firstX, firstY);
     ++n;
@@ -2374,7 +3486,7 @@ void GfxPath::append(GfxPath *path) {
   if (n + path->n > size) {
     size = n + path->n;
     subpaths = (GfxSubpath **)
-                 grealloc(subpaths, size * sizeof(GfxSubpath *));
+                 greallocn(subpaths, size, sizeof(GfxSubpath *));
   }
   for (i = 0; i < path->n; ++i) {
     subpaths[n++] = path->subpaths[i]->copy();
@@ -2395,9 +3507,10 @@ void GfxPath::offset(double dx, double dy) {
 //------------------------------------------------------------------------
 
 GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
-                  int rotate, GBool upsideDown) {
+                  int rotateA, GBool upsideDown) {
   double kx, ky;
 
+  rotate = rotateA;
   px1 = pageBox->x1;
   py1 = pageBox->y1;
   px2 = pageBox->x2;
@@ -2448,8 +3561,11 @@ GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
   strokeColor.c[0] = 0;
   fillPattern = NULL;
   strokePattern = NULL;
+  blendMode = gfxBlendNormal;
   fillOpacity = 1;
   strokeOpacity = 1;
+  fillOverprint = gFalse;
+  strokeOverprint = gFalse;
 
   lineWidth = 1;
   lineDash = NULL;
@@ -2523,7 +3639,7 @@ GfxState::GfxState(GfxState *state) {
     strokePattern = state->strokePattern->copy();
   }
   if (lineDashLength > 0) {
-    lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
+    lineDash = (double *)gmallocn(lineDashLength, sizeof(double));
     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
   }
   saved = NULL;
@@ -2793,3 +3909,38 @@ GfxState *GfxState::restore() {
 
   return oldState;
 }
+
+GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) {
+  Object obj2;
+  int i, j;
+
+  if (obj->isName()) {
+    for (i = 0; i < nGfxBlendModeNames; ++i) {
+      if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) {
+       *mode = gfxBlendModeNames[i].mode;
+       return gTrue;
+      }
+    }
+    return gFalse;
+  } else if (obj->isArray()) {
+    for (i = 0; i < obj->arrayGetLength(); ++i) {
+      obj->arrayGet(i, &obj2);
+      if (!obj2.isName()) {
+       obj2.free();
+       return gFalse;
+      }
+      for (j = 0; j < nGfxBlendModeNames; ++j) {
+       if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) {
+         obj2.free();
+         *mode = gfxBlendModeNames[j].mode;
+         return gTrue;
+       }
+      }
+      obj2.free();
+    }
+    *mode = gfxBlendNormal;
+    return gTrue;
+  } else {
+    return gFalse;
+  }
+}
index 882083a..44dae3f 100644 (file)
@@ -498,29 +498,6 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) {
   char buf[512];
   FILE *f2;
 
-  /* extract path */
-  if(fileName) {
-    char* cfgFileName = fileName->getCString();
-    char* pos1 = strrchr(cfgFileName, '/');
-    char* pos2 = strrchr(cfgFileName, '\\');
-    char* p = pos1>pos2?pos1:pos2;
-    int pos = p ? p-cfgFileName : -1;
-    GString*path = new GString(new GString(cfgFileName), 0, (pos < 0 ? strlen(cfgFileName): pos));
-    if(pos1>=0)
-       path->append('/');
-    else if(pos2>=0)
-       path->append('\\');
-    else
-#ifdef WIN32
-       path->append('\\');
-#else
-       path->append('/');
-#endif
-    this->path = path;
-  } else {
-    this->path = new GString();
-  }
-  
   line = 1;
   while (getLine(buf, sizeof(buf) - 1, f)) {
 
@@ -717,32 +694,6 @@ void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName,
   fclose(f);
 }
 
-static GString* qualify_filename(GString*path, GString*filename)
-{
-  GString*fullpath = 0;
-  char*prefix = "/usr/local/share/xpdf/";
-
-  if (filename->getChar(0) != '\\' && filename->getChar(0) != '/') {
-    /* relative path */
-    fullpath = path->copy();
-    fullpath->append(filename);
-  } else if (!strncmp(filename->getCString(), prefix, strlen(prefix))) {
-    /* xpdf default path */
-    char*s = strchr(filename->getCString()+strlen(prefix), '/');
-    if(s) {
-       fullpath = path->copy();
-       fullpath->append(s+1);
-    } else {
-       fullpath = filename->copy();
-    }
-  } else {
-    /* absolute path */
-    fullpath = filename->copy();
-  }
-  printf("%s -%s-> %s\n", filename->getCString(), path->getCString(), fullpath->getCString());
-  return fullpath;
-}
-
 void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName,
                                     int line) {
   GString *collection, *name, *old;
@@ -754,12 +705,10 @@ void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName,
   }
   collection = (GString *)tokens->get(1);
   name = (GString *)tokens->get(2);
-
   if ((old = (GString *)cidToUnicodes->remove(collection))) {
     delete old;
   }
-
-  cidToUnicodes->add(collection->copy(), qualify_filename(this->path, name));
+  cidToUnicodes->add(collection->copy(), name->copy());
 }
 
 void GlobalParams::parseUnicodeToUnicode(GList *tokens, GString *fileName,
@@ -776,8 +725,7 @@ void GlobalParams::parseUnicodeToUnicode(GList *tokens, GString *fileName,
   if ((old = (GString *)unicodeToUnicodes->remove(font))) {
     delete old;
   }
-
-  unicodeToUnicodes->add(font->copy(), qualify_filename(this->path, file));
+  unicodeToUnicodes->add(font->copy(), file->copy());
 }
 
 void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName,
@@ -794,8 +742,7 @@ void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName,
   if ((old = (GString *)unicodeMaps->remove(encodingName))) {
     delete old;
   }
-
-  unicodeMaps->add(encodingName->copy(), qualify_filename(this->path, name));
+  unicodeMaps->add(encodingName->copy(), name->copy());
 }
 
 void GlobalParams::parseCMapDir(GList *tokens, GString *fileName, int line) {
@@ -813,30 +760,23 @@ void GlobalParams::parseCMapDir(GList *tokens, GString *fileName, int line) {
     list = new GList();
     cMapDirs->add(collection->copy(), list);
   }
-
-  list->append(qualify_filename(this->path, dir));
+  list->append(dir->copy());
 }
 
 void GlobalParams::parseToUnicodeDir(GList *tokens, GString *fileName,
                                     int line) {
-  GString *dir;
-
   if (tokens->getLength() != 2) {
     error(-1, "Bad 'toUnicodeDir' config file command (%s:%d)",
          fileName->getCString(), line);
     return;
   }
-
-  dir = (GString *)tokens->get(1);
-
-  toUnicodeDirs->append(qualify_filename(this->path, dir));
+  toUnicodeDirs->append(((GString *)tokens->get(1))->copy());
 }
 
 void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash,
                                    DisplayFontParamKind kind,
                                    GString *fileName, int line) {
   DisplayFontParam *param, *old;
-  GString *file;
 
   if (tokens->getLength() < 2) {
     goto err1;
@@ -848,15 +788,13 @@ void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash,
     if (tokens->getLength() != 3) {
       goto err2;
     }
-    file = (GString *)tokens->get(2);
-    param->t1.fileName = qualify_filename(this->path, file);
+    param->t1.fileName = ((GString *)tokens->get(2))->copy();
     break;
   case displayFontTT:
     if (tokens->getLength() != 3) {
       goto err2;
     }
-    file = (GString *)tokens->get(2);
-    param->tt.fileName = qualify_filename(this->path, file);
+    param->tt.fileName = ((GString *)tokens->get(2))->copy();
     break;
   }
 
index e14ad4f..1fdef63 100644 (file)
@@ -212,10 +212,10 @@ public:
 
   void addSecurityHandler(XpdfSecurityHandler *handler);
   XpdfSecurityHandler *getSecurityHandler(char *name);
-  void parseFile(GString *fileName, FILE *f);
 
 private:
 
+  void parseFile(GString *fileName, FILE *f);
   void parseNameToUnicode(GList *tokens, GString *fileName, int line);
   void parseCIDToUnicode(GList *tokens, GString *fileName, int line);
   void parseUnicodeToUnicode(GList *tokens, GString *fileName, int line);
@@ -246,10 +246,6 @@ private:
   GBool loadPlugin(char *type, char *name);
 #endif
 
-  //----- config file base path
-
-  GString*path;
-
   //----- static tables
 
   NameToCharCode *             // mapping from char name to
index 327aa24..fdb0edc 100644 (file)
@@ -61,9 +61,6 @@ public:
   // will be reduced to a series of other drawing operations.
   virtual GBool useShadedFills() { return gFalse; }
 
-  // Is this device able to draw gradients?
-  virtual GBool useGradients() = 0;
-
   // Does this device use beginType3Char/endType3Char?  Otherwise,
   // text in Type 3 fonts will be drawn with drawChar/drawString.
   virtual GBool interpretType3Chars() = 0;
@@ -77,7 +74,7 @@ public:
   virtual void setDefaultCTM(double *ctm);
 
   // Start a page.
-  virtual void startPage(int pageNum, GfxState *state, double x1,double y1,double x2,double y2) {}
+  virtual void startPage(int pageNum, GfxState *state) {}
 
   // End a page.
   virtual void endPage() {}
index 5c2ae8b..6ef8433 100644 (file)
@@ -66,19 +66,6 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
     cropBox = mediaBox;
   }
 
-  /* if the crop box is larger than the media box, cut it down to 
-     media box size */
-  if(haveCropBox &&
-     mediaBox.x1 <= cropBox.x2 &&
-     mediaBox.y1 <= cropBox.y2 &&
-     cropBox.x1 <= mediaBox.x2 &&
-     cropBox.y1 <= mediaBox.y2) {
-      if(mediaBox.x1 >= cropBox.x1) cropBox.x1 = mediaBox.x1;
-      if(mediaBox.y1 >= cropBox.y1) cropBox.y1 = mediaBox.y1;
-      if(mediaBox.x2 <= cropBox.x2) cropBox.x2 = mediaBox.x2;
-      if(mediaBox.y2 <= cropBox.y2) cropBox.y2 = mediaBox.y2;
-  }
-
   // other boxes
   bleedBox = cropBox;
   readBox(dict, "BleedBox", &bleedBox);
index 7a663d3..3306279 100644 (file)
@@ -17,8 +17,6 @@
 #include <stddef.h>
 #ifndef WIN32
 #include <unistd.h>
-#else
-extern "C" int unlink(char *filename);
 #endif
 #include <string.h>
 #include <ctype.h>
index f21e311..4c8f756 100644 (file)
 
 // user config file name, relative to the user's home directory
 #if defined(VMS) || (defined(WIN32) && !defined(__CYGWIN32__))
-#define xpdfUserConfigFile "pdf2swf.conf"
+#define xpdfUserConfigFile "xpdfrc"
 #else
-#define xpdfUserConfigFile ".pdf2swf.conf"
+#define xpdfUserConfigFile ".xpdfrc"
 #endif
 
 // system config file name (set via the configure script)
-#ifndef WIN32
-#define xpdfSysConfigFile "/etc/pdf2swf.conf"
+#ifdef SYSTEM_XPDFRC
+#define xpdfSysConfigFile SYSTEM_XPDFRC
 #else
 // under Windows, we get the directory with the executable and then
 // append this file name
-#define xpdfSysConfigFile "pdf2swf.conf"
+#define xpdfSysConfigFile "xpdfrc"
 #endif
 
 //------------------------------------------------------------------------
index 5fa0762..11f5cf6 100644 (file)
@@ -437,52 +437,6 @@ time_t getModTime(char *fileName) {
 #endif
 }
 
-static char* getTempDir()
-{
-#ifdef WIN32
-    char*dir = getenv("TMP");
-    if(!dir) dir = getenv("TEMP");
-    if(!dir) dir = getenv("tmp");
-    if(!dir) dir = getenv("temp");
-    if(!dir) dir = "C:\\";
-#else
-    char* dir = "/tmp/";
-#endif
-    return dir;
-}
-
-char* mktmpname(char*ptr) {
-    static char tmpbuf[128];
-    char*dir = getTempDir();
-    int l = strlen(dir);
-    char*sep = "";
-    if(!ptr)
-       ptr = tmpbuf;
-    if(l && dir[l-1]!='/' && dir[l-1]!='\\') {
-#ifdef WIN32
-       sep = "\\";
-#else
-       sep = "/";
-#endif
-    }
-
- //   used to be mktemp. This does remove the warnings, but
- //   It's not exactly an improvement.
-#ifdef HAVE_LRAND48
-    sprintf(ptr, "%s%s%08x%08x",dir,sep,lrand48(),lrand48());
-#else
-#   ifdef HAVE_RAND
-       sprintf(ptr, "%s%s%08x%08x",dir,sep,rand(),rand());
-#   else
-       static int count = 1;
-       sprintf(ptr, "%s%s%08x%04x%04x",dir,sep,time(0),(unsigned int)tmpbuf^((unsigned int)tmpbuf)>>16,count);
-       count ++;
-#   endif
-#endif
-     return ptr;
-}
-
-
 GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
 #if defined(WIN32)
   //---------- Win32 ----------
@@ -509,7 +463,7 @@ GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
   // with this file name after the tmpnam call and before the fopen
   // call.  I will happily accept fixes to this function for non-Unix
   // OSs.
-  if (!(s = mktmpname(NULL))) {
+  if (!(s = tmpnam(NULL))) {
     return gFalse;
   }
   *name = new GString(s);
@@ -536,7 +490,7 @@ GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
     (*name)->append("/XXXXXX")->append(ext);
     fd = mkstemps((*name)->getCString(), strlen(ext));
 #else
-    if (!(s = mktmpname(NULL))) {
+    if (!(s = tmpnam(NULL))) {
       return gFalse;
     }
     *name = new GString(s);
@@ -553,7 +507,7 @@ GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
     (*name)->append("/XXXXXX");
     fd = mkstemp((*name)->getCString());
 #else // HAVE_MKSTEMP
-    if (!(s = mktmpname(NULL))) {
+    if (!(s = tmpnam(NULL))) {
       return gFalse;
     }
     *name = new GString(s);
index 10a4226..82f1d7a 100644 (file)
@@ -58,9 +58,6 @@ extern GString *getHomeDir();
 // Get current directory.
 extern GString *getCurrentDir();
 
-/* create a temporary filename */
-char* mktmpname(char*ptr);
-
 // Append a file name to a path string.  <path> may be an empty
 // string, denoting the current directory).  Returns <path>.
 extern GString *appendToPath(GString *path, char *fileName);