summaryrefslogtreecommitdiff
path: root/xpdf/Gfx.cc
diff options
context:
space:
mode:
Diffstat (limited to 'xpdf/Gfx.cc')
-rw-r--r--xpdf/Gfx.cc720
1 files changed, 464 insertions, 256 deletions
diff --git a/xpdf/Gfx.cc b/xpdf/Gfx.cc
index 1979f84..0fa48f8 100644
--- a/xpdf/Gfx.cc
+++ b/xpdf/Gfx.cc
@@ -2,7 +2,7 @@
//
// Gfx.cc
//
-// Copyright 1996-2003 Glyph & Cog, LLC
+// Copyright 1996-2013 Glyph & Cog, LLC
//
//========================================================================
@@ -36,7 +36,7 @@
#include "Annot.h"
#include "OptionalContent.h"
#include "Error.h"
-#include "PDFDocEncoding.h"
+#include "TextString.h"
#include "Gfx.h"
// the MSVC math.h doesn't define this
@@ -80,11 +80,15 @@
// fill.
#define patchColorDelta (dblToCol(1 / 256.0))
+// Max errors (undefined operator, wrong number of args) allowed before
+// giving up on a content stream.
+#define contentStreamErrorLimit 500
+
//------------------------------------------------------------------------
// Operator table
//------------------------------------------------------------------------
-#ifdef WIN32 // this works around a bug in the VC7 compiler
+#ifdef _WIN32 // this works around a bug in the VC7 compiler
# pragma optimize("",off)
#endif
@@ -257,7 +261,7 @@ Operator Gfx::opTab[] = {
&Gfx::opCurveTo2},
};
-#ifdef WIN32 // this works around a bug in the VC7 compiler
+#ifdef _WIN32 // this works around a bug in the VC7 compiler
# pragma optimize("",on)
#endif
@@ -337,15 +341,31 @@ GfxFont *GfxResources::lookupFont(char *name) {
for (resPtr = this; resPtr; resPtr = resPtr->next) {
if (resPtr->fonts) {
- if ((font = resPtr->fonts->lookup(name)))
+ if ((font = resPtr->fonts->lookup(name))) {
return font;
+ }
}
}
error(errSyntaxError, -1, "Unknown font tag '{0:s}'", name);
return NULL;
}
-GBool GfxResources::lookupXObject(char *name, Object *obj) {
+GfxFont *GfxResources::lookupFontByRef(Ref ref) {
+ GfxFont *font;
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->fonts) {
+ if ((font = resPtr->fonts->lookupByRef(ref))) {
+ return font;
+ }
+ }
+ }
+ error(errSyntaxError, -1, "Unknown font ref {0:d}.{1:d}", ref.num, ref.gen);
+ return NULL;
+}
+
+GBool GfxResources::lookupXObject(const char *name, Object *obj) {
GfxResources *resPtr;
for (resPtr = this; resPtr; resPtr = resPtr->next) {
@@ -359,7 +379,7 @@ GBool GfxResources::lookupXObject(char *name, Object *obj) {
return gFalse;
}
-GBool GfxResources::lookupXObjectNF(char *name, Object *obj) {
+GBool GfxResources::lookupXObjectNF(const char *name, Object *obj) {
GfxResources *resPtr;
for (resPtr = this; resPtr; resPtr = resPtr->next) {
@@ -373,9 +393,16 @@ GBool GfxResources::lookupXObjectNF(char *name, Object *obj) {
return gFalse;
}
-void GfxResources::lookupColorSpace(char *name, Object *obj) {
+void GfxResources::lookupColorSpace(const char *name, Object *obj) {
GfxResources *resPtr;
+ //~ should also test for G, RGB, and CMYK - but only in inline images (?)
+ if (!strcmp(name, "DeviceGray") ||
+ !strcmp(name, "DeviceRGB") ||
+ !strcmp(name, "DeviceCMYK")) {
+ obj->initNull();
+ return;
+ }
for (resPtr = this; resPtr; resPtr = resPtr->next) {
if (resPtr->colorSpaceDict.isDict()) {
if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) {
@@ -387,15 +414,19 @@ void GfxResources::lookupColorSpace(char *name, Object *obj) {
obj->initNull();
}
-GfxPattern *GfxResources::lookupPattern(char *name) {
+GfxPattern *GfxResources::lookupPattern(const char *name
+ ) {
GfxResources *resPtr;
GfxPattern *pattern;
- Object obj;
+ Object objRef, obj;
for (resPtr = this; resPtr; resPtr = resPtr->next) {
if (resPtr->patternDict.isDict()) {
if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) {
- pattern = GfxPattern::parse(&obj);
+ resPtr->patternDict.dictLookupNF(name, &objRef);
+ pattern = GfxPattern::parse(&objRef, &obj
+ );
+ objRef.free();
obj.free();
return pattern;
}
@@ -406,7 +437,8 @@ GfxPattern *GfxResources::lookupPattern(char *name) {
return NULL;
}
-GfxShading *GfxResources::lookupShading(char *name) {
+GfxShading *GfxResources::lookupShading(const char *name
+ ) {
GfxResources *resPtr;
GfxShading *shading;
Object obj;
@@ -414,7 +446,8 @@ GfxShading *GfxResources::lookupShading(char *name) {
for (resPtr = this; resPtr; resPtr = resPtr->next) {
if (resPtr->shadingDict.isDict()) {
if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) {
- shading = GfxShading::parse(&obj);
+ shading = GfxShading::parse(&obj
+ );
obj.free();
return shading;
}
@@ -425,7 +458,7 @@ GfxShading *GfxResources::lookupShading(char *name) {
return NULL;
}
-GBool GfxResources::lookupGState(char *name, Object *obj) {
+GBool GfxResources::lookupGState(const char *name, Object *obj) {
GfxResources *resPtr;
for (resPtr = this; resPtr; resPtr = resPtr->next) {
@@ -440,7 +473,7 @@ GBool GfxResources::lookupGState(char *name, Object *obj) {
return gFalse;
}
-GBool GfxResources::lookupPropertiesNF(char *name, Object *obj) {
+GBool GfxResources::lookupPropertiesNF(const char *name, Object *obj) {
GfxResources *resPtr;
for (resPtr = this; resPtr; resPtr = resPtr->next) {
@@ -491,6 +524,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict,
markedContentStack = new GList();
ocState = gTrue;
parser = NULL;
+ contentStreamStack = new GList();
abortCheckCbk = abortCheckCbkA;
abortCheckCbkData = abortCheckCbkDataA;
@@ -535,6 +569,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict,
markedContentStack = new GList();
ocState = gTrue;
parser = NULL;
+ contentStreamStack = new GList();
abortCheckCbk = abortCheckCbkA;
abortCheckCbkData = abortCheckCbkDataA;
@@ -563,41 +598,99 @@ Gfx::~Gfx() {
popResources();
}
deleteGList(markedContentStack, GfxMarkedContent);
+ delete contentStreamStack;
}
-void Gfx::display(Object *obj, GBool topLevel) {
- Object obj2;
+void Gfx::display(Object *objRef, GBool topLevel) {
+ Object obj1, obj2;
int i;
- if (obj->isArray()) {
- for (i = 0; i < obj->arrayGetLength(); ++i) {
- obj->arrayGet(i, &obj2);
+ objRef->fetch(xref, &obj1);
+ if (obj1.isArray()) {
+ for (i = 0; i < obj1.arrayGetLength(); ++i) {
+ obj1.arrayGetNF(i, &obj2);
+ if (checkForContentStreamLoop(&obj2)) {
+ obj2.free();
+ obj1.free();
+ return;
+ }
+ obj2.free();
+ }
+ for (i = 0; i < obj1.arrayGetLength(); ++i) {
+ obj1.arrayGet(i, &obj2);
if (!obj2.isStream()) {
- error(errSyntaxError, -1, "Weird page contents");
+ error(errSyntaxError, -1, "Invalid object type for content stream");
obj2.free();
+ obj1.free();
return;
}
obj2.free();
}
- } else if (!obj->isStream()) {
- error(errSyntaxError, -1, "Weird page contents");
+ contentStreamStack->append(&obj1);
+ } else if (obj1.isStream()) {
+ if (checkForContentStreamLoop(objRef)) {
+ obj1.free();
+ return;
+ }
+ contentStreamStack->append(objRef);
+ } else {
+ error(errSyntaxError, -1, "Invalid object type for content stream");
+ obj1.free();
return;
}
- parser = new Parser(xref, new Lexer(xref, obj), gFalse);
+ parser = new Parser(xref, new Lexer(xref, &obj1), gFalse);
go(topLevel);
delete parser;
parser = NULL;
+ contentStreamStack->del(contentStreamStack->getLength() - 1);
+ obj1.free();
+}
+
+// If <ref> is already on contentStreamStack, i.e., if there is a loop
+// in the content streams, report an error, and return true.
+GBool Gfx::checkForContentStreamLoop(Object *ref) {
+ Object *objPtr;
+ Object obj1;
+ int i, j;
+
+ if (ref->isRef()) {
+ for (i = 0; i < contentStreamStack->getLength(); ++i) {
+ objPtr = (Object *)contentStreamStack->get(i);
+ if (objPtr->isRef()) {
+ if (ref->getRefNum() == objPtr->getRefNum() &&
+ ref->getRefGen() == objPtr->getRefGen()) {
+ error(errSyntaxError, -1, "Loop in content streams");
+ return gTrue;
+ }
+ } else if (objPtr->isArray()) {
+ for (j = 0; j < objPtr->arrayGetLength(); ++j) {
+ objPtr->arrayGetNF(j, &obj1);
+ if (obj1.isRef()) {
+ if (ref->getRefNum() == obj1.getRefNum() &&
+ ref->getRefGen() == obj1.getRefGen()) {
+ error(errSyntaxError, -1, "Loop in content streams");
+ obj1.free();
+ return gTrue;
+ }
+ }
+ obj1.free();
+ }
+ }
+ }
+ }
+ return gFalse;
}
void Gfx::go(GBool topLevel) {
Object obj;
Object args[maxArgs];
int numArgs, i;
- int lastAbortCheck;
+ int lastAbortCheck, errCount;
// scan a sequence of objects
updateLevel = 1; // make sure even empty pages trigger a call to dump()
lastAbortCheck = 0;
+ errCount = 0;
numArgs = 0;
parser->getObj(&obj);
while (!obj.isEOF()) {
@@ -613,7 +706,9 @@ void Gfx::go(GBool topLevel) {
printf("\n");
fflush(stdout);
}
- execOp(&obj, args, numArgs);
+ if (!execOp(&obj, args, numArgs)) {
+ ++errCount;
+ }
obj.free();
for (i = 0; i < numArgs; ++i)
args[i].free();
@@ -635,6 +730,13 @@ void Gfx::go(GBool topLevel) {
}
}
+ // check for too many errors
+ if (errCount > contentStreamErrorLimit) {
+ error(errSyntaxError, -1,
+ "Too many errors - giving up on this content stream");
+ break;
+ }
+
// got an argument - save it
} else if (numArgs < maxArgs) {
args[numArgs++] = obj;
@@ -678,7 +780,8 @@ void Gfx::go(GBool topLevel) {
}
}
-void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
+// Returns true if successful, false on error.
+GBool Gfx::execOp(Object *cmd, Object args[], int numArgs) {
Operator *op;
char *name;
Object *argPtr;
@@ -687,9 +790,11 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
// find operator
name = cmd->getCmd();
if (!(op = findOp(name))) {
- if (ignoreUndef == 0)
- error(errSyntaxError, getPos(), "Unknown operator '{0:s}'", name);
- return;
+ if (ignoreUndef > 0) {
+ return gTrue;
+ }
+ error(errSyntaxError, getPos(), "Unknown operator '{0:s}'", name);
+ return gFalse;
}
// type check args
@@ -698,7 +803,7 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
if (numArgs < op->numArgs) {
error(errSyntaxError, getPos(),
"Too few ({0:d}) args to '{1:s}' operator", numArgs, name);
- return;
+ return gFalse;
}
if (numArgs > op->numArgs) {
#if 0
@@ -713,7 +818,7 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
error(errSyntaxError, getPos(),
"Too many ({0:d}) args to '{1:s}' operator",
numArgs, name);
- return;
+ return gFalse;
}
}
for (i = 0; i < numArgs; ++i) {
@@ -721,12 +826,14 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
error(errSyntaxError, getPos(),
"Arg #{0:d} to '{1:s}' operator is wrong type ({2:s})",
i, name, argPtr[i].getTypeName());
- return;
+ return gFalse;
}
}
// do it
(this->*op->func)(argPtr, numArgs);
+
+ return gTrue;
}
Operator *Gfx::findOp(char *name) {
@@ -766,7 +873,7 @@ GBool Gfx::checkArg(Object *arg, TchkType type) {
return gFalse;
}
-int Gfx::getPos() {
+GFileOffset Gfx::getPos() {
return parser ? parser->getPos() : -1;
}
@@ -840,7 +947,7 @@ void Gfx::opSetLineWidth(Object args[], int numArgs) {
}
void Gfx::opSetExtGState(Object args[], int numArgs) {
- Object obj1, obj2, obj3, obj4, obj5;
+ Object obj1, obj2, obj3, objRef3, obj4, obj5;
Object args2[2];
GfxBlendMode mode;
GBool haveFillOP;
@@ -895,22 +1002,21 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
args2[1].free();
}
obj2.free();
-#if 0 //~ need to add a new version of GfxResources::lookupFont() that
- //~ takes an indirect ref instead of a name
+ if (obj1.dictLookup("FL", &obj2)->isNum()) {
+ opSetFlat(&obj2, 1);
+ }
+ obj2.free();
+
+ // font
if (obj1.dictLookup("Font", &obj2)->isArray() &&
obj2.arrayGetLength() == 2) {
- obj2.arrayGet(0, &args2[0]);
- obj2.arrayGet(1, &args2[1]);
- if (args2[0].isDict() && args2[1].isNum()) {
- opSetFont(args2, 2);
+ obj2.arrayGetNF(0, &obj3);
+ obj2.arrayGetNF(1, &obj4);
+ if (obj3.isRef() && obj4.isNum()) {
+ doSetFont(res->lookupFontByRef(obj3.getRef()), obj4.getNum());
}
- args2[0].free();
- args2[1].free();
- }
- obj2.free();
-#endif
- if (obj1.dictLookup("FL", &obj2)->isNum()) {
- opSetFlat(&obj2, 1);
+ obj3.free();
+ obj4.free();
}
obj2.free();
@@ -1045,7 +1151,8 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
blendingColorSpace = NULL;
isolated = knockout = gFalse;
if (!obj4.dictLookup("CS", &obj5)->isNull()) {
- blendingColorSpace = GfxColorSpace::parse(&obj5);
+ blendingColorSpace = GfxColorSpace::parse(&obj5
+ );
}
obj5.free();
if (obj4.dictLookup("I", &obj5)->isBool()) {
@@ -1066,8 +1173,10 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
}
}
}
- doSoftMask(&obj3, alpha, blendingColorSpace,
+ obj2.dictLookupNF("G", &objRef3);
+ doSoftMask(&obj3, &objRef3, alpha, blendingColorSpace,
isolated, knockout, funcs[0], &backdropColor);
+ objRef3.free();
if (funcs[0]) {
delete funcs[0];
}
@@ -1090,7 +1199,7 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
obj1.free();
}
-void Gfx::doSoftMask(Object *str, GBool alpha,
+void Gfx::doSoftMask(Object *str, Object *strRef, GBool alpha,
GfxColorSpace *blendingColorSpace,
GBool isolated, GBool knockout,
Function *transferFunc, GfxColor *backdropColor) {
@@ -1149,7 +1258,7 @@ void Gfx::doSoftMask(Object *str, GBool alpha,
// draw it
++formDepth;
- drawForm(str, resDict, m, bbox, gTrue, gTrue,
+ drawForm(strRef, resDict, m, bbox, gTrue, gTrue,
blendingColorSpace, isolated, knockout,
alpha, transferFunc, backdropColor);
--formDepth;
@@ -1171,7 +1280,7 @@ void Gfx::opSetFillGray(Object args[], int numArgs) {
GfxColor color;
state->setFillPattern(NULL);
- state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+ state->setFillColorSpace(GfxColorSpace::create(csDeviceGray));
out->updateFillColorSpace(state);
color.c[0] = dblToCol(args[0].getNum());
state->setFillColor(&color);
@@ -1182,7 +1291,7 @@ void Gfx::opSetStrokeGray(Object args[], int numArgs) {
GfxColor color;
state->setStrokePattern(NULL);
- state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
+ state->setStrokeColorSpace(GfxColorSpace::create(csDeviceGray));
out->updateStrokeColorSpace(state);
color.c[0] = dblToCol(args[0].getNum());
state->setStrokeColor(&color);
@@ -1194,7 +1303,7 @@ void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
int i;
state->setFillPattern(NULL);
- state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
+ state->setFillColorSpace(GfxColorSpace::create(csDeviceCMYK));
out->updateFillColorSpace(state);
for (i = 0; i < 4; ++i) {
color.c[i] = dblToCol(args[i].getNum());
@@ -1208,7 +1317,7 @@ void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
int i;
state->setStrokePattern(NULL);
- state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
+ state->setStrokeColorSpace(GfxColorSpace::create(csDeviceCMYK));
out->updateStrokeColorSpace(state);
for (i = 0; i < 4; ++i) {
color.c[i] = dblToCol(args[i].getNum());
@@ -1222,7 +1331,7 @@ void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
int i;
state->setFillPattern(NULL);
- state->setFillColorSpace(new GfxDeviceRGBColorSpace());
+ state->setFillColorSpace(GfxColorSpace::create(csDeviceRGB));
out->updateFillColorSpace(state);
for (i = 0; i < 3; ++i) {
color.c[i] = dblToCol(args[i].getNum());
@@ -1236,7 +1345,7 @@ void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
int i;
state->setStrokePattern(NULL);
- state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
+ state->setStrokeColorSpace(GfxColorSpace::create(csDeviceRGB));
out->updateStrokeColorSpace(state);
for (i = 0; i < 3; ++i) {
color.c[i] = dblToCol(args[i].getNum());
@@ -1253,9 +1362,11 @@ void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
state->setFillPattern(NULL);
res->lookupColorSpace(args[0].getName(), &obj);
if (obj.isNull()) {
- colorSpace = GfxColorSpace::parse(&args[0]);
+ colorSpace = GfxColorSpace::parse(&args[0]
+ );
} else {
- colorSpace = GfxColorSpace::parse(&obj);
+ colorSpace = GfxColorSpace::parse(&obj
+ );
}
obj.free();
if (colorSpace) {
@@ -1277,9 +1388,11 @@ void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) {
state->setStrokePattern(NULL);
res->lookupColorSpace(args[0].getName(), &obj);
if (obj.isNull()) {
- colorSpace = GfxColorSpace::parse(&args[0]);
+ colorSpace = GfxColorSpace::parse(&args[0]
+ );
} else {
- colorSpace = GfxColorSpace::parse(&obj);
+ colorSpace = GfxColorSpace::parse(&obj
+ );
}
obj.free();
if (colorSpace) {
@@ -1350,7 +1463,8 @@ void Gfx::opSetFillColorN(Object args[], int numArgs) {
out->updateFillColor(state);
}
if (args[numArgs-1].isName() &&
- (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
+ (pattern = res->lookupPattern(args[numArgs-1].getName()
+ ))) {
state->setFillPattern(pattern);
}
@@ -1395,7 +1509,8 @@ void Gfx::opSetStrokeColorN(Object args[], int numArgs) {
out->updateStrokeColor(state);
}
if (args[numArgs-1].isName() &&
- (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
+ (pattern = res->lookupPattern(args[numArgs-1].getName()
+ ))) {
state->setStrokePattern(pattern);
}
@@ -1751,11 +1866,11 @@ void Gfx::doPatternText() {
}
void Gfx::doPatternImageMask(Object *ref, Stream *str, int width, int height,
- GBool invert, GBool inlineImg) {
+ GBool invert, GBool inlineImg, GBool interpolate) {
saveState();
out->setSoftMaskFromImageMask(state, ref, str,
- width, height, invert, inlineImg);
+ width, height, invert, inlineImg, interpolate);
state->clearPath();
state->moveTo(0, 0);
@@ -1773,11 +1888,11 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
GfxPatternColorSpace *patCS;
GfxColorSpace *cs;
GfxState *savedState;
- double xMin, yMin, xMax, yMax, x, y, x1, y1;
+ double xMin, yMin, xMax, yMax, x, y, x1, y1, t;
double cxMin, cyMin, cxMax, cyMax;
int xi0, yi0, xi1, yi1, xi, yi;
double *ctm, *btm, *ptm;
- double m[6], ictm[6], m1[6], imb[6];
+ double bbox[4], m[6], ictm[6], m1[6], imb[6];
double det;
double xstep, ystep;
int i;
@@ -1791,7 +1906,12 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
btm = baseMatrix;
ptm = tPat->getMatrix();
// iCTM = invert CTM
- det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ det = ctm[0] * ctm[3] - ctm[1] * ctm[2];
+ if (fabs(det) < 0.000001) {
+ error(errSyntaxError, getPos(), "Singular matrix in tiling pattern fill");
+ return;
+ }
+ det = 1 / det;
ictm[0] = ctm[3] * det;
ictm[1] = -ctm[1] * det;
ictm[2] = -ctm[2] * det;
@@ -1814,7 +1934,12 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
// construct a (device space) -> (pattern space) transform matrix
- det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]);
+ det = m1[0] * m1[3] - m1[1] * m1[2];
+ if (fabs(det) < 0.000001) {
+ error(errSyntaxError, getPos(), "Singular matrix in tiling pattern fill");
+ return;
+ }
+ det = 1 / det;
imb[0] = m1[3] * det;
imb[1] = -m1[1] * det;
imb[2] = -m1[2] * det;
@@ -1839,9 +1964,9 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
out->updateFillColor(state);
out->updateStrokeColor(state);
} else {
- state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+ state->setFillColorSpace(GfxColorSpace::create(csDeviceGray));
out->updateFillColorSpace(state);
- state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
+ state->setStrokeColorSpace(GfxColorSpace::create(csDeviceGray));
out->updateStrokeColorSpace(state);
}
if (!stroke) {
@@ -1912,21 +2037,31 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
// draw the pattern
//~ this should treat negative steps differently -- start at right/top
//~ edge instead of left/bottom (?)
+ bbox[0] = tPat->getBBox()[0];
+ bbox[1] = tPat->getBBox()[1];
+ bbox[2] = tPat->getBBox()[2];
+ bbox[3] = tPat->getBBox()[3];
+ if (bbox[0] > bbox[2]) {
+ t = bbox[0]; bbox[0] = bbox[2]; bbox[2] = t;
+ }
+ if (bbox[1] > bbox[3]) {
+ t = bbox[1]; bbox[1] = bbox[3]; bbox[3] = t;
+ }
xstep = fabs(tPat->getXStep());
ystep = fabs(tPat->getYStep());
- xi0 = (int)ceil((xMin - tPat->getBBox()[2]) / xstep);
- xi1 = (int)floor((xMax - tPat->getBBox()[0]) / xstep) + 1;
- yi0 = (int)ceil((yMin - tPat->getBBox()[3]) / ystep);
- yi1 = (int)floor((yMax - tPat->getBBox()[1]) / ystep) + 1;
+ xi0 = (int)ceil((xMin - bbox[2]) / xstep);
+ xi1 = (int)floor((xMax - bbox[0]) / xstep) + 1;
+ yi0 = (int)ceil((yMin - bbox[3]) / ystep);
+ yi1 = (int)floor((yMax - bbox[1]) / ystep) + 1;
for (i = 0; i < 4; ++i) {
m1[i] = m[i];
}
if (out->useTilingPatternFill()) {
m1[4] = m[4];
m1[5] = m[5];
- out->tilingPatternFill(state, this, tPat->getContentStream(),
+ out->tilingPatternFill(state, this, tPat->getContentStreamRef(),
tPat->getPaintType(), tPat->getResDict(),
- m1, tPat->getBBox(),
+ m1, bbox,
xi0, yi0, xi1, yi1, xstep, ystep);
} else {
for (yi = yi0; yi < yi1; ++yi) {
@@ -1935,8 +2070,8 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
y = yi * ystep;
m1[4] = x * m[0] + y * m[2] + m[4];
m1[5] = x * m[1] + y * m[3] + m[5];
- drawForm(tPat->getContentStream(), tPat->getResDict(),
- m1, tPat->getBBox());
+ drawForm(tPat->getContentStreamRef(), tPat->getResDict(),
+ m1, bbox);
}
}
}
@@ -1979,7 +2114,12 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat,
btm = baseMatrix;
ptm = sPat->getMatrix();
// iCTM = invert CTM
- det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ det = ctm[0] * ctm[3] - ctm[1] * ctm[2];
+ if (fabs(det) < 0.000001) {
+ error(errSyntaxError, getPos(), "Singular matrix in shading pattern fill");
+ return;
+ }
+ det = 1 / det;
ictm[0] = ctm[3] * det;
ictm[1] = -ctm[1] * det;
ictm[2] = -ctm[2] * det;
@@ -2074,11 +2214,16 @@ void Gfx::opShFill(Object args[], int numArgs) {
GfxState *savedState;
double xMin, yMin, xMax, yMax;
+ if (!out->needNonText()) {
+ return;
+ }
+
if (!ocState) {
return;
}
- if (!(shading = res->lookupShading(args[0].getName()))) {
+ if (!(shading = res->lookupShading(args[0].getName()
+ ))) {
return;
}
@@ -2487,7 +2632,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
GfxColor colorA, colorB;
double xa, ya, xb, yb, ra, rb;
double ta, tb, sa, sb;
- double sz, sMin, sMax, h;
+ double sMin, sMax, h;
double sLeft, sRight, sTop, sBottom, sZero, sDiag;
GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero;
GBool haveSMin, haveSMax;
@@ -2513,18 +2658,14 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
if (h == 0) {
enclosed = gTrue;
theta = 0; // make gcc happy
- sz = 0; // make gcc happy
} else if (r1 - r0 == 0) {
enclosed = gFalse;
theta = 0;
- sz = 0; // make gcc happy
- } else if (fabs(r1 - r0) >= h) {
+ } else if (fabs(r1 - r0) >= h - 0.0001) {
enclosed = gTrue;
theta = 0; // make gcc happy
- sz = 0; // make gcc happy
} else {
enclosed = gFalse;
- sz = -r0 / (r1 - r0);
theta = asin((r1 - r0) / h);
}
if (enclosed) {
@@ -2598,7 +2739,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
haveSMin = gTrue;
}
}
- if (haveSZero && sZero < 0) {
+ if (haveSZero && sZero <= 0) {
if (!haveSMin || sZero > sMin) {
sMin = sZero;
}
@@ -2865,34 +3006,56 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
double x0, y0, x1, y1, x2, y2;
- GfxColor color0, color1, color2;
+ double color0[gfxColorMaxComps];
+ double color1[gfxColorMaxComps];
+ double color2[gfxColorMaxComps];
int i;
for (i = 0; i < shading->getNTriangles(); ++i) {
- shading->getTriangle(i, &x0, &y0, &color0,
- &x1, &y1, &color1,
- &x2, &y2, &color2);
- gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2,
- shading->getColorSpace()->getNComps(), 0);
+ shading->getTriangle(i, &x0, &y0, color0,
+ &x1, &y1, color1,
+ &x2, &y2, color2);
+ gouraudFillTriangle(x0, y0, color0, x1, y1, color1, x2, y2, color2,
+ shading, 0);
}
}
-void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
- double x1, double y1, GfxColor *color1,
- double x2, double y2, GfxColor *color2,
- int nComps, int depth) {
+void Gfx::gouraudFillTriangle(double x0, double y0, double *color0,
+ double x1, double y1, double *color1,
+ double x2, double y2, double *color2,
+ GfxGouraudTriangleShading *shading, int depth) {
+ double dx0, dy0, dx1, dy1, dx2, dy2;
double x01, y01, x12, y12, x20, y20;
- GfxColor color01, color12, color20;
- int i;
-
+ double color01[gfxColorMaxComps];
+ double color12[gfxColorMaxComps];
+ double color20[gfxColorMaxComps];
+ GfxColor c0, c1, c2;
+ int nComps, i;
+
+ // recursion ends when:
+ // (1) color difference is smaller than gouraudColorDelta; or
+ // (2) triangles are smaller than 0.5 pixel (note that "device
+ // space" is 72dpi when generating PostScript); or
+ // (3) max recursion depth (gouraudMaxDepth) is hit.
+ nComps = shading->getColorSpace()->getNComps();
+ shading->getColor(color0, &c0);
+ shading->getColor(color1, &c1);
+ shading->getColor(color2, &c2);
for (i = 0; i < nComps; ++i) {
- if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta ||
- abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) {
+ if (abs(c0.c[i] - c1.c[i]) > gouraudColorDelta ||
+ abs(c1.c[i] - c2.c[i]) > gouraudColorDelta) {
break;
}
}
- if (i == nComps || depth == gouraudMaxDepth) {
- state->setFillColor(color0);
+ state->transformDelta(x1 - x0, y1 - y0, &dx0, &dy0);
+ state->transformDelta(x2 - x1, y2 - y1, &dx1, &dy1);
+ state->transformDelta(x0 - x2, y0 - y2, &dx2, &dy2);
+ if (i == nComps ||
+ depth == gouraudMaxDepth ||
+ (fabs(dx0) < 0.5 && fabs(dy0) < 0.5 &&
+ fabs(dx1) < 0.5 && fabs(dy1) < 0.5 &&
+ fabs(dx2) < 0.5 && fabs(dy2) < 0.5)) {
+ state->setFillColor(&c0);
out->updateFillColor(state);
state->moveTo(x0, y0);
state->lineTo(x1, y1);
@@ -2907,21 +3070,19 @@ void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
y12 = 0.5 * (y1 + y2);
x20 = 0.5 * (x2 + x0);
y20 = 0.5 * (y2 + y0);
- //~ if the shading has a Function, this should interpolate on the
- //~ function parameter, not on the color components
- for (i = 0; i < nComps; ++i) {
- color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
- color12.c[i] = (color1->c[i] + color2->c[i]) / 2;
- color20.c[i] = (color2->c[i] + color0->c[i]) / 2;
- }
- gouraudFillTriangle(x0, y0, color0, x01, y01, &color01,
- x20, y20, &color20, nComps, depth + 1);
- gouraudFillTriangle(x01, y01, &color01, x1, y1, color1,
- x12, y12, &color12, nComps, depth + 1);
- gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12,
- x20, y20, &color20, nComps, depth + 1);
- gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12,
- x2, y2, color2, nComps, depth + 1);
+ for (i = 0; i < shading->getNComps(); ++i) {
+ color01[i] = 0.5 * (color0[i] + color1[i]);
+ color12[i] = 0.5 * (color1[i] + color2[i]);
+ color20[i] = 0.5 * (color2[i] + color0[i]);
+ }
+ gouraudFillTriangle(x0, y0, color0, x01, y01, color01,
+ x20, y20, color20, shading, depth + 1);
+ gouraudFillTriangle(x01, y01, color01, x1, y1, color1,
+ x12, y12, color12, shading, depth + 1);
+ gouraudFillTriangle(x01, y01, color01, x12, y12, color12,
+ x20, y20, color20, shading, depth + 1);
+ gouraudFillTriangle(x20, y20, color20, x12, y12, color12,
+ x2, y2, color2, shading, depth + 1);
}
}
@@ -2938,31 +3099,32 @@ void Gfx::doPatchMeshShFill(GfxPatchMeshShading *shading) {
start = 0;
}
for (i = 0; i < shading->getNPatches(); ++i) {
- fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(),
- start);
+ fillPatch(shading->getPatch(i), shading, start);
}
}
-void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) {
+void Gfx::fillPatch(GfxPatch *patch, GfxPatchMeshShading *shading, int depth) {
GfxPatch patch00, patch01, patch10, patch11;
+ GfxColor c00, c01, c10, c11;
double xx[4][8], yy[4][8];
double xxm, yym;
- int i;
+ int nComps, i;
+ nComps = shading->getColorSpace()->getNComps();
+ shading->getColor(patch->color[0][0], &c00);
+ shading->getColor(patch->color[0][1], &c01);
+ shading->getColor(patch->color[1][0], &c10);
+ shading->getColor(patch->color[1][1], &c11);
for (i = 0; i < nComps; ++i) {
- if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
- > patchColorDelta ||
- abs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
- > patchColorDelta ||
- abs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
- > patchColorDelta ||
- abs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
- > patchColorDelta) {
+ if (abs(c00.c[i] - c01.c[i]) > patchColorDelta ||
+ abs(c01.c[i] - c11.c[i]) > patchColorDelta ||
+ abs(c11.c[i] - c10.c[i]) > patchColorDelta ||
+ abs(c10.c[i] - c00.c[i]) > patchColorDelta) {
break;
}
}
if (i == nComps || depth == patchMaxDepth) {
- state->setFillColor(&patch->color[0][0]);
+ state->setFillColor(&c00);
out->updateFillColor(state);
state->moveTo(patch->x[0][0], patch->y[0][0]);
state->curveTo(patch->x[0][1], patch->y[0][1],
@@ -3039,35 +3201,33 @@ void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) {
patch11.x[3][i-4] = xx[3][i];
patch11.y[3][i-4] = yy[3][i];
}
- //~ if the shading has a Function, this should interpolate on the
- //~ function parameter, not on the color components
- for (i = 0; i < nComps; ++i) {
- patch00.color[0][0].c[i] = patch->color[0][0].c[i];
- patch00.color[0][1].c[i] = (patch->color[0][0].c[i] +
- patch->color[0][1].c[i]) / 2;
- patch01.color[0][0].c[i] = patch00.color[0][1].c[i];
- patch01.color[0][1].c[i] = patch->color[0][1].c[i];
- patch01.color[1][1].c[i] = (patch->color[0][1].c[i] +
- patch->color[1][1].c[i]) / 2;
- patch11.color[0][1].c[i] = patch01.color[1][1].c[i];
- patch11.color[1][1].c[i] = patch->color[1][1].c[i];
- patch11.color[1][0].c[i] = (patch->color[1][1].c[i] +
- patch->color[1][0].c[i]) / 2;
- patch10.color[1][1].c[i] = patch11.color[1][0].c[i];
- patch10.color[1][0].c[i] = patch->color[1][0].c[i];
- patch10.color[0][0].c[i] = (patch->color[1][0].c[i] +
- patch->color[0][0].c[i]) / 2;
- patch00.color[1][0].c[i] = patch10.color[0][0].c[i];
- patch00.color[1][1].c[i] = (patch00.color[1][0].c[i] +
- patch01.color[1][1].c[i]) / 2;
- patch01.color[1][0].c[i] = patch00.color[1][1].c[i];
- patch11.color[0][0].c[i] = patch00.color[1][1].c[i];
- patch10.color[0][1].c[i] = patch00.color[1][1].c[i];
- }
- fillPatch(&patch00, nComps, depth + 1);
- fillPatch(&patch10, nComps, depth + 1);
- fillPatch(&patch01, nComps, depth + 1);
- fillPatch(&patch11, nComps, depth + 1);
+ for (i = 0; i < shading->getNComps(); ++i) {
+ patch00.color[0][0][i] = patch->color[0][0][i];
+ patch00.color[0][1][i] = 0.5 * (patch->color[0][0][i] +
+ patch->color[0][1][i]);
+ patch01.color[0][0][i] = patch00.color[0][1][i];
+ patch01.color[0][1][i] = patch->color[0][1][i];
+ patch01.color[1][1][i] = 0.5 * (patch->color[0][1][i] +
+ patch->color[1][1][i]);
+ patch11.color[0][1][i] = patch01.color[1][1][i];
+ patch11.color[1][1][i] = patch->color[1][1][i];
+ patch11.color[1][0][i] = 0.5 * (patch->color[1][1][i] +
+ patch->color[1][0][i]);
+ patch10.color[1][1][i] = patch11.color[1][0][i];
+ patch10.color[1][0][i] = patch->color[1][0][i];
+ patch10.color[0][0][i] = 0.5 * (patch->color[1][0][i] +
+ patch->color[0][0][i]);
+ patch00.color[1][0][i] = patch10.color[0][0][i];
+ patch00.color[1][1][i] = 0.5 * (patch00.color[1][0][i] +
+ patch01.color[1][1][i]);
+ patch01.color[1][0][i] = patch00.color[1][1][i];
+ patch11.color[0][0][i] = patch00.color[1][1][i];
+ patch10.color[0][1][i] = patch00.color[1][1][i];
+ }
+ fillPatch(&patch00, shading, depth + 1);
+ fillPatch(&patch10, shading, depth + 1);
+ fillPatch(&patch01, shading, depth + 1);
+ fillPatch(&patch11, shading, depth + 1);
}
}
@@ -3123,19 +3283,22 @@ void Gfx::opSetCharSpacing(Object args[], int numArgs) {
}
void Gfx::opSetFont(Object args[], int numArgs) {
- GfxFont *font;
+ doSetFont(res->lookupFont(args[0].getName()), args[1].getNum());
+}
- if (!(font = res->lookupFont(args[0].getName()))) {
+void Gfx::doSetFont(GfxFont *font, double size) {
+ if (!font) {
+ state->setFont(NULL, 0);
return;
}
if (printCommands) {
printf(" font: tag=%s name='%s' %g\n",
font->getTag()->getCString(),
font->getName() ? font->getName()->getCString() : "???",
- args[1].getNum());
+ size);
fflush(stdout);
}
- state->setFont(font, args[1].getNum());
+ state->setFont(font, size);
fontChanged = gTrue;
}
@@ -3343,7 +3506,7 @@ void Gfx::doShowText(GString *s) {
double x0, y0, x1, y1;
double oldCTM[6], newCTM[6];
double *mat;
- Object charProc;
+ Object charProcRef, charProc;
Dict *resDict;
Parser *oldParser;
GfxState *savedState;
@@ -3427,12 +3590,13 @@ void Gfx::doShowText(GString *s) {
state->transformDelta(dx, dy, &ddx, &ddy);
if (!out->beginType3Char(state, curX + riseX, curY + riseY, ddx, ddy,
code, u, uLen)) {
- ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
+ ((Gfx8BitFont *)font)->getCharProcNF(code, &charProcRef);
+ charProcRef.fetch(xref, &charProc);
if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
pushResources(resDict);
}
if (charProc.isStream()) {
- display(&charProc, gFalse);
+ display(&charProcRef, gFalse);
} else {
error(errSyntaxError, getPos(),
"Missing or bad Type3 CharProc entry");
@@ -3442,6 +3606,7 @@ void Gfx::doShowText(GString *s) {
popResources();
}
charProc.free();
+ charProcRef.free();
}
restoreStateStack(savedState);
curX += tdx;
@@ -3592,44 +3757,53 @@ void Gfx::opXObject(Object args[], int numArgs) {
obj1.free();
return;
}
+#if USE_EXCEPTIONS
+ try {
+#endif
#if OPI_SUPPORT
- obj1.streamGetDict()->lookup("OPI", &opiDict);
- if (opiDict.isDict()) {
- out->opiBegin(state, opiDict.getDict());
- }
+ obj1.streamGetDict()->lookup("OPI", &opiDict);
+ if (opiDict.isDict()) {
+ out->opiBegin(state, opiDict.getDict());
+ }
#endif
- obj1.streamGetDict()->lookup("Subtype", &obj2);
- if (obj2.isName("Image")) {
- if (out->needNonText()) {
+ obj1.streamGetDict()->lookup("Subtype", &obj2);
+ if (obj2.isName("Image")) {
+ if (out->needNonText()) {
+ res->lookupXObjectNF(name, &refObj);
+ doImage(&refObj, obj1.getStream(), gFalse);
+ refObj.free();
+ }
+ } else if (obj2.isName("Form")) {
res->lookupXObjectNF(name, &refObj);
- doImage(&refObj, obj1.getStream(), gFalse);
+ if (out->useDrawForm() && refObj.isRef()) {
+ out->drawForm(refObj.getRef());
+ } else {
+ doForm(&refObj, &obj1);
+ }
refObj.free();
- }
- } else if (obj2.isName("Form")) {
- res->lookupXObjectNF(name, &refObj);
- if (out->useDrawForm() && refObj.isRef()) {
- out->drawForm(refObj.getRef());
+ } else if (obj2.isName("PS")) {
+ obj1.streamGetDict()->lookup("Level1", &obj3);
+ out->psXObject(obj1.getStream(),
+ obj3.isStream() ? obj3.getStream() : (Stream *)NULL);
+ } else if (obj2.isName()) {
+ error(errSyntaxError, getPos(),
+ "Unknown XObject subtype '{0:s}'", obj2.getName());
} else {
- doForm(&obj1);
- }
- refObj.free();
- } else if (obj2.isName("PS")) {
- obj1.streamGetDict()->lookup("Level1", &obj3);
- out->psXObject(obj1.getStream(),
- obj3.isStream() ? obj3.getStream() : (Stream *)NULL);
- } else if (obj2.isName()) {
- error(errSyntaxError, getPos(),
- "Unknown XObject subtype '{0:s}'", obj2.getName());
- } else {
- error(errSyntaxError, getPos(),
- "XObject subtype is missing or wrong type");
- }
- obj2.free();
+ error(errSyntaxError, getPos(),
+ "XObject subtype is missing or wrong type");
+ }
+ obj2.free();
#if OPI_SUPPORT
- if (opiDict.isDict()) {
- out->opiEnd(state, opiDict.getDict());
+ if (opiDict.isDict()) {
+ out->opiEnd(state, opiDict.getDict());
+ }
+ opiDict.free();
+#endif
+#if USE_EXCEPTIONS
+ } catch (GMemException e) {
+ obj1.free();
+ throw;
}
- opiDict.free();
#endif
obj1.free();
}
@@ -3649,6 +3823,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
int maskWidth, maskHeight;
GBool maskInvert;
Stream *maskStr;
+ GBool interpolate;
Object obj1, obj2;
int i, n;
@@ -3710,6 +3885,9 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
}
if (obj1.isInt()) {
bits = obj1.getInt();
+ if (bits < 1 || bits > 16) {
+ goto err2;
+ }
} else if (mask) {
bits = 1;
} else {
@@ -3718,6 +3896,15 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
obj1.free();
}
+ // interpolate flag
+ dict->lookup("Interpolate", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("I", &obj1);
+ }
+ interpolate = obj1.isBool() && obj1.getBool();
+ obj1.free();
+
// display a mask
if (mask) {
@@ -3751,9 +3938,11 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
// draw it
} else {
if (state->getFillColorSpace()->getMode() == csPattern) {
- doPatternImageMask(ref, str, width, height, invert, inlineImg);
+ doPatternImageMask(ref, str, width, height, invert, inlineImg,
+ interpolate);
} else {
- out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
+ out->drawImageMask(state, ref, str, width, height, invert, inlineImg,
+ interpolate);
}
}
@@ -3775,13 +3964,14 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
}
}
if (!obj1.isNull()) {
- colorSpace = GfxColorSpace::parse(&obj1);
+ colorSpace = GfxColorSpace::parse(&obj1
+ );
} else if (csMode == streamCSDeviceGray) {
- colorSpace = new GfxDeviceGrayColorSpace();
+ colorSpace = GfxColorSpace::create(csDeviceGray);
} else if (csMode == streamCSDeviceRGB) {
- colorSpace = new GfxDeviceRGBColorSpace();
+ colorSpace = GfxColorSpace::create(csDeviceRGB);
} else if (csMode == streamCSDeviceCMYK) {
- colorSpace = new GfxDeviceCMYKColorSpace();
+ colorSpace = GfxColorSpace::create(csDeviceCMYK);
} else {
colorSpace = NULL;
}
@@ -3860,7 +4050,8 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
obj2.free();
}
}
- maskColorSpace = GfxColorSpace::parse(&obj1);
+ maskColorSpace = GfxColorSpace::parse(&obj1
+ );
obj1.free();
if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
goto err1;
@@ -3977,14 +4168,17 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
} else {
if (haveSoftMask) {
out->drawSoftMaskedImage(state, ref, str, width, height, colorMap,
- maskStr, maskWidth, maskHeight, maskColorMap);
+ maskStr, maskWidth, maskHeight, maskColorMap,
+ interpolate);
delete maskColorMap;
} else if (haveExplicitMask) {
out->drawMaskedImage(state, ref, str, width, height, colorMap,
- maskStr, maskWidth, maskHeight, maskInvert);
+ maskStr, maskWidth, maskHeight, maskInvert,
+ interpolate);
} else {
out->drawImage(state, ref, str, width, height, colorMap,
- haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
+ haveColorKeyMask ? maskColors : (int *)NULL, inlineImg,
+ interpolate);
}
}
@@ -4006,7 +4200,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
error(errSyntaxError, getPos(), "Bad image parameters");
}
-void Gfx::doForm(Object *str) {
+void Gfx::doForm(Object *strRef, Object *str) {
Dict *dict;
GBool transpGroup, isolated, knockout;
GfxColorSpace *blendingColorSpace;
@@ -4087,7 +4281,8 @@ void Gfx::doForm(Object *str) {
if (obj1.dictLookup("S", &obj2)->isName("Transparency")) {
transpGroup = gTrue;
if (!obj1.dictLookup("CS", &obj3)->isNull()) {
- blendingColorSpace = GfxColorSpace::parse(&obj3);
+ blendingColorSpace = GfxColorSpace::parse(&obj3
+ );
}
obj3.free();
if (obj1.dictLookup("I", &obj3)->isBool()) {
@@ -4105,7 +4300,7 @@ void Gfx::doForm(Object *str) {
// draw it
++formDepth;
- drawForm(str, resDict, m, bbox,
+ drawForm(strRef, resDict, m, bbox,
transpGroup, gFalse, blendingColorSpace, isolated, knockout);
--formDepth;
@@ -4117,7 +4312,8 @@ void Gfx::doForm(Object *str) {
ocState = ocSaved;
}
-void Gfx::drawForm(Object *str, Dict *resDict, double *matrix, double *bbox,
+void Gfx::drawForm(Object *strRef, Dict *resDict,
+ double *matrix, double *bbox,
GBool transpGroup, GBool softMask,
GfxColorSpace *blendingColorSpace,
GBool isolated, GBool knockout,
@@ -4181,7 +4377,7 @@ void Gfx::drawForm(Object *str, Dict *resDict, double *matrix, double *bbox,
}
// draw the form
- display(str, gFalse);
+ display(strRef, gFalse);
if (softMask || transpGroup) {
out->endTransparencyGroup(state);
@@ -4210,13 +4406,17 @@ void Gfx::drawForm(Object *str, Dict *resDict, double *matrix, double *bbox,
return;
}
+void Gfx::takeContentStreamStack(Gfx *oldGfx) {
+ contentStreamStack->append(oldGfx->contentStreamStack);
+}
+
//------------------------------------------------------------------------
// in-line image operators
//------------------------------------------------------------------------
void Gfx::opBeginImage(Object args[], int numArgs) {
Stream *str;
- int c1, c2;
+ int c1, c2, c3;
// NB: this function is run even if ocState is false -- doImage() is
// responsible for skipping over the inline image data
@@ -4231,9 +4431,11 @@ void Gfx::opBeginImage(Object args[], int numArgs) {
// skip 'EI' tag
c1 = str->getUndecodedStream()->getChar();
c2 = str->getUndecodedStream()->getChar();
- while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
+ c3 = str->getUndecodedStream()->lookChar();
+ while (!(c1 == 'E' && c2 == 'I' && Lexer::isSpace(c3)) && c3 != EOF) {
c1 = c2;
c2 = str->getUndecodedStream()->getChar();
+ c3 = str->getUndecodedStream()->lookChar();
}
delete str;
}
@@ -4328,9 +4530,7 @@ void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
GfxMarkedContent *mc;
Object obj;
GBool ocStateNew;
- GString *s;
- Unicode *u;
- int uLen, i;
+ TextString *s;
GfxMarkedContentKind mcKind;
if (printCommands) {
@@ -4351,24 +4551,9 @@ void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
mcKind = gfxMCOptionalContent;
} else if (args[0].isName("Span") && numArgs == 2 && args[1].isDict()) {
if (args[1].dictLookup("ActualText", &obj)->isString()) {
- s = obj.getString();
- if ((s->getChar(0) & 0xff) == 0xfe &&
- (s->getChar(1) & 0xff) == 0xff) {
- uLen = (s->getLength() - 2) / 2;
- u = (Unicode *)gmallocn(uLen, sizeof(Unicode));
- for (i = 0; i < uLen; ++i) {
- u[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) |
- (s->getChar(3 + 2*i) & 0xff);
- }
- } else {
- uLen = s->getLength();
- u = (Unicode *)gmallocn(uLen, sizeof(Unicode));
- for (i = 0; i < uLen; ++i) {
- u[i] = pdfDocEncoding[s->getChar(i) & 0xff];
- }
- }
- out->beginActualText(state, u, uLen);
- gfree(u);
+ s = new TextString(obj.getString());
+ out->beginActualText(state, s->getUnicode(), s->getLength());
+ delete s;
mcKind = gfxMCActualText;
}
obj.free();
@@ -4416,14 +4601,14 @@ void Gfx::opMarkPoint(Object args[], int numArgs) {
// misc
//------------------------------------------------------------------------
-void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
+void Gfx::drawAnnot(Object *strRef, AnnotBorderStyle *borderStyle,
double xMin, double yMin, double xMax, double yMax) {
Dict *dict, *resDict;
- Object matrixObj, bboxObj, resObj, obj1;
+ Object str, matrixObj, bboxObj, resObj, obj1;
double formXMin, formYMin, formXMax, formYMax;
double x, y, sx, sy, tx, ty;
double m[6], bbox[4];
- double r, g, b;
+ double *borderColor;
GfxColor color;
double *dash, *dash2;
int dashLength;
@@ -4439,16 +4624,18 @@ void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
}
// draw the appearance stream (if there is one)
- if (str->isStream()) {
+ strRef->fetch(xref, &str);
+ if (str.isStream()) {
// get stream dict
- dict = str->streamGetDict();
+ dict = str.streamGetDict();
// get the form bounding box
dict->lookup("BBox", &bboxObj);
if (!bboxObj.isArray()) {
- bboxObj.free();
error(errSyntaxError, getPos(), "Bad form bounding box");
+ bboxObj.free();
+ str.free();
return;
}
for (i = 0; i < 4; ++i) {
@@ -4548,22 +4735,43 @@ void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
// draw it
- drawForm(str, resDict, m, bbox);
+ drawForm(strRef, resDict, m, bbox);
resObj.free();
}
+ str.free();
// draw the border
- if (borderStyle && borderStyle->getWidth() > 0) {
- if (state->getStrokeColorSpace()->getMode() != csDeviceRGB) {
- state->setStrokePattern(NULL);
- state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
- out->updateStrokeColorSpace(state);
- }
- borderStyle->getColor(&r, &g, &b);
- color.c[0] = dblToCol(r);
- color.c[1] = dblToCol(g);
- color.c[2] = dblToCol(b);
+ if (borderStyle && borderStyle->getWidth() > 0 &&
+ borderStyle->getNumColorComps() > 0) {
+ borderColor = borderStyle->getColor();
+ switch (borderStyle->getNumColorComps()) {
+ case 1:
+ if (state->getStrokeColorSpace()->getMode() != csDeviceGray) {
+ state->setStrokePattern(NULL);
+ state->setStrokeColorSpace(GfxColorSpace::create(csDeviceGray));
+ out->updateStrokeColorSpace(state);
+ }
+ break;
+ case 3:
+ if (state->getStrokeColorSpace()->getMode() != csDeviceRGB) {
+ state->setStrokePattern(NULL);
+ state->setStrokeColorSpace(GfxColorSpace::create(csDeviceRGB));
+ out->updateStrokeColorSpace(state);
+ }
+ break;
+ case 4:
+ if (state->getStrokeColorSpace()->getMode() != csDeviceCMYK) {
+ state->setStrokePattern(NULL);
+ state->setStrokeColorSpace(GfxColorSpace::create(csDeviceCMYK));
+ out->updateStrokeColorSpace(state);
+ }
+ break;
+ }
+ color.c[0] = dblToCol(borderColor[0]);
+ color.c[1] = dblToCol(borderColor[1]);
+ color.c[2] = dblToCol(borderColor[2]);
+ color.c[3] = dblToCol(borderColor[3]);
state->setStrokeColor(&color);
out->updateStrokeColor(state);
state->setLineWidth(borderStyle->getWidth());