]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/GfxState.cc
Imported Xpdf 2.03 and fixed build.
[evince.git] / pdf / xpdf / GfxState.cc
index 7efd0b9ad130ee8ac561e4731ba5b344af74fa7c..d20293974753b9a12294dea87b928379f91082c7 100644 (file)
@@ -98,7 +98,7 @@ GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
     } else if (obj1.isName("Pattern")) {
       cs = GfxPatternColorSpace::parse(csObj->getArray());
     } else {
-      error(-1, "Bad color space '%s'", csObj->getName());
+      error(-1, "Bad color space");
     }
     obj1.free();
   } else {
@@ -1181,18 +1181,22 @@ GfxPattern::~GfxPattern() {
 
 GfxPattern *GfxPattern::parse(Object *obj) {
   GfxPattern *pattern;
-  Dict *dict;
   Object obj1;
 
+  if (obj->isDict()) {
+    obj->dictLookup("PatternType", &obj1);
+  } else if (obj->isStream()) {
+    obj->streamGetDict()->lookup("PatternType", &obj1);
+  } else {
+    return NULL;
+  }
   pattern = NULL;
-  if (obj->isStream()) {
-    dict = obj->streamGetDict();
-    dict->lookup("PatternType", &obj1);
-    if (obj1.isInt() && obj1.getInt() == 1) {
-      pattern = new GfxTilingPattern(dict, obj);
-    }
-    obj1.free();
+  if (obj1.isInt() && obj1.getInt() == 1) {
+    pattern = GfxTilingPattern::parse(obj);
+  } else if (obj1.isInt() && obj1.getInt() == 2) {
+    pattern = GfxShadingPattern::parse(obj);
   }
+  obj1.free();
   return pattern;
 }
 
@@ -1200,33 +1204,42 @@ GfxPattern *GfxPattern::parse(Object *obj) {
 // GfxTilingPattern
 //------------------------------------------------------------------------
 
-GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
-  GfxPattern(1)
-{
+GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
+  GfxTilingPattern *pat;
+  Dict *dict;
+  int paintTypeA, tilingTypeA;
+  double bboxA[4], matrixA[6];
+  double xStepA, yStepA;
+  Object resDictA;
   Object obj1, obj2;
   int i;
 
-  if (streamDict->lookup("PaintType", &obj1)->isInt()) {
-    paintType = obj1.getInt();
+  if (!patObj->isStream()) {
+    return NULL;
+  }
+  dict = patObj->streamGetDict();
+
+  if (dict->lookup("PaintType", &obj1)->isInt()) {
+    paintTypeA = obj1.getInt();
   } else {
-    paintType = 1;
+    paintTypeA = 1;
     error(-1, "Invalid or missing PaintType in pattern");
   }
   obj1.free();
-  if (streamDict->lookup("TilingType", &obj1)->isInt()) {
-    tilingType = obj1.getInt();
+  if (dict->lookup("TilingType", &obj1)->isInt()) {
+    tilingTypeA = obj1.getInt();
   } else {
-    tilingType = 1;
+    tilingTypeA = 1;
     error(-1, "Invalid or missing TilingType in pattern");
   }
   obj1.free();
-  bbox[0] = bbox[1] = 0;
-  bbox[2] = bbox[3] = 1;
-  if (streamDict->lookup("BBox", &obj1)->isArray() &&
+  bboxA[0] = bboxA[1] = 0;
+  bboxA[2] = bboxA[3] = 1;
+  if (dict->lookup("BBox", &obj1)->isArray() &&
       obj1.arrayGetLength() == 4) {
     for (i = 0; i < 4; ++i) {
       if (obj1.arrayGet(i, &obj2)->isNum()) {
-       bbox[i] = obj2.getNum();
+       bboxA[i] = obj2.getNum();
       }
       obj2.free();
     }
@@ -1234,39 +1247,65 @@ GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
     error(-1, "Invalid or missing BBox in pattern");
   }
   obj1.free();
-  if (streamDict->lookup("XStep", &obj1)->isNum()) {
-    xStep = obj1.getNum();
+  if (dict->lookup("XStep", &obj1)->isNum()) {
+    xStepA = obj1.getNum();
   } else {
-    xStep = 1;
+    xStepA = 1;
     error(-1, "Invalid or missing XStep in pattern");
   }
   obj1.free();
-  if (streamDict->lookup("YStep", &obj1)->isNum()) {
-    yStep = obj1.getNum();
+  if (dict->lookup("YStep", &obj1)->isNum()) {
+    yStepA = obj1.getNum();
   } else {
-    yStep = 1;
+    yStepA = 1;
     error(-1, "Invalid or missing YStep in pattern");
   }
   obj1.free();
-  if (!streamDict->lookup("Resources", &resDict)->isDict()) {
-    resDict.free();
-    resDict.initNull();
+  if (!dict->lookup("Resources", &resDictA)->isDict()) {
+    resDictA.free();
+    resDictA.initNull();
     error(-1, "Invalid or missing Resources in pattern");
   }
-  matrix[0] = 1; matrix[1] = 0;
-  matrix[2] = 0; matrix[3] = 1;
-  matrix[4] = 0; matrix[5] = 0;
-  if (streamDict->lookup("Matrix", &obj1)->isArray() &&
+  matrixA[0] = 1; matrixA[1] = 0;
+  matrixA[2] = 0; matrixA[3] = 1;
+  matrixA[4] = 0; matrixA[5] = 0;
+  if (dict->lookup("Matrix", &obj1)->isArray() &&
       obj1.arrayGetLength() == 6) {
     for (i = 0; i < 6; ++i) {
       if (obj1.arrayGet(i, &obj2)->isNum()) {
-       matrix[i] = obj2.getNum();
+       matrixA[i] = obj2.getNum();
       }
       obj2.free();
     }
   }
   obj1.free();
-  stream->copy(&contentStream);
+
+  pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
+                            &resDictA, matrixA, patObj);
+  resDictA.free();
+  return pat;
+}
+
+GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
+                                  double *bboxA, double xStepA, double yStepA,
+                                  Object *resDictA, double *matrixA,
+                                  Object *contentStreamA):
+  GfxPattern(1)
+{
+  int i;
+
+  paintType = paintTypeA;
+  tilingType = tilingTypeA;
+  for (i = 0; i < 4; ++i) {
+    bbox[i] = bboxA[i];
+  }
+  xStep = xStepA;
+  yStep = yStepA;
+  resDictA->copy(&resDict);
+  for (i = 0; i < 6; ++i) {
+    matrix[i] = matrixA[i];
+  }
+  contentStreamA->copy(&contentStream);
 }
 
 GfxTilingPattern::~GfxTilingPattern() {
@@ -1275,127 +1314,341 @@ GfxTilingPattern::~GfxTilingPattern() {
 }
 
 GfxPattern *GfxTilingPattern::copy() {
-  return new GfxTilingPattern(this);
+  return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
+                             &resDict, matrix, &contentStream);
 }
 
-GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
-  GfxPattern(1)
+//------------------------------------------------------------------------
+// GfxShadingPattern
+//------------------------------------------------------------------------
+
+GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
+  Dict *dict;
+  GfxShading *shadingA;
+  double matrixA[6];
+  Object obj1, obj2;
+  int i;
+
+  if (!patObj->isDict()) {
+    return NULL;
+  }
+  dict = patObj->getDict();
+
+  dict->lookup("Shading", &obj1);
+  shadingA = GfxShading::parse(&obj1);
+  obj1.free();
+  if (!shadingA) {
+    return NULL;
+  }
+
+  matrixA[0] = 1; matrixA[1] = 0;
+  matrixA[2] = 0; matrixA[3] = 1;
+  matrixA[4] = 0; matrixA[5] = 0;
+  if (dict->lookup("Matrix", &obj1)->isArray() &&
+      obj1.arrayGetLength() == 6) {
+    for (i = 0; i < 6; ++i) {
+      if (obj1.arrayGet(i, &obj2)->isNum()) {
+       matrixA[i] = obj2.getNum();
+      }
+      obj2.free();
+    }
+  }
+  obj1.free();
+
+  return new GfxShadingPattern(shadingA, matrixA);
+}
+
+GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
+  GfxPattern(2)
 {
-  memcpy(this, pat, sizeof(GfxTilingPattern));
-  pat->resDict.copy(&resDict);
-  pat->contentStream.copy(&contentStream);
+  int i;
+
+  shading = shadingA;
+  for (i = 0; i < 6; ++i) {
+    matrix[i] = matrixA[i];
+  }
+}
+
+GfxShadingPattern::~GfxShadingPattern() {
+  delete shading;
+}
+
+GfxPattern *GfxShadingPattern::copy() {
+  return new GfxShadingPattern(shading->copy(), matrix);
 }
 
 //------------------------------------------------------------------------
 // GfxShading
 //------------------------------------------------------------------------
 
-GfxShading::GfxShading() {
+GfxShading::GfxShading(int typeA) {
+  type = typeA;
+  colorSpace = NULL;
+}
+
+GfxShading::GfxShading(GfxShading *shading) {
+  int i;
+
+  type = shading->type;
+  colorSpace = shading->colorSpace->copy();
+  for (i = 0; i < gfxColorMaxComps; ++i) {
+    background.c[i] = shading->background.c[i];
+  }
+  hasBackground = shading->hasBackground;
+  xMin = shading->xMin;
+  yMin = shading->yMin;
+  xMax = shading->xMax;
+  yMax = shading->yMax;
+  hasBBox = shading->hasBBox;
 }
 
 GfxShading::~GfxShading() {
-  delete colorSpace;
+  if (colorSpace) {
+    delete colorSpace;
+  }
 }
 
 GfxShading *GfxShading::parse(Object *obj) {
   GfxShading *shading;
+  Dict *dict;
   int typeA;
-  GfxColorSpace *colorSpaceA;
-  GfxColor backgroundA;
-  GBool hasBackgroundA;
-  double xMinA, yMinA, xMaxA, yMaxA;
-  GBool hasBBoxA;
-  Object obj1, obj2;
-  int i;
+  Object obj1;
 
-  shading = NULL;
   if (obj->isDict()) {
+    dict = obj->getDict();
+  } else if (obj->isStream()) {
+    dict = obj->streamGetDict();
+  } else {
+    return NULL;
+  }
 
-    if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
-      error(-1, "Invalid ShadingType in shading dictionary");
-      obj1.free();
-      goto err1;
-    }
-    typeA = obj1.getInt();
+  if (!dict->lookup("ShadingType", &obj1)->isInt()) {
+    error(-1, "Invalid ShadingType in shading dictionary");
     obj1.free();
+    return NULL;
+  }
+  typeA = obj1.getInt();
+  obj1.free();
 
-    obj->dictLookup("ColorSpace", &obj1);
-    if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
-      error(-1, "Bad color space in shading dictionary");
-      obj1.free();
-      goto err1;
-    }
-    obj1.free();
+  switch (typeA) {
+  case 1:
+    shading = GfxFunctionShading::parse(dict);
+    break;
+  case 2:
+    shading = GfxAxialShading::parse(dict);
+    break;
+  case 3:
+    shading = GfxRadialShading::parse(dict);
+    break;
+  default:
+    error(-1, "Unimplemented shading type %d", typeA);
+    goto err1;
+  }
 
-    for (i = 0; i < gfxColorMaxComps; ++i) {
-      backgroundA.c[i] = 0;
-    }
-    hasBackgroundA = gFalse;
-    if (obj->dictLookup("Background", &obj1)->isArray()) {
-      if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
-       hasBackgroundA = gTrue;
-       for (i = 0; i < colorSpaceA->getNComps(); ++i) {
-         backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
-         obj2.free();
-       }
-      } else {
-       error(-1, "Bad Background in shading dictionary");
-      }
-    }
+  return shading;
+
+ err1:
+  return NULL;
+}
+
+GBool GfxShading::init(Dict *dict) {
+  Object obj1, obj2;
+  int i;
+
+  dict->lookup("ColorSpace", &obj1);
+  if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
+    error(-1, "Bad color space in shading dictionary");
     obj1.free();
+    return gFalse;
+  }
+  obj1.free();
 
-    xMinA = yMinA = xMaxA = yMaxA = 0;
-    hasBBoxA = gFalse;
-    if (obj->dictLookup("BBox", &obj1)->isArray()) {
-      if (obj1.arrayGetLength() == 4) {
-       hasBBoxA = gTrue;
-       xMinA = obj1.arrayGet(0, &obj2)->getNum();
-       obj2.free();
-       yMinA = obj1.arrayGet(1, &obj2)->getNum();
-       obj2.free();
-       xMaxA = obj1.arrayGet(2, &obj2)->getNum();
-       obj2.free();
-       yMaxA = obj1.arrayGet(3, &obj2)->getNum();
+  for (i = 0; i < gfxColorMaxComps; ++i) {
+    background.c[i] = 0;
+  }
+  hasBackground = gFalse;
+  if (dict->lookup("Background", &obj1)->isArray()) {
+    if (obj1.arrayGetLength() == colorSpace->getNComps()) {
+      hasBackground = gTrue;
+      for (i = 0; i < colorSpace->getNComps(); ++i) {
+       background.c[i] = obj1.arrayGet(i, &obj2)->getNum();
        obj2.free();
-      } else {
-       error(-1, "Bad BBox in shading dictionary");
       }
+    } else {
+      error(-1, "Bad Background in shading dictionary");
     }
-    obj1.free();
+  }
+  obj1.free();
 
-    switch (typeA) {
-    case 2:
-      shading = GfxAxialShading::parse(obj->getDict());
-      break;
-    case 3:
-      shading = GfxRadialShading::parse(obj->getDict());
-      break;
-    default:
-      error(-1, "Unimplemented shading type %d", typeA);
-      goto err1;
+  xMin = yMin = xMax = yMax = 0;
+  hasBBox = gFalse;
+  if (dict->lookup("BBox", &obj1)->isArray()) {
+    if (obj1.arrayGetLength() == 4) {
+      hasBBox = gTrue;
+      xMin = obj1.arrayGet(0, &obj2)->getNum();
+      obj2.free();
+      yMin = obj1.arrayGet(1, &obj2)->getNum();
+      obj2.free();
+      xMax = obj1.arrayGet(2, &obj2)->getNum();
+      obj2.free();
+      yMax = obj1.arrayGet(3, &obj2)->getNum();
+      obj2.free();
+    } else {
+      error(-1, "Bad BBox in shading dictionary");
     }
+  }
+  obj1.free();
 
-    if (shading) {
-      shading->type = typeA;
-      shading->colorSpace = colorSpaceA;
-      shading->background = backgroundA;
-      shading->hasBackground = hasBackgroundA;
-      shading->xMin = xMinA;
-      shading->yMin = yMinA;
-      shading->xMax = xMaxA;
-      shading->yMax = yMaxA;
-      shading->hasBBox = hasBBoxA;
-    } else {
-      delete colorSpaceA;
+  return gTrue;
+}
+
+//------------------------------------------------------------------------
+// GfxFunctionShading
+//------------------------------------------------------------------------
+
+GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
+                                      double x1A, double y1A,
+                                      double *matrixA,
+                                      Function **funcsA, int nFuncsA):
+  GfxShading(1)
+{
+  int i;
+
+  x0 = x0A;
+  y0 = y0A;
+  x1 = x1A;
+  y1 = y1A;
+  for (i = 0; i < 6; ++i) {
+    matrix[i] = matrixA[i];
+  }
+  nFuncs = nFuncsA;
+  for (i = 0; i < nFuncs; ++i) {
+    funcs[i] = funcsA[i];
+  }
+}
+
+GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
+  GfxShading(shading)
+{
+  int i;
+
+  x0 = shading->x0;
+  y0 = shading->y0;
+  x1 = shading->x1;
+  y1 = shading->y1;
+  for (i = 0; i < 6; ++i) {
+    matrix[i] = shading->matrix[i];
+  }
+  nFuncs = shading->nFuncs;
+  for (i = 0; i < nFuncs; ++i) {
+    funcs[i] = shading->funcs[i]->copy();
+  }
+}
+
+GfxFunctionShading::~GfxFunctionShading() {
+  int i;
+
+  for (i = 0; i < nFuncs; ++i) {
+    delete funcs[i];
+  }
+}
+
+GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
+  GfxFunctionShading *shading;
+  double x0A, y0A, x1A, y1A;
+  double matrixA[6];
+  Function *funcsA[gfxColorMaxComps];
+  int nFuncsA;
+  Object obj1, obj2;
+  int i;
+
+  x0A = y0A = 0;
+  x1A = y1A = 1;
+  if (dict->lookup("Domain", &obj1)->isArray() &&
+      obj1.arrayGetLength() == 4) {
+    x0A = obj1.arrayGet(0, &obj2)->getNum();
+    obj2.free();
+    y0A = obj1.arrayGet(1, &obj2)->getNum();
+    obj2.free();
+    x1A = obj1.arrayGet(2, &obj2)->getNum();
+    obj2.free();
+    y1A = obj1.arrayGet(3, &obj2)->getNum();
+    obj2.free();
+  }
+  obj1.free();
+
+  matrixA[0] = 1; matrixA[1] = 0;
+  matrixA[2] = 0; matrixA[3] = 1;
+  matrixA[4] = 0; matrixA[5] = 0;
+  if (dict->lookup("Matrix", &obj1)->isArray() &&
+      obj1.arrayGetLength() == 6) {
+    matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
+    obj2.free();
+    matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
+    obj2.free();
+    matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
+    obj2.free();
+    matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
+    obj2.free();
+    matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
+    obj2.free();
+    matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
+    obj2.free();
+  }
+  obj1.free();
+
+  dict->lookup("Function", &obj1);
+  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))) {
+       goto err2;
+      }
+      obj2.free();
+    }
+  } else {
+    nFuncsA = 1;
+    if (!(funcsA[0] = Function::parse(&obj1))) {
+      goto err1;
     }
   }
+  obj1.free();
 
+  shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
+                                  funcsA, nFuncsA);
+  if (!shading->init(dict)) {
+    delete shading;
+    return NULL;
+  }
   return shading;
 
+ err2:
+  obj2.free();
  err1:
+  obj1.free();
   return NULL;
 }
 
+GfxShading *GfxFunctionShading::copy() {
+  return new GfxFunctionShading(this);
+}
+
+void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
+  double in[2];
+  int i;
+
+  in[0] = x;
+  in[1] = y;
+  for (i = 0; i < nFuncs; ++i) {
+    funcs[i]->transform(in, &color->c[i]);
+  }
+}
+
 //------------------------------------------------------------------------
 // GfxAxialShading
 //------------------------------------------------------------------------
