summaryrefslogtreecommitdiff
path: root/noncore/unsupported/qpdf/xpdf/Gfx.cc
Side-by-side diff
Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/Gfx.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/unsupported/qpdf/xpdf/Gfx.cc589
1 files changed, 444 insertions, 145 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/Gfx.cc b/noncore/unsupported/qpdf/xpdf/Gfx.cc
index c19971c..17d613e 100644
--- a/noncore/unsupported/qpdf/xpdf/Gfx.cc
+++ b/noncore/unsupported/qpdf/xpdf/Gfx.cc
@@ -4,3 +4,3 @@
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
//
@@ -32,2 +32,7 @@
+// the MSVC math.h doesn't define this
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
//------------------------------------------------------------------------
@@ -42,2 +47,8 @@
+// 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 (1 / 256.0)
+
//------------------------------------------------------------------------
@@ -376,2 +387,3 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, fouble dpi,
xref = xrefA;
+ subPage = gFalse;
printCommands = printCommandsA;
@@ -407,5 +419,37 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, fouble dpi,
-Gfx::~Gfx() {
- GfxResources *resPtr;
+Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
+ PDFRectangle *box, GBool crop, PDFRectangle *cropBox) {
+ int i;
+ xref = xrefA;
+ subPage = gTrue;
+ printCommands = gFalse;
+
+ // start the resource stack
+ res = new GfxResources(xref, resDict, NULL);
+
+ // initialize
+ out = outA;
+ state = new GfxState(72, box, 0, gFalse);
+ fontChanged = gFalse;
+ clip = clipNone;
+ ignoreUndef = 0;
+ for (i = 0; i < 6; ++i) {
+ baseMatrix[i] = state->getCTM()[i];
+ }
+
+ // set crop box
+ if (crop) {
+ state->moveTo(cropBox->x1, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y2);
+ state->lineTo(cropBox->x1, cropBox->y2);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+}
+
+Gfx::~Gfx() {
while (state->hasSaves()) {
@@ -414,10 +458,11 @@ Gfx::~Gfx() {
}
- out->endPage();
+ if (!subPage) {
+ out->endPage();
+ }
while (res) {
- resPtr = res->getNext();
- delete res;
- res = resPtr;
+ popResources();
}
- if (state)
+ if (state) {
delete state;
+ }
}
@@ -451,3 +496,3 @@ void Gfx::go(GBool topLevel) {
Object args[maxArgs];
- int numCmds, numArgs;
+ int numArgs;
int i;
@@ -455,3 +500,3 @@ void Gfx::go(GBool topLevel) {
// scan a sequence of objects
- numCmds = 0;
+ updateLevel = 0;
numArgs = 0;
@@ -478,5 +523,5 @@ void Gfx::go(GBool topLevel) {
// periodically update display
- if (++numCmds == 200) {
+ if (++updateLevel >= 20000) {
out->dump();
- numCmds = 0;
+ updateLevel = 0;
}
@@ -521,3 +566,3 @@ void Gfx::go(GBool topLevel) {
// update display
- if (topLevel && numCmds > 0) {
+ if (topLevel && updateLevel > 0) {
out->dump();
@@ -1140,3 +1185,3 @@ void Gfx::doPatternFill(GBool eoFill) {
fouble *ctm, *btm, *ptm;
- fouble m[6], ictm[6], m1[6], im[6], imb[6];
+ fouble m[6], ictm[6], m1[6], imb[6];
fouble det;
@@ -1191,11 +1236,2 @@ void Gfx::doPatternFill(GBool eoFill) {
- // construct a (current space) -> (pattern space) transform matrix
- det = 1 / (m[0] * m[3] - m[1] * m[2]);
- im[0] = m[3] * det;
- im[1] = -m[1] * det;
- im[2] = -m[2] * det;
- im[3] = m[0] * det;
- im[4] = (m[2] * m[5] - m[3] * m[4]) * det;
- im[5] = (m[1] * m[4] - m[0] * m[5]) * det;
-
// construct a (base space) -> (pattern space) transform matrix
@@ -1333,2 +1369,5 @@ void Gfx::opShFill(Object args[], int numArgs) {
break;
+ case 3:
+ doRadialShFill((GfxRadialShading *)shading);
+ break;
}
@@ -1345,5 +1384,2 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
fouble x0, y0, x1, y1;
- fouble det;
- fouble *ctm;
- fouble ictm[6];
fouble dx, dy, mul;
@@ -1359,50 +1395,4 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
- // get clip region bbox and transform to current user space
- state->getClipBBox(&x0, &y0, &x1, &y1);
- ctm = state->getCTM();
- det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
- ictm[0] = ctm[3] * det;
- ictm[1] = -ctm[1] * det;
- ictm[2] = -ctm[2] * det;
- ictm[3] = ctm[0] * det;
- ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
- ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
- xMin = xMax = x0 * ictm[0] + y0 * ictm[2] + ictm[4];
- yMin = yMax = x0 * ictm[1] + y0 * ictm[3] + ictm[5];
- tx = x0 * ictm[0] + y1 * ictm[2] + ictm[4];
- ty = x0 * ictm[1] + y1 * ictm[3] + ictm[5];
- if (tx < xMin) {
- xMin = tx;
- } else if (tx > xMax) {
- xMax = tx;
- }
- if (ty < yMin) {
- yMin = ty;
- } else if (ty > yMax) {
- yMax = ty;
- }
- tx = x1 * ictm[0] + y0 * ictm[2] + ictm[4];
- ty = x1 * ictm[1] + y0 * ictm[3] + ictm[5];
- if (tx < xMin) {
- xMin = tx;
- } else if (tx > xMax) {
- xMax = tx;
- }
- if (ty < yMin) {
- yMin = ty;
- } else if (ty > yMax) {
- yMax = ty;
- }
- tx = x1 * ictm[0] + y1 * ictm[2] + ictm[4];
- ty = x1 * ictm[1] + y1 * ictm[3] + ictm[5];
- if (tx < xMin) {
- xMin = tx;
- } else if (tx > xMax) {
- xMax = tx;
- }
- if (ty < yMin) {
- yMin = ty;
- } else if (ty > yMax) {
- yMax = ty;
- }
+ // get the clip region bbox
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
@@ -1621,2 +1611,198 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
+void Gfx::doRadialShFill(GfxRadialShading *shading) {
+ fouble sMin, sMax, xMin, yMin, xMax, yMax;
+ fouble x0, y0, r0, x1, y1, r1, t0, t1;
+ int nComps;
+ GfxColor colorA, colorB;
+ fouble xa, ya, xb, yb, ra, rb;
+ fouble ta, tb, sa, sb;
+ int ia, ib, k, n;
+ fouble *ctm;
+ fouble angle, t;
+
+ // get the shading info
+ shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+ nComps = shading->getColorSpace()->getNComps();
+
+ // compute the (possibly extended) s range
+ sMin = 0;
+ sMax = 1;
+ if (shading->getExtend0()) {
+ if (r0 < r1) {
+ // extend the smaller end
+ sMin = -r0 / (r1 - r0);
+ } else {
+ // extend the larger end
+ //~ this computes the diagonal of the bounding box -- we should
+ //~ really compute the intersection of the moving/expanding
+ //~ circles with each of the four corners and look for the max
+ //~ radius
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ sMin = (sqrt((xMax - xMin) * (xMax - xMin) +
+ (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
+ if (sMin > 0) {
+ sMin = 0;
+ } else if (sMin < -20) {
+ // sanity check
+ sMin = -20;
+ }
+ }
+ }
+ if (shading->getExtend1()) {
+ if (r1 < r0) {
+ // extend the smaller end
+ sMax = -r0 / (r1 - r0);
+ } else if (r1 > r0) {
+ // extend the larger end
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ sMax = (sqrt((xMax - xMin) * (xMax - xMin) +
+ (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
+ if (sMax < 1) {
+ sMin = 1;
+ } else if (sMax > 20) {
+ // sanity check
+ sMax = 20;
+ }
+ }
+ }
+
+ // compute the number of steps into which circles must be divided to
+ // achieve a curve flatness of 0.1 pixel in device space for the
+ // largest circle (note that "device space" is 72 dpi when generating
+ // PostScript, hence the relatively small 0.1 pixel accuracy)
+ ctm = state->getCTM();
+ t = fabs(ctm[0]);
+ if (fabs(ctm[1]) > t) {
+ t = fabs(ctm[1]);
+ }
+ if (fabs(ctm[2]) > t) {
+ t = fabs(ctm[2]);
+ }
+ if (fabs(ctm[3]) > t) {
+ t = fabs(ctm[3]);
+ }
+ if (r0 > r1) {
+ t *= r0;
+ } else {
+ t *= r1;
+ }
+ if (t < 1) {
+ n = 3;
+ } else {
+ n = (int)(M_PI / acos(1 - 0.1 / t));
+ if (n < 3) {
+ n = 3;
+ } else if (n > 200) {
+ n = 200;
+ }
+ }
+
+ // Traverse the t axis and do the shading.
+ //
+ // This generates and fills a series of rings. Each ring is defined
+ // by two circles:
+ // sa, ta, xa, ya, ra, colorA
+ // sb, tb, xb, yb, rb, colorB
+ //
+ // The s/t axis is divided into radialMaxSplits parts; these parts
+ // are combined as much as possible while respecting the
+ // radialColorDelta parameter.
+
+ // setup for the start circle
+ ia = 0;
+ sa = sMin;
+ ta = t0 + sa * (t1 - t0);
+ xa = x0 + sa * (x1 - x0);
+ ya = y0 + sa * (y1 - y0);
+ ra = r0 + sa * (r1 - r0);
+ if (ta < t0) {
+ shading->getColor(t0, &colorA);
+ } else if (ta > t1) {
+ shading->getColor(t1, &colorA);
+ } else {
+ shading->getColor(ta, &colorA);
+ }
+
+ while (ia < radialMaxSplits) {
+
+ // go as far along the t axis (toward t1) as we can, such that the
+ // color difference is within the tolerance (radialColorDelta) --
+ // this uses bisection (between the current value, t, and t1),
+ // limited to radialMaxSplits points along the t axis
+ ib = radialMaxSplits;
+ sb = sMin + ((fouble)ib / (fouble)radialMaxSplits) * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ if (tb < t0) {
+ shading->getColor(t0, &colorB);
+ } else if (tb > t1) {
+ shading->getColor(t1, &colorB);
+ } else {
+ shading->getColor(tb, &colorB);
+ }
+ while (ib - ia > 1) {
+ for (k = 0; k < nComps; ++k) {
+ if (fabs(colorB.c[k] - colorA.c[k]) > radialColorDelta) {
+ break;
+ }
+ }
+ if (k == nComps) {
+ break;
+ }
+ ib = (ia + ib) / 2;
+ sb = sMin + ((fouble)ib / (fouble)radialMaxSplits) * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ if (tb < t0) {
+ shading->getColor(t0, &colorB);
+ } else if (tb > t1) {
+ shading->getColor(t1, &colorB);
+ } else {
+ shading->getColor(tb, &colorB);
+ }
+ }
+
+ // compute center and radius of the circle
+ xb = x0 + sb * (x1 - x0);
+ yb = y0 + sb * (y1 - y0);
+ rb = r0 + sb * (r1 - r0);
+
+ // use the average of the colors at the two circles
+ for (k = 0; k < nComps; ++k) {
+ colorA.c[k] = 0.5 * (colorA.c[k] + colorB.c[k]);
+ }
+ state->setFillColor(&colorA);
+ out->updateFillColor(state);
+
+ // construct path for first circle
+ state->moveTo(xa + ra, ya);
+ for (k = 1; k < n; ++k) {
+ angle = ((fouble)k / (fouble)n) * 2 * M_PI;
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+
+ // construct and append path for second circle
+ state->moveTo(xb + rb, yb);
+ for (k = 1; k < n; ++k) {
+ angle = ((fouble)k / (fouble)n) * 2 * M_PI;
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
+ }
+ state->closePath();
+
+ // fill the ring
+ out->eoFill(state);
+ state->clearPath();
+
+ // step to the next value of t
+ ia = ib;
+ sa = sb;
+ ta = tb;
+ xa = xb;
+ ya = yb;
+ ra = rb;
+ colorA = colorB;
+ }
+}
+
void Gfx::doEndPath() {
@@ -1802,2 +1988,3 @@ void Gfx::opShowSpaceText(Object args[], int numArgs) {
Object obj;
+ int wMode;
int i;
@@ -1808,2 +1995,3 @@ void Gfx::opShowSpaceText(Object args[], int numArgs) {
}
+ wMode = state->getFont()->getWMode();
a = args[0].getArray();
@@ -1812,3 +2000,7 @@ void Gfx::opShowSpaceText(Object args[], int numArgs) {
if (obj.isNum()) {
- state->textShift(-obj.getNum() * 0.001 * state->getFontSize());
+ if (wMode) {
+ state->textShift(0, -obj.getNum() * 0.001 * state->getFontSize());
+ } else {
+ state->textShift(-obj.getNum() * 0.001 * state->getFontSize(), 0);
+ }
out->updateTextShift(state, obj.getNum());
@@ -1825,2 +2017,3 @@ void Gfx::doShowText(GString *s) {
GfxFont *font;
+ int wMode;
fouble riseX, riseY;
@@ -1828,6 +2021,11 @@ void Gfx::doShowText(GString *s) {
Unicode u[8];
- fouble dx, dy, dx2, dy2, tdx, tdy;
+ fouble x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy;
fouble originX, originY, tOriginX, tOriginY;
+ fouble oldCTM[6], newCTM[6];
+ fouble *mat;
+ Object charProc;
+ Dict *resDict;
+ Parser *oldParser;
char *p;
- int len, n, uLen, nChars, nSpaces;
+ int len, n, uLen, nChars, nSpaces, i;
@@ -1838,14 +2036,10 @@ void Gfx::doShowText(GString *s) {
font = state->getFont();
+ wMode = font->getWMode();
-#if 0 //~type3
- fouble x, y;
- fouble oldCTM[6], newCTM[6];
- fouble *mat;
- Object charProc;
- Parser *oldParser;
- int i;
-
- //~ also check out->renderType3()
- if (font->getType() == fontType3) {
+ if (out->useDrawChar()) {
out->beginString(state, s);
+ }
+
+ // handle a Type 3 char
+ if (font->getType() == fontType3 && out->interpretType3Chars()) {
mat = state->getCTM();
@@ -1869,2 +2063,4 @@ void Gfx::doShowText(GString *s) {
state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
+ curX = state->getCurX();
+ curY = state->getCurY();
oldParser = parser;
@@ -1876,17 +2072,2 @@ void Gfx::doShowText(GString *s) {
&dx, &dy, &originX, &originY);
- state->transform(state->getCurX() + riseX, state->getCurY() + riseY,
- &x, &y);
- out->saveState(state);
- state = state->save();
- state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
- //~ out->updateCTM(???)
- ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
- if (charProc.isStream()) {
- display(&charProc, gFalse);
- } else {
- error(getPos(), "Missing or bad Type3 CharProc entry");
- }
- state = state->restore();
- out->restoreState(state);
- charProc.free();
dx = dx * state->getFontSize() + state->getCharSpace();
@@ -1898,3 +2079,30 @@ void Gfx::doShowText(GString *s) {
state->textTransformDelta(dx, dy, &tdx, &tdy);
- state->shift(tdx, tdy);
+ state->transform(curX + riseX, curY + riseY, &x, &y);
+ out->saveState(state);
+ state = state->save();
+ state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
+ //~ out->updateCTM(???)
+ if (!out->beginType3Char(state, code, u, uLen)) {
+ ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
+ if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
+ pushResources(resDict);
+ }
+ if (charProc.isStream()) {
+ display(&charProc, gFalse);
+ } else {
+ error(getPos(), "Missing or bad Type3 CharProc entry");
+ }
+ out->endType3Char(state);
+ if (resDict) {
+ popResources();
+ }
+ charProc.free();
+ }
+ state = state->restore();
+ out->restoreState(state);
+ // GfxState::restore() does *not* restore the current position,
+ // so we track it here with (curX, curY)
+ curX += tdx;
+ curY += tdy;
+ state->moveTo(curX, curY);
p += n;
@@ -1903,10 +2111,5 @@ void Gfx::doShowText(GString *s) {
parser = oldParser;
- out->endString(state);
- return;
- }
-#endif
- if (out->useDrawChar()) {
+ } else if (out->useDrawChar()) {
state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
- out->beginString(state, s);
p = s->getCString();
@@ -1917,8 +2120,16 @@ void Gfx::doShowText(GString *s) {
&dx, &dy, &originX, &originY);
- dx = dx * state->getFontSize() + state->getCharSpace();
- if (n == 1 && *p == ' ') {
- dx += state->getWordSpace();
+ if (wMode) {
+ dx *= state->getFontSize();
+ dy = dy * state->getFontSize() + state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dy += state->getWordSpace();
+ }
+ } else {
+ dx = dx * state->getFontSize() + state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dx += state->getWordSpace();
+ }
+ dx *= state->getHorizScaling();
+ dy *= state->getFontSize();
}
- dx *= state->getHorizScaling();
- dy *= state->getFontSize();
state->textTransformDelta(dx, dy, &tdx, &tdy);
@@ -1933,3 +2144,2 @@ void Gfx::doShowText(GString *s) {
}
- out->endString(state);
@@ -1953,7 +2163,14 @@ void Gfx::doShowText(GString *s) {
}
- dx = dx * state->getFontSize()
- + nChars * state->getCharSpace()
- + nSpaces * state->getWordSpace();
- dx *= state->getHorizScaling();
- dy *= state->getFontSize();
+ if (wMode) {
+ dx *= state->getFontSize();
+ dy = dy * state->getFontSize()
+ + nChars * state->getCharSpace()
+ + nSpaces * state->getWordSpace();
+ } else {
+ dx = dx * state->getFontSize()
+ + nChars * state->getCharSpace()
+ + nSpaces * state->getWordSpace();
+ dx *= state->getHorizScaling();
+ dy *= state->getFontSize();
+ }
state->textTransformDelta(dx, dy, &tdx, &tdy);
@@ -1962,2 +2179,8 @@ void Gfx::doShowText(GString *s) {
}
+
+ if (out->useDrawChar()) {
+ out->endString(state);
+ }
+
+ updateLevel += 10 * s->getLength();
}
@@ -1969,3 +2192,3 @@ void Gfx::doShowText(GString *s) {
void Gfx::opXObject(Object args[], int numArgs) {
- Object obj1, obj2, refObj;
+ Object obj1, obj2, obj3, refObj;
#if OPI_SUPPORT
@@ -1995,2 +2218,6 @@ void Gfx::opXObject(Object args[], int numArgs) {
doForm(&obj1);
+ } else if (obj2.isName("PS")) {
+ obj1.streamGetDict()->lookup("Level1", &obj3);
+ out->psXObject(obj1.getStream(),
+ obj3.isStream() ? obj3.getStream() : (Stream *)NULL);
} else if (obj2.isName()) {
@@ -2150,2 +2377,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
+ if ((i = width * height) > 1000) {
+ i = 1000;
+ }
+ updateLevel += i;
+
return;
@@ -2217,4 +2449,4 @@ void Gfx::doForm(Object *str) {
-void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin,
- fouble xMax, fouble yMax) {
+void Gfx::doAnnot(Object *str, fouble xMin, fouble yMin,
+ fouble xMax, fouble yMax) {
Dict *dict, *resDict;
@@ -2222,4 +2454,7 @@ void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin,
Object obj1;
- fouble m[6], bbox[6];
- fouble sx, sy;
+ fouble m[6], bbox[6], ictm[6];
+ fouble *ctm;
+ fouble formX0, formY0, formX1, formY1;
+ fouble annotX0, annotY0, annotX1, annotY1;
+ fouble det, x, y, sx, sy;
int i;
@@ -2229,3 +2464,3 @@ void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin,
- // get bounding box
+ // get the form bounding box
dict->lookup("BBox", &bboxObj);
@@ -2243,3 +2478,3 @@ void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin,
- // get matrix
+ // get the form matrix
dict->lookup("Matrix", &matrixObj);
@@ -2258,12 +2493,60 @@ void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin,
- // scale form bbox to widget rectangle
- sx = fabs((xMax - xMin) / (bbox[2] - bbox[0]));
- sy = fabs((yMax - yMin) / (bbox[3] - bbox[1]));
- m[0] *= sx; m[1] *= sy;
- m[2] *= sx; m[3] *= sy;
- m[4] *= sx; m[5] *= sy;
+ // transform the form bbox from form space to user space
+ formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
+ formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5];
+ formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
+ formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5];
+
+ // transform the annotation bbox from default user space to user
+ // space: (bbox * baseMatrix) * iCTM
+ ctm = state->getCTM();
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4];
+ y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5];
+ annotX0 = ictm[0] * x + ictm[2] * y + ictm[4];
+ annotY0 = ictm[1] * x + ictm[3] * y + ictm[5];
+ x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4];
+ y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5];
+ annotX1 = ictm[0] * x + ictm[2] * y + ictm[4];
+ annotY1 = ictm[1] * x + ictm[3] * y + ictm[5];
+
+ // swap min/max coords
+ if (formX0 > formX1) {
+ x = formX0; formX0 = formX1; formX1 = x;
+ }
+ if (formY0 > formY1) {
+ y = formY0; formY0 = formY1; formY1 = y;
+ }
+ if (annotX0 > annotX1) {
+ x = annotX0; annotX0 = annotX1; annotX1 = x;
+ }
+ if (annotY0 > annotY1) {
+ y = annotY0; annotY0 = annotY1; annotY1 = y;
+ }
- // translate to widget rectangle
- m[4] += xMin;
- m[5] += yMin;
+ // scale the form to fit the annotation bbox
+ if (formX1 == formX0) {
+ // this shouldn't happen
+ sx = 1;
+ } else {
+ sx = (annotX1 - annotX0) / (formX1 - formX0);
+ }
+ if (formY1 == formY0) {
+ // this shouldn't happen
+ sy = 1;
+ } else {
+ sy = (annotY1 - annotY0) / (formY1 - formY0);
+ }
+ m[0] *= sx;
+ m[2] *= sx;
+ m[4] = (m[4] - formX0) * sx + annotX0;
+ m[1] *= sy;
+ m[3] *= sy;
+ m[5] = (m[5] - formY0) * sy + annotY0;
@@ -2283,3 +2566,2 @@ void Gfx::doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox) {
fouble oldBaseMatrix[6];
- GfxResources *resPtr;
int i;
@@ -2287,3 +2569,3 @@ void Gfx::doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox) {
// push new resources on stack
- res = new GfxResources(xref, resDict, res);
+ pushResources(resDict);
@@ -2334,2 +2616,14 @@ void Gfx::doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox) {
// pop resource stack
+ popResources();
+
+ return;
+}
+
+void Gfx::pushResources(Dict *resDict) {
+ res = new GfxResources(xref, resDict, res);
+}
+
+void Gfx::popResources() {
+ GfxResources *resPtr;
+
resPtr = res->getNext();
@@ -2337,4 +2631,2 @@ void Gfx::doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox) {
res = resPtr;
-
- return;
}
@@ -2380,3 +2672,2 @@ Stream *Gfx::buildImageStream() {
obj.free();
- parser->getObj(&obj);
} else {
@@ -2385,4 +2676,6 @@ Stream *Gfx::buildImageStream() {
parser->getObj(&obj);
- if (obj.isEOF() || obj.isError())
+ if (obj.isEOF() || obj.isError()) {
+ gfree(key);
break;
+ }
dict.dictAdd(key, &obj);
@@ -2391,4 +2684,8 @@ Stream *Gfx::buildImageStream() {
}
- if (obj.isEOF())
+ if (obj.isEOF()) {
error(getPos(), "End of file in inline image");
+ obj.free();
+ dict.free();
+ return NULL;
+ }
obj.free();
@@ -2415,3 +2712,3 @@ void Gfx::opEndImage(Object args[], int numArgs) {
void Gfx::opSetCharWidth(Object args[], int numArgs) {
- error(getPos(), "Encountered 'd0' operator in content stream");
+ out->type3D0(state, args[0].getNum(), args[1].getNum());
}
@@ -2419,3 +2716,5 @@ void Gfx::opSetCharWidth(Object args[], int numArgs) {
void Gfx::opSetCacheDevice(Object args[], int numArgs) {
- error(getPos(), "Encountered 'd1' operator in content stream");
+ out->type3D1(state, args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
}