Code

Restore files that shouldn't have been touched. Grrr
[inkscape.git] / src / extension / internal / pdfinput / pdf-parser.cpp
index c64f5de06fe3b4fbfda037c531dd2d0b773b0957..118896fd30318d74881f4d97a1a273ee592bc1ed 100644 (file)
@@ -60,37 +60,11 @@ extern "C" {
 // constants
 //------------------------------------------------------------------------
 
-// Max recursive depth for a function shading fill.
-#define functionMaxDepth 6
+// Default max delta allowed in any color component for a shading fill.
+#define defaultShadingColorDelta (dblToCol( 1 / 2.0 ))
 
-// Max delta allowed in any color component for a function shading fill.
-#define functionColorDelta (dblToCol(1 / 256.0))
-
-// Max number of splits along the t axis for an axial shading fill.
-#define axialMaxSplits 256
-
-// Max delta allowed in any color component for an axial shading fill.
-#define axialColorDelta (dblToCol(1 / 256.0))
-
-// Max number of splits along the t axis for a radial shading fill.
-#define radialMaxSplits 256
-
-// Max delta allowed in any color component for a radial shading fill.
-#define radialColorDelta (dblToCol(1 / 256.0))
-
-// Max recursive depth for a Gouraud triangle shading fill.
-#define gouraudMaxDepth 6
-
-// Max delta allowed in any color component for a Gouraud triangle
-// shading fill.
-#define gouraudColorDelta (dblToCol(1 / 256.0))
-
-// Max recursive depth for a patch mesh shading fill.
-#define patchMaxDepth 6
-
-// Max delta allowed in any color component for a patch mesh shading
-// fill.
-#define patchColorDelta (dblToCol(1 / 256.0))
+// Default max recursive depth for a shading fill.
+#define defaultShadingMaxDepth 6
 
 // Max number of operators kept in the history list.
 #define maxOperatorHistoryDepth 16
@@ -283,7 +257,8 @@ PdfOperator PdfParser::opTab[] = {
 //------------------------------------------------------------------------
 
 PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA,
-                     int pageNum, int rotate, Dict *resDict, PDFRectangle *cropBox) {
+                     int pageNum, int rotate, Dict *resDict,
+                     PDFRectangle *box, PDFRectangle *cropBox) {
 
   int i;
 
@@ -295,7 +270,9 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui
   res = new GfxResources(xref, resDict, NULL);
 
   // initialize
-  state = new GfxState(72.0, 72.0, cropBox, rotate, gTrue);
+  state = new GfxState(72.0, 72.0, box, rotate, gTrue);
+  clipHistory = new ClipHistoryEntry();
+  setDefaultApproximationPrecision();
   fontChanged = gFalse;
   clip = clipNone;
   ignoreUndef = 0;
@@ -310,6 +287,7 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui
     baseMatrix[i] = ctm[i];
     scaledCTM[i] = PX_PER_PT * ctm[i];
   }
+  saveState();
   builder->setTransform((double*)&scaledCTM);
   formDepth = 0;
 
@@ -327,6 +305,7 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui
         state->lineTo(cropBox->x1, cropBox->y2);
         state->closePath();
         state->clip();
+        clipHistory->setClip(state->getPath(), clipNormal);
         builder->setClipPath(state);
         state->clearPath();
     }
@@ -334,6 +313,34 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui
   pushOperator("startPage");
 }
 
+PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA,
+                     Dict *resDict, PDFRectangle *box) {
+
+  int i;
+
+  xref = xrefA;
+  subPage = gTrue;
+  printCommands = false;
+
+  // start the resource stack
+  res = new GfxResources(xref, resDict, NULL);
+
+  // initialize
+  operatorHistory = NULL;
+  builder = builderA;
+  state = new GfxState(72, 72, box, 0, gFalse);
+  clipHistory = new ClipHistoryEntry();
+  setDefaultApproximationPrecision();
+  
+  fontChanged = gFalse;
+  clip = clipNone;
+  ignoreUndef = 0;
+  for (i = 0; i < 6; ++i) {
+    baseMatrix[i] = state->getCTM()[i];
+  }
+  formDepth = 0;
+}
+
 PdfParser::~PdfParser() {
   while (state->hasSaves()) {
     restoreState();
@@ -347,6 +354,9 @@ PdfParser::~PdfParser() {
   if (state) {
     delete state;
   }
+  if (clipHistory) {
+    delete clipHistory;
+  }
 }
 
 void PdfParser::parse(Object *obj, GBool topLevel) {
@@ -357,14 +367,14 @@ void PdfParser::parse(Object *obj, GBool topLevel) {
     for (i = 0; i < obj->arrayGetLength(); ++i) {
       obj->arrayGet(i, &obj2);
       if (!obj2.isStream()) {
-       error(-1, "Weird page contents");
+       error(-1, const_cast<char*>("Weird page contents"));
        obj2.free();
        return;
       }
       obj2.free();
     }
   } else if (!obj->isStream()) {
-    error(-1, "Weird page contents");
+    error(-1, const_cast<char*>("Weird page contents"));
     return;
   }
   parser = new Parser(xref, new Lexer(xref, obj), gFalse);
@@ -377,7 +387,6 @@ void PdfParser::go(GBool topLevel) {
   Object obj;
   Object args[maxArgs];
   int numArgs, i;
-  int lastAbortCheck;
 
   // scan a sequence of objects
   numArgs = 0;
@@ -410,7 +419,7 @@ void PdfParser::go(GBool topLevel) {
 
     // too many arguments - something is wrong
     } else {
-      error(getPos(), "Too many args in content stream");
+      error(getPos(), const_cast<char*>("Too many args in content stream"));
       if (printCommands) {
        printf("throwing away arg: ");
        obj.print(stdout);
@@ -427,7 +436,7 @@ void PdfParser::go(GBool topLevel) {
 
   // args at end with no command
   if (numArgs > 0) {
-    error(getPos(), "Leftover args in content stream");
+    error(getPos(), const_cast<char*>("Leftover args in content stream"));
     if (printCommands) {
       printf("%d leftovers:", numArgs);
       for (i = 0; i < numArgs; ++i) {
@@ -493,7 +502,7 @@ void PdfParser::execOp(Object *cmd, Object args[], int numArgs) {
   name = cmd->getCmd();
   if (!(op = findOp(name))) {
     if (ignoreUndef == 0)
-      error(getPos(), "Unknown operator '%s'", name);
+      error(getPos(), const_cast<char*>("Unknown operator '%s'"), name);
     return;
   }
 
@@ -501,7 +510,7 @@ void PdfParser::execOp(Object *cmd, Object args[], int numArgs) {
   argPtr = args;
   if (op->numArgs >= 0) {
     if (numArgs < op->numArgs) {
-      error(getPos(), "Too few (%d) args to '%s' operator", numArgs, name);
+      error(getPos(), const_cast<char*>("Too few (%d) args to '%s' operator"), numArgs, name);
       return;
     }
     if (numArgs > op->numArgs) {
@@ -513,14 +522,14 @@ void PdfParser::execOp(Object *cmd, Object args[], int numArgs) {
     }
   } else {
     if (numArgs > -op->numArgs) {
-      error(getPos(), "Too many (%d) args to '%s' operator",
+      error(getPos(), const_cast<char*>("Too many (%d) args to '%s' operator"),
            numArgs, name);
       return;
     }
   }
   for (i = 0; i < numArgs; ++i) {
     if (!checkArg(&argPtr[i], op->tchk[i])) {
-      error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)",
+      error(getPos(), const_cast<char*>("Arg #%d to '%s' operator is wrong type (%s)"),
            i, name, argPtr[i].getTypeName());
       return;
     }
@@ -598,20 +607,20 @@ void PdfParser::opConcat(Object args[], int numArgs) {
   double a5 = args[5].getNum();
   if (!strcmp(prevOp, "q")) {
       builder->setTransform(a0, a1, a2, a3, a4, a5);
-  } else if (!strcmp(prevOp, "cm")) {
+  } else if (!strcmp(prevOp, "cm") || !strcmp(prevOp, "startPage")) {
       // multiply it with the previous transform
       double otherMatrix[6];
-      if (!builder->getTransform((double*)&otherMatrix)) { // invalid transform
+      if (!builder->getTransform(otherMatrix)) { // invalid transform
           // construct identity matrix
           otherMatrix[0] = otherMatrix[3] = 1.0;
           otherMatrix[1] = otherMatrix[2] = otherMatrix[4] = otherMatrix[5] = 0.0;
       }
-      double c0 = otherMatrix[0]*a0 + otherMatrix[1]*a2;
-      double c1 = otherMatrix[0]*a1 + otherMatrix[1]*a3;
-      double c2 = otherMatrix[2]*a0 + otherMatrix[3]*a2;
-      double c3 = otherMatrix[2]*a1 + otherMatrix[3]*a3;
-      double c4 = otherMatrix[4]*a0 + otherMatrix[5]*a2 + a4;
-      double c5 = otherMatrix[4]*a1 + otherMatrix[5]*a3 + a5;
+      double c0 = a0*otherMatrix[0] + a1*otherMatrix[2];
+      double c1 = a0*otherMatrix[1] + a1*otherMatrix[3];
+      double c2 = a2*otherMatrix[0] + a3*otherMatrix[2];
+      double c3 = a2*otherMatrix[1] + a3*otherMatrix[3];
+      double c4 = a4*otherMatrix[0] + a5*otherMatrix[2] + otherMatrix[4];
+      double c5 = a4*otherMatrix[1] + a5*otherMatrix[3] + otherMatrix[5];
       builder->setTransform(c0, c1, c2, c3, c4, c5);
   } else {
       builder->pushGroup();
@@ -681,7 +690,7 @@ void PdfParser::opSetExtGState(Object args[], int numArgs) {
     return;
   }
   if (!obj1.isDict()) {
-    error(getPos(), "ExtGState '%s' is wrong type", args[0].getName());
+    error(getPos(), const_cast<char*>("ExtGState '%s' is wrong type"), args[0].getName());
     obj1.free();
     return;
   }
@@ -692,29 +701,29 @@ void PdfParser::opSetExtGState(Object args[], int numArgs) {
   }
 
   // transparency support: blend mode, fill/stroke opacity
-  if (!obj1.dictLookup("BM", &obj2)->isNull()) {
+  if (!obj1.dictLookup(const_cast<char*>("BM"), &obj2)->isNull()) {
     if (state->parseBlendMode(&obj2, &mode)) {
       state->setBlendMode(mode);
     } else {
-      error(getPos(), "Invalid blend mode in ExtGState");
+      error(getPos(), const_cast<char*>("Invalid blend mode in ExtGState"));
     }
   }
   obj2.free();
-  if (obj1.dictLookup("ca", &obj2)->isNum()) {
+  if (obj1.dictLookup(const_cast<char*>("ca"), &obj2)->isNum()) {
     state->setFillOpacity(obj2.getNum());
   }
   obj2.free();
-  if (obj1.dictLookup("CA", &obj2)->isNum()) {
+  if (obj1.dictLookup(const_cast<char*>("CA"), &obj2)->isNum()) {
     state->setStrokeOpacity(obj2.getNum());
   }
   obj2.free();
 
   // fill/stroke overprint
-  if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) {
+  if ((haveFillOP = (obj1.dictLookup(const_cast<char*>("op"), &obj2)->isBool()))) {
     state->setFillOverprint(obj2.getBool());
   }
   obj2.free();
-  if (obj1.dictLookup("OP", &obj2)->isBool()) {
+  if (obj1.dictLookup(const_cast<char*>("OP"), &obj2)->isBool()) {
     state->setStrokeOverprint(obj2.getBool());
     if (!haveFillOP) {
       state->setFillOverprint(obj2.getBool());
@@ -723,18 +732,18 @@ void PdfParser::opSetExtGState(Object args[], int numArgs) {
   obj2.free();
 
   // stroke adjust
-  if (obj1.dictLookup("SA", &obj2)->isBool()) {
+  if (obj1.dictLookup(const_cast<char*>("SA"), &obj2)->isBool()) {
     state->setStrokeAdjust(obj2.getBool());
   }
   obj2.free();
 
   // transfer function
-  if (obj1.dictLookup("TR2", &obj2)->isNull()) {
+  if (obj1.dictLookup(const_cast<char*>("TR2"), &obj2)->isNull()) {
     obj2.free();
-    obj1.dictLookup("TR", &obj2);
+    obj1.dictLookup(const_cast<char*>("TR"), &obj2);
   }
-  if (obj2.isName("Default") ||
-      obj2.isName("Identity")) {
+  if (obj2.isName(const_cast<char*>("Default")) ||
+      obj2.isName(const_cast<char*>("Identity"))) {
     funcs[0] = funcs[1] = funcs[2] = funcs[3] = NULL;
     state->setTransfer(funcs);
   } else if (obj2.isArray() && obj2.arrayGetLength() == 4) {
@@ -755,34 +764,34 @@ void PdfParser::opSetExtGState(Object args[], int numArgs) {
       state->setTransfer(funcs);
     }
   } else if (!obj2.isNull()) {
-    error(getPos(), "Invalid transfer function in ExtGState");
+    error(getPos(), const_cast<char*>("Invalid transfer function in ExtGState"));
   }
   obj2.free();
 
   // soft mask
-  if (!obj1.dictLookup("SMask", &obj2)->isNull()) {
-    if (obj2.isName("None")) {
-      //out->clearSoftMask(state);
+  if (!obj1.dictLookup(const_cast<char*>("SMask"), &obj2)->isNull()) {
+    if (obj2.isName(const_cast<char*>("None"))) {
+      builder->clearSoftMask(state);
     } else if (obj2.isDict()) {
-      if (obj2.dictLookup("S", &obj3)->isName("Alpha")) {
+      if (obj2.dictLookup(const_cast<char*>("S"), &obj3)->isName(const_cast<char*>("Alpha"))) {
        alpha = gTrue;
       } else { // "Luminosity"
        alpha = gFalse;
       }
       obj3.free();
       funcs[0] = NULL;
-      if (!obj2.dictLookup("TR", &obj3)->isNull()) {
+      if (!obj2.dictLookup(const_cast<char*>("TR"), &obj3)->isNull()) {
        funcs[0] = Function::parse(&obj3);
        if (funcs[0]->getInputSize() != 1 ||
            funcs[0]->getOutputSize() != 1) {
          error(getPos(),
-               "Invalid transfer function in soft mask in ExtGState");
+               const_cast<char*>("Invalid transfer function in soft mask in ExtGState"));
          delete funcs[0];
          funcs[0] = NULL;
        }
       }
       obj3.free();
-      if ((haveBackdropColor = obj2.dictLookup("BC", &obj3)->isArray())) {
+      if ((haveBackdropColor = obj2.dictLookup(const_cast<char*>("BC"), &obj3)->isArray())) {
        for (i = 0; i < gfxColorMaxComps; ++i) {
          backdropColor.c[i] = 0;
        }
@@ -795,19 +804,19 @@ void PdfParser::opSetExtGState(Object args[], int numArgs) {
        }
       }
       obj3.free();
-      if (obj2.dictLookup("G", &obj3)->isStream()) {
-       if (obj3.streamGetDict()->lookup("Group", &obj4)->isDict()) {
+      if (obj2.dictLookup(const_cast<char*>("G"), &obj3)->isStream()) {
+       if (obj3.streamGetDict()->lookup(const_cast<char*>("Group"), &obj4)->isDict()) {
          blendingColorSpace = NULL;
          isolated = knockout = gFalse;
-         if (!obj4.dictLookup("CS", &obj5)->isNull()) {
+         if (!obj4.dictLookup(const_cast<char*>("CS"), &obj5)->isNull()) {
            blendingColorSpace = GfxColorSpace::parse(&obj5);
          }
          obj5.free();
-         if (obj4.dictLookup("I", &obj5)->isBool()) {
+         if (obj4.dictLookup(const_cast<char*>("I"), &obj5)->isBool()) {
            isolated = obj5.getBool();
          }
          obj5.free();
-         if (obj4.dictLookup("K", &obj5)->isBool()) {
+         if (obj4.dictLookup(const_cast<char*>("K"), &obj5)->isBool()) {
            knockout = obj5.getBool();
          }
          obj5.free();
@@ -827,15 +836,15 @@ void PdfParser::opSetExtGState(Object args[], int numArgs) {
            delete funcs[0];
          }
        } else {
-         error(getPos(), "Invalid soft mask in ExtGState - missing group");
+         error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
        }
        obj4.free();
       } else {
-       error(getPos(), "Invalid soft mask in ExtGState - missing group");
+       error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
       }
       obj3.free();
     } else if (!obj2.isNull()) {
-      error(getPos(), "Invalid soft mask in ExtGState");
+      error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState"));
     }
   }
   obj2.free();
@@ -861,17 +870,17 @@ void PdfParser::doSoftMask(Object *str, GBool alpha,
   dict = str->streamGetDict();
 
   // check form type
-  dict->lookup("FormType", &obj1);
+  dict->lookup(const_cast<char*>("FormType"), &obj1);
   if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
-    error(getPos(), "Unknown form type");
+    error(getPos(), const_cast<char*>("Unknown form type"));
   }
   obj1.free();
 
   // get bounding box
-  dict->lookup("BBox", &obj1);
+  dict->lookup(const_cast<char*>("BBox"), &obj1);
   if (!obj1.isArray()) {
     obj1.free();
-    error(getPos(), "Bad form bounding box");
+    error(getPos(), const_cast<char*>("Bad form bounding box"));
     return;
   }
   for (i = 0; i < 4; ++i) {
@@ -882,7 +891,7 @@ void PdfParser::doSoftMask(Object *str, GBool alpha,
   obj1.free();
 
   // get matrix
-  dict->lookup("Matrix", &obj1);
+  dict->lookup(const_cast<char*>("Matrix"), &obj1);
   if (obj1.isArray()) {
     for (i = 0; i < 6; ++i) {
       obj1.arrayGet(i, &obj2);
@@ -897,7 +906,7 @@ void PdfParser::doSoftMask(Object *str, GBool alpha,
   obj1.free();
 
   // get resources
-  dict->lookup("Resources", &obj1);
+  dict->lookup(const_cast<char*>("Resources"), &obj1);
   resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL;
 
   // draw it
@@ -1011,7 +1020,7 @@ void PdfParser::opSetFillColorSpace(Object args[], int numArgs) {
     state->setFillColor(&color);
     builder->updateStyle(state);
   } else {
-    error(getPos(), "Bad color space (fill)");
+    error(getPos(), const_cast<char*>("Bad color space (fill)"));
   }
 }
 
@@ -1034,7 +1043,7 @@ void PdfParser::opSetStrokeColorSpace(Object args[], int numArgs) {
     state->setStrokeColor(&color);
     builder->updateStyle(state);
   } else {
-    error(getPos(), "Bad color space (stroke)");
+    error(getPos(), const_cast<char*>("Bad color space (stroke)"));
   }
 }
 
@@ -1043,7 +1052,7 @@ void PdfParser::opSetFillColor(Object args[], int numArgs) {
   int i;
 
   if (numArgs != state->getFillColorSpace()->getNComps()) {
-    error(getPos(), "Incorrect number of arguments in 'sc' command");
+    error(getPos(), const_cast<char*>("Incorrect number of arguments in 'sc' command"));
     return;
   }
   state->setFillPattern(NULL);
@@ -1059,7 +1068,7 @@ void PdfParser::opSetStrokeColor(Object args[], int numArgs) {
   int i;
 
   if (numArgs != state->getStrokeColorSpace()->getNComps()) {
-    error(getPos(), "Incorrect number of arguments in 'SC' command");
+    error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SC' command"));
     return;
   }
   state->setStrokePattern(NULL);
@@ -1080,7 +1089,7 @@ void PdfParser::opSetFillColorN(Object args[], int numArgs) {
       if (!((GfxPatternColorSpace *)state->getFillColorSpace())->getUnder() ||
          numArgs - 1 != ((GfxPatternColorSpace *)state->getFillColorSpace())
                             ->getUnder()->getNComps()) {
-       error(getPos(), "Incorrect number of arguments in 'scn' command");
+       error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
        return;
       }
       for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
@@ -1094,11 +1103,12 @@ void PdfParser::opSetFillColorN(Object args[], int numArgs) {
     if (args[numArgs-1].isName() &&
        (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
       state->setFillPattern(pattern);
+      builder->updateStyle(state);
     }
 
   } else {
     if (numArgs != state->getFillColorSpace()->getNComps()) {
-      error(getPos(), "Incorrect number of arguments in 'scn' command");
+      error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
       return;
     }
     state->setFillPattern(NULL);
@@ -1123,7 +1133,7 @@ void PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
               ->getUnder() ||
          numArgs - 1 != ((GfxPatternColorSpace *)state->getStrokeColorSpace())
                             ->getUnder()->getNComps()) {
-       error(getPos(), "Incorrect number of arguments in 'SCN' command");
+       error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
        return;
       }
       for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
@@ -1137,11 +1147,12 @@ void PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
     if (args[numArgs-1].isName() &&
        (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
       state->setStrokePattern(pattern);
+      builder->updateStyle(state);
     }
 
   } else {
     if (numArgs != state->getStrokeColorSpace()->getNComps()) {
-      error(getPos(), "Incorrect number of arguments in 'SCN' command");
+      error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
       return;
     }
     state->setStrokePattern(NULL);
@@ -1165,7 +1176,7 @@ void PdfParser::opMoveTo(Object args[], int numArgs) {
 
 void PdfParser::opLineTo(Object args[], int numArgs) {
   if (!state->isCurPt()) {
-    error(getPos(), "No current point in lineto");
+    error(getPos(), const_cast<char*>("No current point in lineto"));
     return;
   }
   state->lineTo(args[0].getNum(), args[1].getNum());
@@ -1175,7 +1186,7 @@ void PdfParser::opCurveTo(Object args[], int numArgs) {
   double x1, y1, x2, y2, x3, y3;
 
   if (!state->isCurPt()) {
-    error(getPos(), "No current point in curveto");
+    error(getPos(), const_cast<char*>("No current point in curveto"));
     return;
   }
   x1 = args[0].getNum();
@@ -1191,7 +1202,7 @@ void PdfParser::opCurveTo1(Object args[], int numArgs) {
   double x1, y1, x2, y2, x3, y3;
 
   if (!state->isCurPt()) {
-    error(getPos(), "No current point in curveto1");
+    error(getPos(), const_cast<char*>("No current point in curveto1"));
     return;
   }
   x1 = state->getCurX();
@@ -1207,7 +1218,7 @@ void PdfParser::opCurveTo2(Object args[], int numArgs) {
   double x1, y1, x2, y2, x3, y3;
 
   if (!state->isCurPt()) {
-    error(getPos(), "No current point in curveto2");
+    error(getPos(), const_cast<char*>("No current point in curveto2"));
     return;
   }
   x1 = args[0].getNum();
@@ -1235,7 +1246,7 @@ void PdfParser::opRectangle(Object args[], int numArgs) {
 
 void PdfParser::opClosePath(Object args[], int numArgs) {
   if (!state->isCurPt()) {
-    error(getPos(), "No current point in closepath");
+    error(getPos(), const_cast<char*>("No current point in closepath"));
     return;
   }
   state->closePath();
@@ -1251,7 +1262,7 @@ void PdfParser::opEndPath(Object args[], int numArgs) {
 
 void PdfParser::opStroke(Object args[], int numArgs) {
   if (!state->isCurPt()) {
-    //error(getPos(), "No path in stroke");
+    //error(getPos(), const_cast<char*>("No path in stroke"));
     return;
   }
   if (state->isPath()) {
@@ -1267,7 +1278,7 @@ void PdfParser::opStroke(Object args[], int numArgs) {
 
 void PdfParser::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) {
   if (!state->isCurPt()) {
-    //error(getPos(), "No path in closepath/stroke");
+    //error(getPos(), const_cast<char*>("No path in closepath/stroke"));
     return;
   }
   state->closePath();
@@ -1284,7 +1295,7 @@ void PdfParser::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) {
 
 void PdfParser::opFill(Object args[], int numArgs) {
   if (!state->isCurPt()) {
-    //error(getPos(), "No path in fill");
+    //error(getPos(), const_cast<char*>("No path in fill"));
     return;
   }
   if (state->isPath()) {
@@ -1300,7 +1311,7 @@ void PdfParser::opFill(Object args[], int numArgs) {
 
 void PdfParser::opEOFill(Object args[], int numArgs) {
   if (!state->isCurPt()) {
-    //error(getPos(), "No path in eofill");
+    //error(getPos(), const_cast<char*>("No path in eofill"));
     return;
   }
   if (state->isPath()) {
@@ -1316,7 +1327,7 @@ void PdfParser::opEOFill(Object args[], int numArgs) {
 
 void PdfParser::opFillStroke(Object args[], int numArgs) {
   if (!state->isCurPt()) {
-    //error(getPos(), "No path in fill/stroke");
+    //error(getPos(), const_cast<char*>("No path in fill/stroke"));
     return;
   }
   if (state->isPath()) {
@@ -1329,7 +1340,7 @@ void PdfParser::opFillStroke(Object args[], int numArgs) {
 
 void PdfParser::opCloseFillStroke(Object args[], int numArgs) {
   if (!state->isCurPt()) {
-    //error(getPos(), "No path in closepath/fill/stroke");
+    //error(getPos(), const_cast<char*>("No path in closepath/fill/stroke"));
     return;
   }
   if (state->isPath()) {
@@ -1341,7 +1352,7 @@ void PdfParser::opCloseFillStroke(Object args[], int numArgs) {
 
 void PdfParser::opEOFillStroke(Object args[], int numArgs) {
   if (!state->isCurPt()) {
-    //error(getPos(), "No path in eofill/stroke");
+    //error(getPos(), const_cast<char*>("No path in eofill/stroke"));
     return;
   }
   if (state->isPath()) {
@@ -1352,7 +1363,7 @@ void PdfParser::opEOFillStroke(Object args[], int numArgs) {
 
 void PdfParser::opCloseEOFillStroke(Object args[], int numArgs) {
   if (!state->isCurPt()) {
-    //error(getPos(), "No path in closepath/eofill/stroke");
+    //error(getPos(), const_cast<char*>("No path in closepath/eofill/stroke"));
     return;
   }
   if (state->isPath()) {
@@ -1393,7 +1404,7 @@ void PdfParser::doPatternFillFallback(GBool eoFill) {
     doShadingPatternFillFallback((GfxShadingPattern *)pattern, gFalse, eoFill);
     break;
   default:
-    error(getPos(), "Unimplemented pattern type (%d) in fill",
+    error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in fill"),
          pattern->getType());
     break;
   }
@@ -1412,7 +1423,7 @@ void PdfParser::doPatternStrokeFallback() {
     doShadingPatternFillFallback((GfxShadingPattern *)pattern, gTrue, gFalse);
     break;
   default:
-    error(getPos(), "Unimplemented pattern type (%d) in stroke",
+    error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in stroke"),
          pattern->getType());
     break;
   }
@@ -1453,9 +1464,9 @@ void PdfParser::doShadingPatternFillFallback(GfxShadingPattern *sPat,
   } else {
     state->clip();
     if (eoFill) {
-      builder->clip(state, true);
+      builder->setClipPath(state, true);
     } else {
-      builder->clip(state);
+      builder->setClipPath(state);
     }
   }
 
@@ -1526,16 +1537,47 @@ void PdfParser::doShadingPatternFillFallback(GfxShadingPattern *sPat,
 
 void PdfParser::opShFill(Object args[], int numArgs) {
   GfxShading *shading;
-  GfxPath *savedPath;
+  GfxPath *savedPath = NULL;
   double xMin, yMin, xMax, yMax;
+  double gradientTransform[6];
+  double *matrix = NULL;
+  GBool savedState = gFalse;
 
   if (!(shading = res->lookupShading(args[0].getName()))) {
     return;
   }
 
   // save current graphics state
-  savedPath = state->getPath()->copy();
-  saveState();
+  if (shading->getType() != 2 && shading->getType() != 3) {
+    savedPath = state->getPath()->copy();
+    saveState();
+    savedState = gTrue;
+  } else {  // get gradient transform if possible
+      // check proper operator sequence
+      // first there should be one W(*) and then one 'cm' somewhere before 'sh'
+      GBool seenClip, seenConcat;
+      seenClip = (clipHistory->getClipPath() != NULL);
+      seenConcat = gFalse;
+      int i = 1;
+      while (i <= maxOperatorHistoryDepth) {
+        const char *opName = getPreviousOperator(i);
+        if (!strcmp(opName, "cm")) {
+          if (seenConcat) {   // more than one 'cm'
+            break;
+          } else {
+            seenConcat = gTrue;
+          }
+        }
+        i++;
+      }
+
+      if (seenConcat && seenClip) {
+        if (builder->getTransform(gradientTransform)) {
+          matrix = (double*)&gradientTransform;
+          builder->setTransform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);  // remove transform
+        }
+      }
+  }
 
   // clip to bbox
   if (shading->getHasBBox()) {
@@ -1546,12 +1588,16 @@ void PdfParser::opShFill(Object args[], int numArgs) {
     state->lineTo(xMin, yMax);
     state->closePath();
     state->clip();
-    builder->clip(state);
+    if (savedState)
+      builder->setClipPath(state);
+    else
+      builder->clip(state);
     state->clearPath();
   }
 
   // set the color space
-  state->setFillColorSpace(shading->getColorSpace()->copy());
+  if (savedState)
+    state->setFillColorSpace(shading->getColorSpace()->copy());
 
   // do shading type-specific operations
   switch (shading->getType()) {
@@ -1560,7 +1606,10 @@ void PdfParser::opShFill(Object args[], int numArgs) {
     break;
   case 2:
   case 3:
-    // no need to implement these
+    if (clipHistory->getClipPath()) {
+      builder->addShadedFill(shading, matrix, clipHistory->getClipPath(),
+                             clipHistory->getClipType() == clipEO ? true : false);
+    }
     break;
   case 4:
   case 5:
@@ -1573,8 +1622,10 @@ void PdfParser::opShFill(Object args[], int numArgs) {
   }
 
   // restore graphics state
-  restoreState();
-  state->setPath(savedPath);
+  if (savedState) {
+    restoreState();
+    state->setPath(savedPath);
+  }
 
   delete shading;
 }
@@ -1598,6 +1649,7 @@ void PdfParser::doFunctionShFill1(GfxFunctionShading *shading,
   GfxColor fillColor;
   GfxColor color0M, color1M, colorM0, colorM1, colorMM;
   GfxColor colors2[4];
+  double functionColorDelta = colorDeltas[pdfFunctionShading-1];
   double *matrix;
   double xM, yM;
   int nComps, i, j;
@@ -1625,7 +1677,7 @@ void PdfParser::doFunctionShFill1(GfxFunctionShading *shading,
   // -- fill the rectangle; but require at least one subdivision
   // (depth==0) to avoid problems when the four outer corners of the
   // shaded region are the same color
-  if ((i == 4 && depth > 0) || depth == functionMaxDepth) {
+  if ((i == 4 && depth > 0) || depth == maxDepths[pdfFunctionShading-1]) {
 
     // use the center color
     shading->getColor(xM, yM, &fillColor);
@@ -1717,16 +1769,17 @@ void PdfParser::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
                              double x2, double y2, GfxColor *color2,
                              int nComps, int depth) {
   double x01, y01, x12, y12, x20, y20;
+  double gouraudColorDelta = colorDeltas[pdfGouraudTriangleShading-1];
   GfxColor color01, color12, color20;
   int i;
 
   for (i = 0; i < nComps; ++i) {
     if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta ||
-       abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) {
+       abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) {
       break;
     }
   }
-  if (i == nComps || depth == gouraudMaxDepth) {
+  if (i == nComps || depth == maxDepths[pdfGouraudTriangleShading-1]) {
     state->setFillColor(color0);
     state->moveTo(x0, y0);
     state->lineTo(x1, y1);
@@ -1781,6 +1834,7 @@ void PdfParser::fillPatch(GfxPatch *patch, int nComps, int depth) {
   GfxPatch patch00, patch01, patch10, patch11;
   double xx[4][8], yy[4][8];
   double xxm, yym;
+  double patchColorDelta = colorDeltas[pdfPatchMeshShading-1];
   int i;
 
   for (i = 0; i < nComps; ++i) {
@@ -1795,7 +1849,7 @@ void PdfParser::fillPatch(GfxPatch *patch, int nComps, int depth) {
       break;
     }
   }
-  if (i == nComps || depth == patchMaxDepth) {
+  if (i == nComps || depth == maxDepths[pdfPatchMeshShading-1]) {
     state->setFillColor(&patch->color[0][0]);
     state->moveTo(patch->x[0][0], patch->y[0][0]);
     state->curveTo(patch->x[0][1], patch->y[0][1],
@@ -1908,8 +1962,10 @@ void PdfParser::doEndPath() {
   if (state->isCurPt() && clip != clipNone) {
     state->clip();
     if (clip == clipNormal) {
+      clipHistory->setClip(state->getPath(), clipNormal);
       builder->clip(state);
     } else {
+      clipHistory->setClip(state->getPath(), clipEO);
       builder->clip(state, true);
     }
   }
@@ -1936,6 +1992,7 @@ void PdfParser::opEOClip(Object args[], int numArgs) {
 void PdfParser::opBeginText(Object args[], int numArgs) {
   state->setTextMat(1, 0, 0, 1, 0, 0);
   state->textMoveTo(0, 0);
+  builder->updateTextPosition(0.0, 0.0);
   fontChanged = gTrue;
   builder->beginTextObject(state);
 }
@@ -1956,6 +2013,10 @@ void PdfParser::opSetFont(Object args[], int numArgs) {
   GfxFont *font;
 
   if (!(font = res->lookupFont(args[0].getName()))) {
+    // unsetting the font (drawing no text) is better than using the
+    // previous one and drawing random glyphs from it
+    state->setFont(NULL, args[1].getNum());
+    fontChanged = gTrue;
     return;
   }
   if (printCommands) {
@@ -1990,6 +2051,7 @@ void PdfParser::opSetWordSpacing(Object args[], int numArgs) {
 
 void PdfParser::opSetHorizScaling(Object args[], int numArgs) {
   state->setHorizScaling(args[0].getNum());
+  builder->updateTextMatrix(state);
   fontChanged = gTrue;
 }
 
@@ -2003,6 +2065,7 @@ void PdfParser::opTextMove(Object args[], int numArgs) {
   tx = state->getLineX() + args[0].getNum();
   ty = state->getLineY() + args[1].getNum();
   state->textMoveTo(tx, ty);
+  builder->updateTextPosition(tx, ty);
 }
 
 void PdfParser::opTextMoveSet(Object args[], int numArgs) {
@@ -2013,6 +2076,7 @@ void PdfParser::opTextMoveSet(Object args[], int numArgs) {
   state->setLeading(-ty);
   ty += state->getLineY();
   state->textMoveTo(tx, ty);
+  builder->updateTextPosition(tx, ty);
 }
 
 void PdfParser::opSetTextMatrix(Object args[], int numArgs) {
@@ -2020,6 +2084,8 @@ void PdfParser::opSetTextMatrix(Object args[], int numArgs) {
                    args[2].getNum(), args[3].getNum(),
                    args[4].getNum(), args[5].getNum());
   state->textMoveTo(0, 0);
+  builder->updateTextMatrix(state);
+  builder->updateTextPosition(0.0, 0.0);
   fontChanged = gTrue;
 }
 
@@ -2029,6 +2095,7 @@ void PdfParser::opTextNextLine(Object args[], int numArgs) {
   tx = state->getLineX();
   ty = state->getLineY() - state->getLeading();
   state->textMoveTo(tx, ty);
+  builder->updateTextPosition(tx, ty);
 }
 
 //------------------------------------------------------------------------
@@ -2037,7 +2104,7 @@ void PdfParser::opTextNextLine(Object args[], int numArgs) {
 
 void PdfParser::opShowText(Object args[], int numArgs) {
   if (!state->getFont()) {
-    error(getPos(), "No font in show");
+    error(getPos(), const_cast<char*>("No font in show"));
     return;
   }
   if (fontChanged) {
@@ -2051,7 +2118,7 @@ void PdfParser::opMoveShowText(Object args[], int numArgs) {
   double tx, ty;
 
   if (!state->getFont()) {
-    error(getPos(), "No font in move/show");
+    error(getPos(), const_cast<char*>("No font in move/show"));
     return;
   }
   if (fontChanged) {
@@ -2061,6 +2128,7 @@ void PdfParser::opMoveShowText(Object args[], int numArgs) {
   tx = state->getLineX();
   ty = state->getLineY() - state->getLeading();
   state->textMoveTo(tx, ty);
+  builder->updateTextPosition(tx, ty);
   doShowText(args[0].getString());
 }
 
@@ -2068,7 +2136,7 @@ void PdfParser::opMoveSetShowText(Object args[], int numArgs) {
   double tx, ty;
 
   if (!state->getFont()) {
-    error(getPos(), "No font in move/set/show");
+    error(getPos(), const_cast<char*>("No font in move/set/show"));
     return;
   }
   if (fontChanged) {
@@ -2080,6 +2148,7 @@ void PdfParser::opMoveSetShowText(Object args[], int numArgs) {
   tx = state->getLineX();
   ty = state->getLineY() - state->getLeading();
   state->textMoveTo(tx, ty);
+  builder->updateTextPosition(tx, ty);
   doShowText(args[2].getString());
 }
 
@@ -2090,7 +2159,7 @@ void PdfParser::opShowSpaceText(Object args[], int numArgs) {
   int i;
 
   if (!state->getFont()) {
-    error(getPos(), "No font in show/space");
+    error(getPos(), const_cast<char*>("No font in show/space"));
     return;
   }
   if (fontChanged) {
@@ -2111,22 +2180,35 @@ void PdfParser::opShowSpaceText(Object args[], int numArgs) {
        state->textShift(-obj.getNum() * 0.001 *
                         fabs(state->getFontSize()), 0);
       }
+      builder->updateTextShift(state, obj.getNum());
     } else if (obj.isString()) {
       doShowText(obj.getString());
     } else {
-      error(getPos(), "Element of show/space array must be number or string");
+      error(getPos(), const_cast<char*>("Element of show/space array must be number or string"));
     }
     obj.free();
   }
 }
 
+
+
+/*
+ * The `POPPLER_NEW_GFXFONT' stuff is for the change to GfxFont's getNextChar() call.
+ * Thanks to tsdgeos for the fix.
+ * Miklos, does this look ok?
+ */   
+
 void PdfParser::doShowText(GooString *s) {
   GfxFont *font;
   int wMode;
   double riseX, riseY;
   CharCode code;
+#ifdef POPPLER_NEW_GFXFONT
+  Unicode *u = NULL;
+#else
   Unicode u[8];
-  double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, lineX, lineY;
+#endif
+  double x, y, dx, dy, curX, curY, tdx, tdy, lineX, lineY;
   double originX, originY, tOriginX, tOriginY;
   double oldCTM[6], newCTM[6];
   double *mat;
@@ -2134,7 +2216,7 @@ void PdfParser::doShowText(GooString *s) {
   Dict *resDict;
   Parser *oldParser;
   char *p;
-  int len, n, uLen, nChars, nSpaces, i;
+  int len, n, uLen, i;
 
   font = state->getFont();
   wMode = font->getWMode();
@@ -2173,7 +2255,11 @@ void PdfParser::doShowText(GooString *s) {
     len = s->getLength();
     while (len > 0) {
       n = font->getNextChar(p, len, &code,
+#ifdef POPPLER_NEW_GFXFONT
+                           &u, &uLen,  /* TODO: This looks like a memory leak for u. */
+#else
                            u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
+#endif
                            &dx, &dy, &originX, &originY);
       dx = dx * state->getFontSize() + state->getCharSpace();
       if (n == 1 && *p == ' ') {
@@ -2196,7 +2282,7 @@ void PdfParser::doShowText(GooString *s) {
        if (charProc.isStream()) {
          //parse(&charProc, gFalse); // TODO: parse into SVG font
        } else {
-         error(getPos(), "Missing or bad Type3 CharProc entry");
+         error(getPos(), const_cast<char*>("Missing or bad Type3 CharProc entry"));
        }
        //out->endType3Char(state);
        if (resDict) {
@@ -2222,7 +2308,11 @@ void PdfParser::doShowText(GooString *s) {
     len = s->getLength();
     while (len > 0) {
       n = font->getNextChar(p, len, &code,
+#ifdef POPPLER_NEW_GFXFONT
+                           &u, &uLen,  /* TODO: This looks like a memory leak for u. */
+#else
                            u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
+#endif
                            &dx, &dy, &originX, &originY);
       
       if (wMode) {
@@ -2244,7 +2334,7 @@ void PdfParser::doShowText(GooString *s) {
       originY *= state->getFontSize();
       state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
       builder->addChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
-                      tdx, tdy, tOriginX, tOriginY, code, n, u, uLen);
+                       dx, dy, tOriginX, tOriginY, code, n, u, uLen);
       state->shift(tdx, tdy);
       p += n;
       len -= n;
@@ -2254,6 +2344,7 @@ void PdfParser::doShowText(GooString *s) {
   builder->endString(state);
 }
 
+
 //------------------------------------------------------------------------
 // XObject operators
 //------------------------------------------------------------------------
@@ -2267,25 +2358,25 @@ void PdfParser::opXObject(Object args[], int numArgs) {
     return;
   }
   if (!obj1.isStream()) {
-    error(getPos(), "XObject '%s' is wrong type", name);
+    error(getPos(), const_cast<char*>("XObject '%s' is wrong type"), name);
     obj1.free();
     return;
   }
-  obj1.streamGetDict()->lookup("Subtype", &obj2);
-  if (obj2.isName("Image")) {
+  obj1.streamGetDict()->lookup(const_cast<char*>("Subtype"), &obj2);
+  if (obj2.isName(const_cast<char*>("Image"))) {
     res->lookupXObjectNF(name, &refObj);
     doImage(&refObj, obj1.getStream(), gFalse);
     refObj.free();
-  } else if (obj2.isName("Form")) {
+  } else if (obj2.isName(const_cast<char*>("Form"))) {
     doForm(&obj1);
-  } else if (obj2.isName("PS")) {
-    obj1.streamGetDict()->lookup("Level1", &obj3);
+  } else if (obj2.isName(const_cast<char*>("PS"))) {
+    obj1.streamGetDict()->lookup(const_cast<char*>("Level1"), &obj3);
 /*    out->psXObject(obj1.getStream(),
                   obj3.isStream() ? obj3.getStream() : (Stream *)NULL);*/
   } else if (obj2.isName()) {
-    error(getPos(), "Unknown XObject subtype '%s'", obj2.getName());
+    error(getPos(), const_cast<char*>("Unknown XObject subtype '%s'"), obj2.getName());
   } else {
-    error(getPos(), "XObject subtype is missing or wrong type");
+    error(getPos(), const_cast<char*>("XObject subtype is missing or wrong type"));
   }
   obj2.free();
   obj1.free();
@@ -2318,10 +2409,10 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
   dict = str->getDict();
 
   // get size
-  dict->lookup("Width", &obj1);
+  dict->lookup(const_cast<char*>("Width"), &obj1);
   if (obj1.isNull()) {
     obj1.free();
-    dict->lookup("W", &obj1);
+    dict->lookup(const_cast<char*>("W"), &obj1);
   }
   if (obj1.isInt())
     width = obj1.getInt();
@@ -2330,10 +2421,10 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
   else
     goto err2;
   obj1.free();
-  dict->lookup("Height", &obj1);
+  dict->lookup(const_cast<char*>("Height"), &obj1);
   if (obj1.isNull()) {
     obj1.free();
-    dict->lookup("H", &obj1);
+    dict->lookup(const_cast<char*>("H"), &obj1);
   }
   if (obj1.isInt())
     height = obj1.getInt();
@@ -2344,10 +2435,10 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
   obj1.free();
 
   // image or mask?
-  dict->lookup("ImageMask", &obj1);
+  dict->lookup(const_cast<char*>("ImageMask"), &obj1);
   if (obj1.isNull()) {
     obj1.free();
-    dict->lookup("IM", &obj1);
+    dict->lookup(const_cast<char*>("IM"), &obj1);
   }
   mask = gFalse;
   if (obj1.isBool())
@@ -2358,10 +2449,10 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
 
   // bit depth
   if (bits == 0) {
-    dict->lookup("BitsPerComponent", &obj1);
+    dict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
     if (obj1.isNull()) {
       obj1.free();
-      dict->lookup("BPC", &obj1);
+      dict->lookup(const_cast<char*>("BPC"), &obj1);
     }
     if (obj1.isInt()) {
       bits = obj1.getInt();
@@ -2380,10 +2471,10 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
     if (bits != 1)
       goto err1;
     invert = gFalse;
-    dict->lookup("Decode", &obj1);
+    dict->lookup(const_cast<char*>("Decode"), &obj1);
     if (obj1.isNull()) {
       obj1.free();
-      dict->lookup("D", &obj1);
+      dict->lookup(const_cast<char*>("D"), &obj1);
     }
     if (obj1.isArray()) {
       obj1.arrayGet(0, &obj2);
@@ -2396,15 +2487,15 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
     obj1.free();
 
     // draw it
-    //out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
+    builder->addImageMask(state, str, width, height, invert);
 
   } else {
 
     // get color space and color map
-    dict->lookup("ColorSpace", &obj1);
+    dict->lookup(const_cast<char*>("ColorSpace"), &obj1);
     if (obj1.isNull()) {
       obj1.free();
-      dict->lookup("CS", &obj1);
+      dict->lookup(const_cast<char*>("CS"), &obj1);
     }
     if (obj1.isName()) {
       res->lookupColorSpace(obj1.getName(), &obj2);
@@ -2430,10 +2521,10 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
     if (!colorSpace) {
       goto err1;
     }
-    dict->lookup("Decode", &obj1);
+    dict->lookup(const_cast<char*>("Decode"), &obj1);
     if (obj1.isNull()) {
       obj1.free();
-      dict->lookup("D", &obj1);
+      dict->lookup(const_cast<char*>("D"), &obj1);
     }
     colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
     obj1.free();
@@ -2448,8 +2539,8 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
     maskWidth = maskHeight = 0; // make gcc happy
     maskInvert = gFalse; // make gcc happy
     maskColorMap = NULL; // make gcc happy
-    dict->lookup("Mask", &maskObj);
-    dict->lookup("SMask", &smaskObj);
+    dict->lookup(const_cast<char*>("Mask"), &maskObj);
+    dict->lookup(const_cast<char*>("SMask"), &smaskObj);
     if (smaskObj.isStream()) {
       // soft mask
       if (inlineImg) {
@@ -2457,40 +2548,40 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
       }
       maskStr = smaskObj.getStream();
       maskDict = smaskObj.streamGetDict();
-      maskDict->lookup("Width", &obj1);
+      maskDict->lookup(const_cast<char*>("Width"), &obj1);
       if (obj1.isNull()) {
        obj1.free();
-       maskDict->lookup("W", &obj1);
+       maskDict->lookup(const_cast<char*>("W"), &obj1);
       }
       if (!obj1.isInt()) {
        goto err2;
       }
       maskWidth = obj1.getInt();
       obj1.free();
-      maskDict->lookup("Height", &obj1);
+      maskDict->lookup(const_cast<char*>("Height"), &obj1);
       if (obj1.isNull()) {
        obj1.free();
-       maskDict->lookup("H", &obj1);
+       maskDict->lookup(const_cast<char*>("H"), &obj1);
       }
       if (!obj1.isInt()) {
        goto err2;
       }
       maskHeight = obj1.getInt();
       obj1.free();
-      maskDict->lookup("BitsPerComponent", &obj1);
+      maskDict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
       if (obj1.isNull()) {
        obj1.free();
-       maskDict->lookup("BPC", &obj1);
+       maskDict->lookup(const_cast<char*>("BPC"), &obj1);
       }
       if (!obj1.isInt()) {
        goto err2;
       }
       maskBits = obj1.getInt();
       obj1.free();
-      maskDict->lookup("ColorSpace", &obj1);
+      maskDict->lookup(const_cast<char*>("ColorSpace"), &obj1);
       if (obj1.isNull()) {
        obj1.free();
-       maskDict->lookup("CS", &obj1);
+       maskDict->lookup(const_cast<char*>("CS"), &obj1);
       }
       if (obj1.isName()) {
        res->lookupColorSpace(obj1.getName(), &obj2);
@@ -2506,10 +2597,10 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
       if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
        goto err1;
       }
-      maskDict->lookup("Decode", &obj1);
+      maskDict->lookup(const_cast<char*>("Decode"), &obj1);
       if (obj1.isNull()) {
        obj1.free();
-       maskDict->lookup("D", &obj1);
+       maskDict->lookup(const_cast<char*>("D"), &obj1);
       }
       maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
       obj1.free();
@@ -2536,40 +2627,40 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
       }
       maskStr = maskObj.getStream();
       maskDict = maskObj.streamGetDict();
-      maskDict->lookup("Width", &obj1);
+      maskDict->lookup(const_cast<char*>("Width"), &obj1);
       if (obj1.isNull()) {
        obj1.free();
-       maskDict->lookup("W", &obj1);
+       maskDict->lookup(const_cast<char*>("W"), &obj1);
       }
       if (!obj1.isInt()) {
        goto err2;
       }
       maskWidth = obj1.getInt();
       obj1.free();
-      maskDict->lookup("Height", &obj1);
+      maskDict->lookup(const_cast<char*>("Height"), &obj1);
       if (obj1.isNull()) {
        obj1.free();
-       maskDict->lookup("H", &obj1);
+       maskDict->lookup(const_cast<char*>("H"), &obj1);
       }
       if (!obj1.isInt()) {
        goto err2;
       }
       maskHeight = obj1.getInt();
       obj1.free();
-      maskDict->lookup("ImageMask", &obj1);
+      maskDict->lookup(const_cast<char*>("ImageMask"), &obj1);
       if (obj1.isNull()) {
        obj1.free();
-       maskDict->lookup("IM", &obj1);
+       maskDict->lookup(const_cast<char*>("IM"), &obj1);
       }
       if (!obj1.isBool() || !obj1.getBool()) {
        goto err2;
       }
       obj1.free();
       maskInvert = gFalse;
-      maskDict->lookup("Decode", &obj1);
+      maskDict->lookup(const_cast<char*>("Decode"), &obj1);
       if (obj1.isNull()) {
        obj1.free();
-       maskDict->lookup("D", &obj1);
+       maskDict->lookup(const_cast<char*>("D"), &obj1);
       }
       if (obj1.isArray()) {
        obj1.arrayGet(0, &obj2);
@@ -2586,12 +2677,12 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
 
     // draw it
     if (haveSoftMask) {
-/*      out->drawSoftMaskedImage(state, ref, str, width, height, colorMap,
-                              maskStr, maskWidth, maskHeight, maskColorMap);*/
+        builder->addSoftMaskedImage(state, str, width, height, colorMap,
+                                    maskStr, maskWidth, maskHeight, maskColorMap);
       delete maskColorMap;
     } else if (haveExplicitMask) {
-/*      out->drawMaskedImage(state, ref, str, width, height, colorMap,
-                          maskStr, maskWidth, maskHeight, maskInvert);*/
+        builder->addMaskedImage(state, str, width, height, colorMap,
+                                maskStr, maskWidth, maskHeight, maskInvert);
     } else {
       builder->addImage(state, str, width, height, colorMap,
                        haveColorKeyMask ? maskColors : (int *)NULL);
@@ -2607,7 +2698,7 @@ void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
  err2:
   obj1.free();
  err1:
-  error(getPos(), "Bad image parameters");
+  error(getPos(), const_cast<char*>("Bad image parameters"));
 }
 
 void PdfParser::doForm(Object *str) {
@@ -2630,17 +2721,17 @@ void PdfParser::doForm(Object *str) {
   dict = str->streamGetDict();
 
   // check form type
-  dict->lookup("FormType", &obj1);
+  dict->lookup(const_cast<char*>("FormType"), &obj1);
   if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
-    error(getPos(), "Unknown form type");
+    error(getPos(), const_cast<char*>("Unknown form type"));
   }
   obj1.free();
 
   // get bounding box
-  dict->lookup("BBox", &bboxObj);
+  dict->lookup(const_cast<char*>("BBox"), &bboxObj);
   if (!bboxObj.isArray()) {
     bboxObj.free();
-    error(getPos(), "Bad form bounding box");
+    error(getPos(), const_cast<char*>("Bad form bounding box"));
     return;
   }
   for (i = 0; i < 4; ++i) {
@@ -2651,7 +2742,7 @@ void PdfParser::doForm(Object *str) {
   bboxObj.free();
 
   // get matrix
-  dict->lookup("Matrix", &matrixObj);
+  dict->lookup(const_cast<char*>("Matrix"), &matrixObj);
   if (matrixObj.isArray()) {
     for (i = 0; i < 6; ++i) {
       matrixObj.arrayGet(i, &obj1);
@@ -2666,24 +2757,24 @@ void PdfParser::doForm(Object *str) {
   matrixObj.free();
 
   // get resources
-  dict->lookup("Resources", &resObj);
+  dict->lookup(const_cast<char*>("Resources"), &resObj);
   resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
 
   // check for a transparency group
   transpGroup = isolated = knockout = gFalse;
   blendingColorSpace = NULL;
-  if (dict->lookup("Group", &obj1)->isDict()) {
-    if (obj1.dictLookup("S", &obj2)->isName("Transparency")) {
+  if (dict->lookup(const_cast<char*>("Group"), &obj1)->isDict()) {
+    if (obj1.dictLookup(const_cast<char*>("S"), &obj2)->isName(const_cast<char*>("Transparency"))) {
       transpGroup = gTrue;
-      if (!obj1.dictLookup("CS", &obj3)->isNull()) {
+      if (!obj1.dictLookup(const_cast<char*>("CS"), &obj3)->isNull()) {
        blendingColorSpace = GfxColorSpace::parse(&obj3);
       }
       obj3.free();
-      if (obj1.dictLookup("I", &obj3)->isBool()) {
+      if (obj1.dictLookup(const_cast<char*>("I"), &obj3)->isBool()) {
        isolated = obj3.getBool();
       }
       obj3.free();
-      if (obj1.dictLookup("K", &obj3)->isBool()) {
+      if (obj1.dictLookup(const_cast<char*>("K"), &obj3)->isBool()) {
        knockout = obj3.getBool();
       }
       obj3.free();
@@ -2723,6 +2814,12 @@ void PdfParser::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox
   // kill any pre-existing path
   state->clearPath();
 
+  if (softMask || transpGroup) {
+    builder->clearSoftMask(state);
+    builder->pushTransparencyGroup(state, bbox, blendingColorSpace,
+                                   isolated, knockout, softMask);
+  }
+
   // save current parser
   oldParser = parser;
 
@@ -2739,6 +2836,7 @@ void PdfParser::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox
   state->lineTo(bbox[0], bbox[3]);
   state->closePath();
   state->clip();
+  clipHistory->setClip(state->getPath());
   builder->clip(state);
   state->clearPath();
 
@@ -2747,14 +2845,12 @@ void PdfParser::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox
       state->setBlendMode(gfxBlendNormal);
     }
     if (state->getFillOpacity() != 1) {
+      builder->setGroupOpacity(state->getFillOpacity());
       state->setFillOpacity(1);
     }
     if (state->getStrokeOpacity() != 1) {
       state->setStrokeOpacity(1);
     }
-    //out->clearSoftMask(state);
-    //out->beginTransparencyGroup(state, bbox, blendingColorSpace,
-    //                         isolated, knockout, softMask);
   }
 
   // set new base matrix
@@ -2766,10 +2862,6 @@ void PdfParser::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox
   // draw the form
   parse(str, gFalse);
 
-  if (softMask || transpGroup) {
-    //out->endTransparencyGroup(state);
-  }
-
   // restore base matrix
   for (i = 0; i < 6; ++i) {
     baseMatrix[i] = oldBaseMatrix[i];
@@ -2778,6 +2870,10 @@ void PdfParser::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox
   // restore parser
   parser = oldParser;
 
+  if (softMask || transpGroup) {
+      builder->popTransparencyGroup(state);
+  }
+
   // restore graphics state
   restoreState();
 
@@ -2785,9 +2881,9 @@ void PdfParser::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox
   popResources();
 
   if (softMask) {
-    //out->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
+    builder->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
   } else if (transpGroup) {
-    //out->paintTransparencyGroup(state, bbox);
+    builder->paintTransparencyGroup(state, bbox);
   }
 
   return;
@@ -2828,9 +2924,9 @@ Stream *PdfParser::buildImageStream() {
   // build dictionary
   dict.initDict(xref);
   parser->getObj(&obj);
-  while (!obj.isCmd("ID") && !obj.isEOF()) {
+  while (!obj.isCmd(const_cast<char*>("ID")) && !obj.isEOF()) {
     if (!obj.isName()) {
-      error(getPos(), "Inline image dictionary key must be a name object");
+      error(getPos(), const_cast<char*>("Inline image dictionary key must be a name object"));
       obj.free();
     } else {
       key = copyString(obj.getName());
@@ -2845,7 +2941,7 @@ Stream *PdfParser::buildImageStream() {
     parser->getObj(&obj);
   }
   if (obj.isEOF()) {
-    error(getPos(), "End of file in inline image");
+    error(getPos(), const_cast<char*>("End of file in inline image"));
     obj.free();
     dict.free();
     return NULL;
@@ -2860,11 +2956,11 @@ Stream *PdfParser::buildImageStream() {
 }
 
 void PdfParser::opImageData(Object args[], int numArgs) {
-  error(getPos(), "Internal: got 'ID' operator");
+  error(getPos(), const_cast<char*>("Internal: got 'ID' operator"));
 }
 
 void PdfParser::opEndImage(Object args[], int numArgs) {
-  error(getPos(), "Internal: got 'EI' operator");
+  error(getPos(), const_cast<char*>("Internal: got 'EI' operator"));
 }
 
 //------------------------------------------------------------------------
@@ -2938,9 +3034,11 @@ void PdfParser::opMarkPoint(Object args[], int numArgs) {
 void PdfParser::saveState() {
   builder->saveState();
   state = state->save();
+  clipHistory = clipHistory->save();
 }
 
 void PdfParser::restoreState() {
+  clipHistory = clipHistory->restore();
   state = state->restore();
   builder->restoreState();
 }
@@ -2957,4 +3055,86 @@ void PdfParser::popResources() {
   res = resPtr;
 }
 
+void PdfParser::setDefaultApproximationPrecision() {
+  int i;
+
+  for (i = 1; i <= pdfNumShadingTypes; ++i) {
+    setApproximationPrecision(i, defaultShadingColorDelta, defaultShadingMaxDepth);
+  }
+}
+
+void PdfParser::setApproximationPrecision(int shadingType, double colorDelta,
+                                          int maxDepth) {
+
+  if (shadingType > pdfNumShadingTypes || shadingType < 1) {
+    return;
+  }
+  colorDeltas[shadingType-1] = dblToCol(colorDelta);
+  maxDepths[shadingType-1] = maxDepth;
+}
+
+//------------------------------------------------------------------------
+// ClipHistoryEntry
+//------------------------------------------------------------------------
+
+ClipHistoryEntry::ClipHistoryEntry(GfxPath *clipPathA, GfxClipType clipTypeA) {
+    if (clipPathA) {
+        clipPath = clipPathA->copy();
+    } else {
+        clipPath = NULL;
+    }
+    clipType = clipTypeA;
+    saved = NULL;
+}
+
+ClipHistoryEntry::~ClipHistoryEntry() {
+    if (clipPath) {
+        delete clipPath;
+    }
+}
+
+void ClipHistoryEntry::setClip(GfxPath *clipPathA, GfxClipType clipTypeA) {
+    // Free previous clip path
+    if (clipPath) {
+        delete clipPath;
+    }
+    if (clipPathA) {
+        clipPath = clipPathA->copy();
+        clipType = clipTypeA;
+    } else {
+        clipPath = NULL;
+    }
+}
+
+ClipHistoryEntry *ClipHistoryEntry::save() {
+    ClipHistoryEntry *newEntry = new ClipHistoryEntry(this);
+    newEntry->saved = this;
+
+    return newEntry;
+}
+
+ClipHistoryEntry *ClipHistoryEntry::restore() {
+    ClipHistoryEntry *oldEntry;
+
+    if (saved) {
+        oldEntry = saved;
+        saved = NULL;
+        delete this;
+    } else {
+        oldEntry = this;
+    }
+
+    return oldEntry;
+}
+
+ClipHistoryEntry::ClipHistoryEntry(ClipHistoryEntry *other) {
+    if (other->clipPath) {
+        this->clipPath = other->clipPath->copy();
+        this->clipType = other->clipType;
+    } else {
+        this->clipPath = NULL;
+    }
+    saved = NULL;
+}
+
 #endif /* HAVE_POPPLER */