@@ -1404,7 +1657,9 @@ GfxAxialShading::GfxAxialShading(double x0A, double y0A,
                                 double x1A, double y1A,
                                 double t0A, double t1A,
                                 Function **funcsA, int nFuncsA,
-                                GBool extend0A, GBool extend1A) {
+                                GBool extend0A, GBool extend1A):
+  GfxShading(2)
+{
   int i;
 
   x0 = x0A;
@@ -1421,6 +1676,25 @@ GfxAxialShading::GfxAxialShading(double x0A, double y0A,
   extend1 = extend1A;
 }
 
+GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
+  GfxShading(shading)
+{
+  int i;
+
+  x0 = shading->x0;
+  y0 = shading->y0;
+  x1 = shading->x1;
+  y1 = shading->y1;
+  t0 = shading->t0;
+  y1 = shading->t1;
+  nFuncs = shading->nFuncs;
+  for (i = 0; i < nFuncs; ++i) {
+    funcs[i] = shading->funcs[i]->copy();
+  }
+  extend0 = shading->extend0;
+  extend1 = shading->extend1;
+}
+
 GfxAxialShading::~GfxAxialShading() {
   int i;
 
@@ -1430,6 +1704,7 @@ GfxAxialShading::~GfxAxialShading() {
 }
 
 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
+  GfxAxialShading *shading;
   double x0A, y0A, x1A, y1A;
   double t0A, t1A;
   Function *funcsA[gfxColorMaxComps];
@@ -1469,6 +1744,10 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
   dict->lookup("Function", &obj1);
   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))) {
@@ -1497,16 +1776,27 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
   }
   obj1.free();
 
-  return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
-                            funcsA, nFuncsA, extend0A, extend1A);
+  shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
+                               funcsA, nFuncsA, extend0A, extend1A);
+  if (!shading->init(dict)) {
+    delete shading;
+    return NULL;
+  }
+  return shading;
 
  err1:
   return NULL;
 }
 
+GfxShading *GfxAxialShading::copy() {
+  return new GfxAxialShading(this);
+}
+
 void GfxAxialShading::getColor(double t, GfxColor *color) {
   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 < nFuncs; ++i) {
     funcs[i]->transform(&t, &color->c[i]);
   }
@@ -1520,7 +1810,9 @@ GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
                                   double x1A, double y1A, double r1A,
                                   double t0A, double t1A,
                                   Function **funcsA, int nFuncsA,
-                                  GBool extend0A, GBool extend1A) {
+                                  GBool extend0A, GBool extend1A):
+  GfxShading(3)
+{
   int i;
 
   x0 = x0A;
@@ -1539,6 +1831,27 @@ GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
   extend1 = extend1A;
 }
 
+GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
+  GfxShading(shading)
+{
+  int i;
+
+  x0 = shading->x0;
+  y0 = shading->y0;
+  r0 = shading->r0;
+  x1 = shading->x1;
+  y1 = shading->y1;
+  r1 = shading->r1;
+  t0 = shading->t0;
+  y1 = shading->t1;
+  nFuncs = shading->nFuncs;
+  for (i = 0; i < nFuncs; ++i) {
+    funcs[i] = shading->funcs[i]->copy();
+  }
+  extend0 = shading->extend0;
+  extend1 = shading->extend1;
+}
+
 GfxRadialShading::~GfxRadialShading() {
   int i;
 
@@ -1548,6 +1861,7 @@ GfxRadialShading::~GfxRadialShading() {
 }
 
 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
+  GfxRadialShading *shading;
   double x0A, y0A, r0A, x1A, y1A, r1A;
   double t0A, t1A;
   Function *funcsA[gfxColorMaxComps];
@@ -1591,6 +1905,10 @@ GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
   dict->lookup("Function", &obj1);
   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))) {
@@ -1619,16 +1937,27 @@ GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
   }
   obj1.free();
 
-  return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
-                             funcsA, nFuncsA, extend0A, extend1A);
+  shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
+                                funcsA, nFuncsA, extend0A, extend1A);
+  if (!shading->init(dict)) {
+    delete shading;
+    return NULL;
+  }
+  return shading;
 
  err1:
   return NULL;
 }
 
+GfxShading *GfxRadialShading::copy() {
+  return new GfxRadialShading(this);
+}
+
 void GfxRadialShading::getColor(double t, GfxColor *color) {
   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 < nFuncs; ++i) {
     funcs[i]->transform(&t, &color->c[i]);
   }
@@ -1741,6 +2070,36 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
   ok = gFalse;
 }
 
+GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
+  int n, i;
+
+  colorSpace = colorMap->colorSpace->copy();
+  bits = colorMap->bits;
+  nComps = colorMap->nComps;
+  nComps2 = colorMap->nComps2;
+  colorSpace2 = NULL;
+  lookup = NULL;
+  if (colorSpace->getMode() == csIndexed) {
+    colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+    n = ((GfxIndexedColorSpace *)colorSpace)->getIndexHigh();
+    n = (n + 1) * nComps2 * sizeof(double);
+  } else if (colorSpace->getMode() == csSeparation) {
+    colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
+    n = (1 << bits) - 1;
+    n = (n + 1) * nComps2 * sizeof(double);
+  } else {
+    n = (1 << bits) - 1;
+    n = (n + 1) * nComps * sizeof(double);
+  }
+  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];
+  }
+  ok = gTrue;
+}
+
 GfxImageColorMap::~GfxImageColorMap() {
   delete colorSpace;
   gfree(lookup);
@@ -1886,6 +2245,15 @@ void GfxSubpath::close() {
   closed = gTrue;
 }
 
+void GfxSubpath::offset(double dx, double dy) {
+  int i;
+
+  for (i = 0; i < n; ++i) {
+    x[i] += dx;
+    y[i] += dy;
+  }
+}
+
 GfxPath::GfxPath() {
   justMoved = gFalse;
   size = 16;
@@ -1968,55 +2336,78 @@ void GfxPath::close() {
   subpaths[n-1]->close();
 }
 
+void GfxPath::append(GfxPath *path) {
+  int i;
+
+  if (n + path->n > size) {
+    size = n + path->n;
+    subpaths = (GfxSubpath **)
+                 grealloc(subpaths, size * sizeof(GfxSubpath *));
+  }
+  for (i = 0; i < path->n; ++i) {
+    subpaths[n++] = path->subpaths[i]->copy();
+  }
+  justMoved = gFalse;
+}
+
+void GfxPath::offset(double dx, double dy) {
+  int i;
+
+  for (i = 0; i < n; ++i) {
+    subpaths[i]->offset(dx, dy);
+  }
+}
+
 //------------------------------------------------------------------------
 // GfxState
 //------------------------------------------------------------------------
 
-GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
-                  GBool upsideDown) {
-  double k;
+GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
+                  int rotate, GBool upsideDown) {
+  double kx, ky;
 
   px1 = pageBox->x1;
   py1 = pageBox->y1;
   px2 = pageBox->x2;
   py2 = pageBox->y2;
-  k = dpi / 72.0;
+  kx = hDPI / 72.0;
+  ky = vDPI / 72.0;
   if (rotate == 90) {
     ctm[0] = 0;
-    ctm[1] = upsideDown ? k : -k;
-    ctm[2] = k;
+    ctm[1] = upsideDown ? ky : -ky;
+    ctm[2] = kx;
     ctm[3] = 0;
-    ctm[4] = -k * py1;
-    ctm[5] = k * (upsideDown ? -px1 : px2);
-    pageWidth = k * (py2 - py1);
-    pageHeight = k * (px2 - px1);
+    ctm[4] = -kx * py1;
+    ctm[5] = ky * (upsideDown ? -px1 : px2);
+    pageWidth = kx * (py2 - py1);
+    pageHeight = ky * (px2 - px1);
   } else if (rotate == 180) {
-    ctm[0] = -k;
+    ctm[0] = -kx;
     ctm[1] = 0;
     ctm[2] = 0;
-    ctm[3] = upsideDown ? k : -k;
-    ctm[4] = k * px2;
-    ctm[5] = k * (upsideDown ? -py1 : py2);
-    pageWidth = k * (px2 - px1);
-    pageHeight = k * (py2 - py1);
+    ctm[3] = upsideDown ? ky : -ky;
+    ctm[4] = kx * px2;
+    ctm[5] = ky * (upsideDown ? -py1 : py2);
+    pageWidth = kx * (px2 - px1);
+    pageHeight = ky * (py2 - py1);
   } else if (rotate == 270) {
     ctm[0] = 0;
-    ctm[1] = upsideDown ? -k : k;
-    ctm[2] = -k;
+    ctm[1] = upsideDown ? -ky : ky;
+    ctm[2] = -kx;
     ctm[3] = 0;
-    ctm[4] = k * py2;
-    ctm[5] = k * (upsideDown ? px2 : -px1);
-    pageWidth = k * (py2 - py1);
-    pageHeight = k * (px2 - px1);
+    ctm[4] = kx * py2;
+    ctm[5] = ky * (upsideDown ? px2 : -px1);
+    pageWidth = kx * (py2 - py1);
+    pageHeight = ky * (px2 - px1);
   } else {
-    ctm[0] = k;
+    ctm[0] = kx;
     ctm[1] = 0;
     ctm[2] = 0;
-    ctm[3] = upsideDown ? -k : k;
-    ctm[4] = -k * px1;
-    ctm[5] = k * (upsideDown ? py2 : -py1);
-    pageWidth = k * (px2 - px1);
-    pageHeight = k * (py2 - py1);
+    ctm[3] = upsideDown ? -ky : ky;
+    ctm[4] = -kx * px1;
+    ctm[5] = ky * (upsideDown ? py2 : -py1);
+    pageWidth = kx * (px2 - px1);
+    pageHeight = ky * (py2 - py1);
   }
 
   fillColorSpace = new GfxDeviceGrayColorSpace();
@@ -2032,7 +2423,7 @@ GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
   lineDash = NULL;
   lineDashLength = 0;
   lineDashStart = 0;
-  flatness = 0;
+  flatness = 1;
   lineJoin = 0;
   lineCap = 0;
   miterLimit = 10;