summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Astals Cid <aacid@kde.org>2012-01-10 23:35:45 +0100
committerAlbert Astals Cid <aacid@kde.org>2012-01-10 23:35:45 +0100
commit431fddbc14548cdce21d94cfa4d3779bc142839f (patch)
tree07f060b03a484f1f8ae2c831565c8e40e887c015
parentddc9703d76b2d07674b61c74246db00aac3eb319 (diff)
update with Thomas merges
-rw-r--r--ALL_DIFF28083
1 files changed, 11982 insertions, 16101 deletions
diff --git a/ALL_DIFF b/ALL_DIFF
index 385d9a2..149caaa 100644
--- a/ALL_DIFF
+++ b/ALL_DIFF
@@ -1,16101 +1,11982 @@
-diff -ru xpdf-3.02/doc/pdftotext.1 xpdf-3.03/doc/pdftotext.1
---- xpdf-3.02/doc/pdftotext.1 2007-02-27 23:05:51.000000000 +0100
-+++ xpdf-3.03/doc/pdftotext.1 2011-08-15 23:08:53.000000000 +0200
-@@ -49,6 +49,10 @@
- text. The default is to \'undo' physical layout (columns,
- hyphenation, etc.) and output the text in reading order.
- .TP
-+.BI \-fixed " number"
-+Assume fixed-pitch (or tabular) text, with the specified character
-+width (in points). This forces physical layout mode.
-+.TP
- .B \-raw
- Keep the text in content stream order. This is a hack which often
- "undoes" column formatting, etc. Use of raw mode is no longer
-diff -ru xpdf-3.02/splash/Splash.cc xpdf-3.03/splash/Splash.cc
---- xpdf-3.02/splash/Splash.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/splash/Splash.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -1772,22 +2390,10 @@
- SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
- int w, int h, SplashCoord *mat,
- GBool glyphMode) {
-- SplashPipe pipe;
-- GBool rot;
-- SplashCoord xScale, yScale, xShear, yShear, yShear1;
-- int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
-- int ulx, uly, llx, lly, urx, ury, lrx, lry;
-- int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
-- int xMin, xMax, yMin, yMax;
-- SplashClipResult clipRes, clipRes2;
-- int yp, yq, yt, yStep, lastYStep;
-- int xp, xq, xt, xStep, xSrc;
-- int k1, spanXMin, spanXMax, spanY;
-- SplashColorPtr pixBuf, p;
-- int pixAcc;
-- int x, y, x1, x2, y2;
-- SplashCoord y1;
-- int n, m, i, j;
-+ SplashBitmap *scaledMask;
-+ SplashClipResult clipRes;
-+ GBool minorAxisZero;
-+ int x0, y0, x1, y1, scaledWidth, scaledHeight;
-
- if (debugMode) {
- printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
-@@ -1796,286 +2402,729 @@
- }
-
- // check for singular matrix
-- if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
-+ if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
- return splashErrSingularMatrix;
- }
-
-- // compute scale, shear, rotation, translation parameters
-- rot = splashAbs(mat[1]) > splashAbs(mat[0]);
-- if (rot) {
-- xScale = -mat[1];
-- yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
-- xShear = -mat[3] / yScale;
-- yShear = -mat[0] / mat[1];
-- } else {
-- xScale = mat[0];
-- yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
-- xShear = mat[2] / yScale;
-- yShear = mat[1] / mat[0];
-- }
-- // Note 1: The PDF spec says that all pixels whose *centers* lie
-- // within the region get painted -- but that doesn't seem to match
-- // up with what Acrobat actually does: it ends up leaving gaps
-- // between image stripes. So we use the same rule here as for
-- // fills: any pixel that overlaps the region gets painted.
-- // Note 2: The "glyphMode" flag is a kludge: it switches back to
-- // "correct" behavior (matching the spec), for use in rendering Type
-- // 3 fonts.
-- // Note 3: The +/-0.01 in these computations is to avoid floating
-- // point precision problems which can lead to gaps between image
-- // stripes (it can cause image stripes to overlap, but that's a much
-- // less visible problem).
-- if (glyphMode) {
-- if (xScale >= 0) {
-- tx = splashRound(mat[4]);
-- tx2 = splashRound(mat[4] + xScale) - 1;
-- } else {
-- tx = splashRound(mat[4]) - 1;
-- tx2 = splashRound(mat[4] + xScale);
-- }
-- } else {
-- if (xScale >= 0) {
-- tx = splashFloor(mat[4] - 0.01);
-- tx2 = splashFloor(mat[4] + xScale + 0.01);
-- } else {
-- tx = splashFloor(mat[4] + 0.01);
-- tx2 = splashFloor(mat[4] + xScale - 0.01);
-- }
-- }
-- scaledWidth = abs(tx2 - tx) + 1;
-- if (glyphMode) {
-- if (yScale >= 0) {
-- ty = splashRound(mat[5]);
-- ty2 = splashRound(mat[5] + yScale) - 1;
-- } else {
-- ty = splashRound(mat[5]) - 1;
-- ty2 = splashRound(mat[5] + yScale);
-- }
-- } else {
-- if (yScale >= 0) {
-- ty = splashFloor(mat[5] - 0.01);
-- ty2 = splashFloor(mat[5] + yScale + 0.01);
-- } else {
-- ty = splashFloor(mat[5] + 0.01);
-- ty2 = splashFloor(mat[5] + yScale - 0.01);
-- }
-- }
-- scaledHeight = abs(ty2 - ty) + 1;
-- xSign = (xScale < 0) ? -1 : 1;
-- ySign = (yScale < 0) ? -1 : 1;
-- yShear1 = (SplashCoord)xSign * yShear;
--
-- // clipping
-- ulx1 = 0;
-- uly1 = 0;
-- urx1 = xSign * (scaledWidth - 1);
-- ury1 = (int)(yShear * urx1);
-- llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
-- lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
-- lrx1 = xSign * (scaledWidth - 1) +
-- splashRound(xShear * ySign * (scaledHeight - 1));
-- lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
-- if (rot) {
-- ulx = tx + uly1; uly = ty - ulx1;
-- urx = tx + ury1; ury = ty - urx1;
-- llx = tx + lly1; lly = ty - llx1;
-- lrx = tx + lry1; lry = ty - lrx1;
-- } else {
-- ulx = tx + ulx1; uly = ty + uly1;
-- urx = tx + urx1; ury = ty + ury1;
-- llx = tx + llx1; lly = ty + lly1;
-- lrx = tx + lrx1; lry = ty + lry1;
-- }
-- xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
-- : (llx < lrx) ? llx : lrx
-- : (urx < llx) ? (urx < lrx) ? urx : lrx
-- : (llx < lrx) ? llx : lrx;
-- xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
-- : (llx > lrx) ? llx : lrx
-- : (urx > llx) ? (urx > lrx) ? urx : lrx
-- : (llx > lrx) ? llx : lrx;
-- yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
-- : (lly < lry) ? lly : lry
-- : (ury < lly) ? (ury < lry) ? ury : lry
-- : (lly < lry) ? lly : lry;
-- yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
-- : (lly > lry) ? lly : lry
-- : (ury > lly) ? (ury > lry) ? ury : lry
-- : (lly > lry) ? lly : lry;
-- clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
-- opClipRes = clipRes;
--
-- // compute Bresenham parameters for x and y scaling
-- yp = h / scaledHeight;
-- yq = h % scaledHeight;
-- xp = w / scaledWidth;
-- xq = w % scaledWidth;
-+ minorAxisZero = mat[1] == 0 && mat[2] == 0;
-
-- // allocate pixel buffer
-- pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w);
-+ // scaling only
-+ if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
-+ x0 = imgCoordMungeLowerC(mat[4], glyphMode);
-+ y0 = imgCoordMungeLowerC(mat[5], glyphMode);
-+ x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode);
-+ y1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode);
-+ // make sure narrow images cover at least one pixel
-+ if (x0 == x1) {
-+ ++x1;
-+ }
-+ if (y0 == y1) {
-+ ++y1;
-+ }
-+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
-+ opClipRes = clipRes;
-+ if (clipRes != splashClipAllOutside) {
-+ scaledWidth = x1 - x0;
-+ scaledHeight = y1 - y0;
-+ scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight);
-+ blitMask(scaledMask, x0, y0, clipRes);
-+ delete scaledMask;
-+ }
-+
-+ // scaling plus vertical flip
-+ } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
-+ x0 = imgCoordMungeLowerC(mat[4], glyphMode);
-+ y0 = imgCoordMungeLowerC(mat[3] + mat[5], glyphMode);
-+ x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode);
-+ y1 = imgCoordMungeUpperC(mat[5], glyphMode);
-+ // make sure narrow images cover at least one pixel
-+ if (x0 == x1) {
-+ ++x1;
-+ }
-+ if (y0 == y1) {
-+ ++y1;
-+ }
-+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
-+ opClipRes = clipRes;
-+ if (clipRes != splashClipAllOutside) {
-+ scaledWidth = x1 - x0;
-+ scaledHeight = y1 - y0;
-+ scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight);
-+ vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
-+ blitMask(scaledMask, x0, y0, clipRes);
-+ delete scaledMask;
-+ }
-
-- // initialize the pixel pipe
-- pipeInit(&pipe, 0, 0, state->fillPattern, NULL, state->fillAlpha,
-- gTrue, gFalse);
-- if (vectorAntialias) {
-- drawAAPixelInit();
-+ // all other cases
-+ } else {
-+ arbitraryTransformMask(src, srcData, w, h, mat, glyphMode);
- }
-
-- // init y scale Bresenham
-- yt = 0;
-- lastYStep = 1;
-+ return splashOk;
-+}
-
-- for (y = 0; y < scaledHeight; ++y) {
-+void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
-+ int srcWidth, int srcHeight,
-+ SplashCoord *mat, GBool glyphMode) {
-+ SplashBitmap *scaledMask;
-+ SplashClipResult clipRes, clipRes2;
-+ SplashPipe pipe;
-+ int scaledWidth, scaledHeight, t0, t1;
-+ SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11;
-+ SplashCoord vx[4], vy[4];
-+ int xMin, yMin, xMax, yMax;
-+ ImageSection section[3];
-+ int nSections;
-+ int y, xa, xb, x, i, xx, yy;
-+
-+ // compute the four vertices of the target quadrilateral
-+ vx[0] = mat[4]; vy[0] = mat[5];
-+ vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5];
-+ vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5];
-+ vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5];
-
-- // y scale Bresenham
-- yStep = yp;
-- yt += yq;
-- if (yt >= scaledHeight) {
-- yt -= scaledHeight;
-- ++yStep;
-+ // clipping
-+ xMin = imgCoordMungeLowerC(vx[0], glyphMode);
-+ xMax = imgCoordMungeUpperC(vx[0], glyphMode);
-+ yMin = imgCoordMungeLowerC(vy[0], glyphMode);
-+ yMax = imgCoordMungeUpperC(vy[0], glyphMode);
-+ for (i = 1; i < 4; ++i) {
-+ t0 = imgCoordMungeLowerC(vx[i], glyphMode);
-+ if (t0 < xMin) {
-+ xMin = t0;
-+ }
-+ t0 = imgCoordMungeUpperC(vx[i], glyphMode);
-+ if (t0 > xMax) {
-+ xMax = t0;
-+ }
-+ t1 = imgCoordMungeLowerC(vy[i], glyphMode);
-+ if (t1 < yMin) {
-+ yMin = t1;
-+ }
-+ t1 = imgCoordMungeUpperC(vy[i], glyphMode);
-+ if (t1 > yMax) {
-+ yMax = t1;
- }
-+ }
-+ clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1);
-+ opClipRes = clipRes;
-+ if (clipRes == splashClipAllOutside) {
-+ return;
-+ }
-
-- // read row(s) from image
-- n = (yp > 0) ? yStep : lastYStep;
-- if (n > 0) {
-- p = pixBuf;
-- for (i = 0; i < n; ++i) {
-- (*src)(srcData, p);
-- p += w;
-- }
-+ // compute the scale factors
-+ if (mat[0] >= 0) {
-+ t0 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode) -
-+ imgCoordMungeLowerC(mat[4], glyphMode);
-+ } else {
-+ t0 = imgCoordMungeUpperC(mat[4], glyphMode) -
-+ imgCoordMungeLowerC(mat[0] + mat[4], glyphMode);
-+ }
-+ if (mat[1] >= 0) {
-+ t1 = imgCoordMungeUpperC(mat[1] + mat[5], glyphMode) -
-+ imgCoordMungeLowerC(mat[5], glyphMode);
-+ } else {
-+ t1 = imgCoordMungeUpperC(mat[5], glyphMode) -
-+ imgCoordMungeLowerC(mat[1] + mat[5], glyphMode);
-+ }
-+ scaledWidth = t0 > t1 ? t0 : t1;
-+ if (mat[2] >= 0) {
-+ t0 = imgCoordMungeUpperC(mat[2] + mat[4], glyphMode) -
-+ imgCoordMungeLowerC(mat[4], glyphMode);
-+ } else {
-+ t0 = imgCoordMungeUpperC(mat[4], glyphMode) -
-+ imgCoordMungeLowerC(mat[2] + mat[4], glyphMode);
-+ }
-+ if (mat[3] >= 0) {
-+ t1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode) -
-+ imgCoordMungeLowerC(mat[5], glyphMode);
-+ } else {
-+ t1 = imgCoordMungeUpperC(mat[5], glyphMode) -
-+ imgCoordMungeLowerC(mat[3] + mat[5], glyphMode);
-+ }
-+ scaledHeight = t0 > t1 ? t0 : t1;
-+ if (scaledWidth == 0) {
-+ scaledWidth = 1;
-+ }
-+ if (scaledHeight == 0) {
-+ scaledHeight = 1;
-+ }
-+
-+ // compute the inverse transform (after scaling) matrix
-+ r00 = mat[0] / scaledWidth;
-+ r01 = mat[1] / scaledWidth;
-+ r10 = mat[2] / scaledHeight;
-+ r11 = mat[3] / scaledHeight;
-+ det = r00 * r11 - r01 * r10;
-+ if (splashAbs(det) < 1e-6) {
-+ // this should be caught by the singular matrix check in fillImageMask
-+ return;
-+ }
-+ ir00 = r11 / det;
-+ ir01 = -r01 / det;
-+ ir10 = -r10 / det;
-+ ir11 = r00 / det;
-+
-+ // scale the input image
-+ scaledMask = scaleMask(src, srcData, srcWidth, srcHeight,
-+ scaledWidth, scaledHeight);
-+
-+ // construct the three sections
-+ i = (vy[2] <= vy[3]) ? 2 : 3;
-+ if (vy[1] <= vy[i]) {
-+ i = 1;
-+ }
-+ if (vy[0] < vy[i] || (i != 3 && vy[0] == vy[i])) {
-+ i = 0;
-+ }
-+ if (vy[i] == vy[(i+1) & 3]) {
-+ section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode);
-+ section[0].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1;
-+ if (vx[i] < vx[(i+1) & 3]) {
-+ section[0].ia0 = i;
-+ section[0].ia1 = (i+3) & 3;
-+ section[0].ib0 = (i+1) & 3;
-+ section[0].ib1 = (i+2) & 3;
-+ } else {
-+ section[0].ia0 = (i+1) & 3;
-+ section[0].ia1 = (i+2) & 3;
-+ section[0].ib0 = i;
-+ section[0].ib1 = (i+3) & 3;
-+ }
-+ nSections = 1;
-+ } else {
-+ section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode);
-+ section[2].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1;
-+ section[0].ia0 = section[0].ib0 = i;
-+ section[2].ia1 = section[2].ib1 = (i+2) & 3;
-+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
-+ section[0].ia1 = section[2].ia0 = (i+1) & 3;
-+ section[0].ib1 = section[2].ib0 = (i+3) & 3;
-+ } else {
-+ section[0].ia1 = section[2].ia0 = (i+3) & 3;
-+ section[0].ib1 = section[2].ib0 = (i+1) & 3;
- }
-- lastYStep = yStep;
-+ if (vy[(i+1) & 3] < vy[(i+3) & 3]) {
-+ section[1].y0 = imgCoordMungeLowerC(vy[(i+1) & 3], glyphMode);
-+ section[2].y0 = imgCoordMungeUpperC(vy[(i+3) & 3], glyphMode);
-+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
-+ section[1].ia0 = (i+1) & 3;
-+ section[1].ia1 = (i+2) & 3;
-+ section[1].ib0 = i;
-+ section[1].ib1 = (i+3) & 3;
-+ } else {
-+ section[1].ia0 = i;
-+ section[1].ia1 = (i+3) & 3;
-+ section[1].ib0 = (i+1) & 3;
-+ section[1].ib1 = (i+2) & 3;
-+ }
-+ } else {
-+ section[1].y0 = imgCoordMungeLowerC(vy[(i+3) & 3], glyphMode);
-+ section[2].y0 = imgCoordMungeUpperC(vy[(i+1) & 3], glyphMode);
-+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
-+ section[1].ia0 = i;
-+ section[1].ia1 = (i+1) & 3;
-+ section[1].ib0 = (i+3) & 3;
-+ section[1].ib1 = (i+2) & 3;
-+ } else {
-+ section[1].ia0 = (i+3) & 3;
-+ section[1].ia1 = (i+2) & 3;
-+ section[1].ib0 = i;
-+ section[1].ib1 = (i+1) & 3;
-+ }
-+ }
-+ section[0].y1 = section[1].y0 - 1;
-+ section[1].y1 = section[2].y0 - 1;
-+ nSections = 3;
-+ }
-+ for (i = 0; i < nSections; ++i) {
-+ section[i].xa0 = vx[section[i].ia0];
-+ section[i].ya0 = vy[section[i].ia0];
-+ section[i].xa1 = vx[section[i].ia1];
-+ section[i].ya1 = vy[section[i].ia1];
-+ section[i].xb0 = vx[section[i].ib0];
-+ section[i].yb0 = vy[section[i].ib0];
-+ section[i].xb1 = vx[section[i].ib1];
-+ section[i].yb1 = vy[section[i].ib1];
-+ section[i].dxdya = (section[i].xa1 - section[i].xa0) /
-+ (section[i].ya1 - section[i].ya0);
-+ section[i].dxdyb = (section[i].xb1 - section[i].xb0) /
-+ (section[i].yb1 - section[i].yb0);
-+ }
-+
-+ // initialize the pixel pipe
-+ pipeInit(&pipe, 0, 0, state->fillPattern, NULL,
-+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
-+ if (vectorAntialias) {
-+ drawAAPixelInit();
-+ }
-
-- // loop-invariant constants
-- k1 = splashRound(xShear * ySign * y);
-+ // make sure narrow images cover at least one pixel
-+ if (nSections == 1) {
-+ if (section[0].y0 == section[0].y1) {
-+ ++section[0].y1;
-+ clipRes = opClipRes = splashClipPartial;
-+ }
-+ } else {
-+ if (section[0].y0 == section[2].y1) {
-+ ++section[1].y1;
-+ clipRes = opClipRes = splashClipPartial;
-+ }
-+ }
-
-- // clipping test
-- if (clipRes != splashClipAllInside &&
-- !rot &&
-- (int)(yShear * k1) ==
-- (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
-- if (xSign > 0) {
-- spanXMin = tx + k1;
-- spanXMax = spanXMin + (scaledWidth - 1);
-+ // scan all pixels inside the target region
-+ for (i = 0; i < nSections; ++i) {
-+ for (y = section[i].y0; y <= section[i].y1; ++y) {
-+ xa = imgCoordMungeLowerC(section[i].xa0 +
-+ ((SplashCoord)y + 0.5 - section[i].ya0) *
-+ section[i].dxdya,
-+ glyphMode);
-+ xb = imgCoordMungeUpperC(section[i].xb0 +
-+ ((SplashCoord)y + 0.5 - section[i].yb0) *
-+ section[i].dxdyb,
-+ glyphMode);
-+ // make sure narrow images cover at least one pixel
-+ if (xa == xb) {
-+ ++xb;
-+ }
-+ if (clipRes != splashClipAllInside) {
-+ clipRes2 = state->clip->testSpan(xa, xb - 1, y);
- } else {
-- spanXMax = tx + k1;
-- spanXMin = spanXMax - (scaledWidth - 1);
-+ clipRes2 = clipRes;
- }
-- spanY = ty + ySign * y + (int)(yShear * k1);
-- clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
-- if (clipRes2 == splashClipAllOutside) {
-- continue;
-+ for (x = xa; x < xb; ++x) {
-+ // map (x+0.5, y+0.5) back to the scaled image
-+ xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 +
-+ ((SplashCoord)y + 0.5 - mat[5]) * ir10);
-+ yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 +
-+ ((SplashCoord)y + 0.5 - mat[5]) * ir11);
-+ // xx should always be within bounds, but floating point
-+ // inaccuracy can cause problems
-+ if (xx < 0) {
-+ xx = 0;
-+ } else if (xx >= scaledWidth) {
-+ xx = scaledWidth - 1;
-+ }
-+ if (yy < 0) {
-+ yy = 0;
-+ } else if (yy >= scaledHeight) {
-+ yy = scaledHeight - 1;
-+ }
-+ pipe.shape = scaledMask->data[yy * scaledWidth + xx];
-+ if (vectorAntialias && clipRes2 != splashClipAllInside) {
-+ drawAAPixel(&pipe, x, y);
-+ } else {
-+ drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside);
-+ }
- }
-+ }
-+ }
-+
-+ delete scaledMask;
-+}
-+
-+// Scale an image mask into a SplashBitmap.
-+SplashBitmap *Splash::scaleMask(SplashImageMaskSource src, void *srcData,
-+ int srcWidth, int srcHeight,
-+ int scaledWidth, int scaledHeight) {
-+ SplashBitmap *dest;
-+
-+ dest = new SplashBitmap(scaledWidth, scaledHeight, 1, splashModeMono8,
-+ gFalse);
-+ if (scaledHeight < srcHeight) {
-+ if (scaledWidth < srcWidth) {
-+ scaleMaskYdXd(src, srcData, srcWidth, srcHeight,
-+ scaledWidth, scaledHeight, dest);
-+ } else {
-+ scaleMaskYdXu(src, srcData, srcWidth, srcHeight,
-+ scaledWidth, scaledHeight, dest);
-+ }
-+ } else {
-+ if (scaledWidth < srcWidth) {
-+ scaleMaskYuXd(src, srcData, srcWidth, srcHeight,
-+ scaledWidth, scaledHeight, dest);
- } else {
-- clipRes2 = clipRes;
-+ scaleMaskYuXu(src, srcData, srcWidth, srcHeight,
-+ scaledWidth, scaledHeight, dest);
- }
-+ }
-+ return dest;
-+}
-
-- // init x scale Bresenham
-- xt = 0;
-- xSrc = 0;
-+void Splash::scaleMaskYdXd(SplashImageMaskSource src, void *srcData,
-+ int srcWidth, int srcHeight,
-+ int scaledWidth, int scaledHeight,
-+ SplashBitmap *dest) {
-+ Guchar *lineBuf;
-+ Guint *pixBuf;
-+ Guint pix;
-+ Guchar *destPtr;
-+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1;
-+ int i, j;
-+
-+ // Bresenham parameters for y scale
-+ yp = srcHeight / scaledHeight;
-+ yq = srcHeight % scaledHeight;
-+
-+ // Bresenham parameters for x scale
-+ xp = srcWidth / scaledWidth;
-+ xq = srcWidth % scaledWidth;
-+
-+ // allocate buffers
-+ lineBuf = (Guchar *)gmalloc(srcWidth);
-+ pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
-
-- // x shear
-- x1 = k1;
-+ // init y scale Bresenham
-+ yt = 0;
-+
-+ destPtr = dest->data;
-+ for (y = 0; y < scaledHeight; ++y) {
-+
-+ // y scale Bresenham
-+ if ((yt += yq) >= scaledHeight) {
-+ yt -= scaledHeight;
-+ yStep = yp + 1;
-+ } else {
-+ yStep = yp;
-+ }
-
-- // y shear
-- y1 = (SplashCoord)ySign * y + yShear * x1;
-- // this is a kludge: if yShear1 is negative, then (int)y1 would
-- // change immediately after the first pixel, which is not what we
-- // want
-- if (yShear1 < 0) {
-- y1 += 0.999;
-+ // read rows from image
-+ memset(pixBuf, 0, srcWidth * sizeof(int));
-+ for (i = 0; i < yStep; ++i) {
-+ (*src)(srcData, lineBuf);
-+ for (j = 0; j < srcWidth; ++j) {
-+ pixBuf[j] += lineBuf[j];
-+ }
- }
-
-- // loop-invariant constants
-- n = yStep > 0 ? yStep : 1;
-+ // init x scale Bresenham
-+ xt = 0;
-+ d0 = (255 << 23) / (yStep * xp);
-+ d1 = (255 << 23) / (yStep * (xp + 1));
-
-+ xx = 0;
- for (x = 0; x < scaledWidth; ++x) {
-
- // x scale Bresenham
-- xStep = xp;
-- xt += xq;
-- if (xt >= scaledWidth) {
-+ if ((xt += xq) >= scaledWidth) {
- xt -= scaledWidth;
-- ++xStep;
-+ xStep = xp + 1;
-+ d = d1;
-+ } else {
-+ xStep = xp;
-+ d = d0;
-+ }
-+
-+ // compute the final pixel
-+ pix = 0;
-+ for (i = 0; i < xStep; ++i) {
-+ pix += pixBuf[xx++];
- }
-+ // (255 * pix) / xStep * yStep
-+ pix = (pix * d) >> 23;
-+
-+ // store the pixel
-+ *destPtr++ = (Guchar)pix;
-+ }
-+ }
-
-- // rotation
-- if (rot) {
-- x2 = (int)y1;
-- y2 = -x1;
-+ gfree(pixBuf);
-+ gfree(lineBuf);
-+}
-+
-+void Splash::scaleMaskYdXu(SplashImageMaskSource src, void *srcData,
-+ int srcWidth, int srcHeight,
-+ int scaledWidth, int scaledHeight,
-+ SplashBitmap *dest) {
-+ Guchar *lineBuf;
-+ Guint *pixBuf;
-+ Guint pix;
-+ Guchar *destPtr;
-+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d;
-+ int i, j;
-+
-+ // Bresenham parameters for y scale
-+ yp = srcHeight / scaledHeight;
-+ yq = srcHeight % scaledHeight;
-+
-+ // Bresenham parameters for x scale
-+ xp = scaledWidth / srcWidth;
-+ xq = scaledWidth % srcWidth;
-+
-+ // allocate buffers
-+ lineBuf = (Guchar *)gmalloc(srcWidth);
-+ pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
-+
-+ // init y scale Bresenham
-+ yt = 0;
-+
-+ destPtr = dest->data;
-+ for (y = 0; y < scaledHeight; ++y) {
-+
-+ // y scale Bresenham
-+ if ((yt += yq) >= scaledHeight) {
-+ yt -= scaledHeight;
-+ yStep = yp + 1;
-+ } else {
-+ yStep = yp;
-+ }
-+
-+ // read rows from image
-+ memset(pixBuf, 0, srcWidth * sizeof(int));
-+ for (i = 0; i < yStep; ++i) {
-+ (*src)(srcData, lineBuf);
-+ for (j = 0; j < srcWidth; ++j) {
-+ pixBuf[j] += lineBuf[j];
-+ }
-+ }
-+
-+ // init x scale Bresenham
-+ xt = 0;
-+ d = (255 << 23) / yStep;
-+
-+ for (x = 0; x < srcWidth; ++x) {
-+
-+ // x scale Bresenham
-+ if ((xt += xq) >= srcWidth) {
-+ xt -= srcWidth;
-+ xStep = xp + 1;
- } else {
-- x2 = x1;
-- y2 = (int)y1;
-+ xStep = xp;
- }
-
-- // compute the alpha value for (x,y) after the x and y scaling
-- // operations
-- m = xStep > 0 ? xStep : 1;
-- p = pixBuf + xSrc;
-- pixAcc = 0;
-- for (i = 0; i < n; ++i) {
-- for (j = 0; j < m; ++j) {
-- pixAcc += *p++;
-- }
-- p += w - m;
-+ // compute the final pixel
-+ pix = pixBuf[x];
-+ // (255 * pix) / yStep
-+ pix = (pix * d) >> 23;
-+
-+ // store the pixel
-+ for (i = 0; i < xStep; ++i) {
-+ *destPtr++ = (Guchar)pix;
- }
-+ }
-+ }
-
-- // blend fill color with background
-- if (pixAcc != 0) {
-- pipe.shape = (pixAcc == n * m)
-- ? (SplashCoord)1
-- : (SplashCoord)pixAcc / (SplashCoord)(n * m);
-- if (vectorAntialias && clipRes2 != splashClipAllInside) {
-- drawAAPixel(&pipe, tx + x2, ty + y2);
-- } else {
-- drawPixel(&pipe, tx + x2, ty + y2, clipRes2 == splashClipAllInside);
-- }
-+ gfree(pixBuf);
-+ gfree(lineBuf);
-+}
-+
-+void Splash::scaleMaskYuXd(SplashImageMaskSource src, void *srcData,
-+ int srcWidth, int srcHeight,
-+ int scaledWidth, int scaledHeight,
-+ SplashBitmap *dest) {
-+ Guchar *lineBuf;
-+ Guint pix;
-+ Guchar *destPtr0, *destPtr;
-+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1;
-+ int i;
-+
-+ // Bresenham parameters for y scale
-+ yp = scaledHeight / srcHeight;
-+ yq = scaledHeight % srcHeight;
-+
-+ // Bresenham parameters for x scale
-+ xp = srcWidth / scaledWidth;
-+ xq = srcWidth % scaledWidth;
-+
-+ // allocate buffers
-+ lineBuf = (Guchar *)gmalloc(srcWidth);
-+
-+ // init y scale Bresenham
-+ yt = 0;
-+
-+ destPtr0 = dest->data;
-+ for (y = 0; y < srcHeight; ++y) {
-+
-+ // y scale Bresenham
-+ if ((yt += yq) >= srcHeight) {
-+ yt -= srcHeight;
-+ yStep = yp + 1;
-+ } else {
-+ yStep = yp;
-+ }
-+
-+ // read row from image
-+ (*src)(srcData, lineBuf);
-+
-+ // init x scale Bresenham
-+ xt = 0;
-+ d0 = (255 << 23) / xp;
-+ d1 = (255 << 23) / (xp + 1);
-+
-+ xx = 0;
-+ for (x = 0; x < scaledWidth; ++x) {
-+
-+ // x scale Bresenham
-+ if ((xt += xq) >= scaledWidth) {
-+ xt -= scaledWidth;
-+ xStep = xp + 1;
-+ d = d1;
-+ } else {
-+ xStep = xp;
-+ d = d0;
-+ }
-+
-+ // compute the final pixel
-+ pix = 0;
-+ for (i = 0; i < xStep; ++i) {
-+ pix += lineBuf[xx++];
-+ }
-+ // (255 * pix) / xStep
-+ pix = (pix * d) >> 23;
-+
-+ // store the pixel
-+ for (i = 0; i < yStep; ++i) {
-+ destPtr = destPtr0 + i * scaledWidth + x;
-+ *destPtr = (Guchar)pix;
- }
-+ }
-+
-+ destPtr0 += yStep * scaledWidth;
-+ }
-+
-+ gfree(lineBuf);
-+}
-+
-+void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
-+ int srcWidth, int srcHeight,
-+ int scaledWidth, int scaledHeight,
-+ SplashBitmap *dest) {
-+ Guchar *lineBuf;
-+ Guint pix;
-+ Guchar *destPtr0, *destPtr;
-+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx;
-+ int i, j;
-+
-+ // Bresenham parameters for y scale
-+ yp = scaledHeight / srcHeight;
-+ yq = scaledHeight % srcHeight;
-+
-+ // Bresenham parameters for x scale
-+ xp = scaledWidth / srcWidth;
-+ xq = scaledWidth % srcWidth;
-+
-+ // allocate buffers
-+ lineBuf = (Guchar *)gmalloc(srcWidth);
-+
-+ // init y scale Bresenham
-+ yt = 0;
-+
-+ destPtr0 = dest->data;
-+ for (y = 0; y < srcHeight; ++y) {
-+
-+ // y scale Bresenham
-+ if ((yt += yq) >= srcHeight) {
-+ yt -= srcHeight;
-+ yStep = yp + 1;
-+ } else {
-+ yStep = yp;
-+ }
-+
-+ // read row from image
-+ (*src)(srcData, lineBuf);
-+
-+ // init x scale Bresenham
-+ xt = 0;
-+
-+ xx = 0;
-+ for (x = 0; x < srcWidth; ++x) {
-
- // x scale Bresenham
-- xSrc += xStep;
-+ if ((xt += xq) >= srcWidth) {
-+ xt -= srcWidth;
-+ xStep = xp + 1;
-+ } else {
-+ xStep = xp;
-+ }
-+
-+ // compute the final pixel
-+ pix = lineBuf[x] ? 255 : 0;
-
-- // x shear
-- x1 += xSign;
-+ // store the pixel
-+ for (i = 0; i < yStep; ++i) {
-+ for (j = 0; j < xStep; ++j) {
-+ destPtr = destPtr0 + i * scaledWidth + xx + j;
-+ *destPtr++ = (Guchar)pix;
-+ }
-+ }
-
-- // y shear
-- y1 += yShear1;
-+ xx += xStep;
- }
-+
-+ destPtr0 += yStep * scaledWidth;
- }
-
-- // free memory
-- gfree(pixBuf);
-+ gfree(lineBuf);
-+}
-
-- return splashOk;
-+void Splash::blitMask(SplashBitmap *src, int xDest, int yDest,
-+ SplashClipResult clipRes) {
-+ SplashPipe pipe;
-+ Guchar *p;
-+ int w, h, x, y;
-+
-+ w = src->getWidth();
-+ h = src->getHeight();
-+ if (vectorAntialias && clipRes != splashClipAllInside) {
-+ pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL,
-+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
-+ drawAAPixelInit();
-+ p = src->getDataPtr();
-+ for (y = 0; y < h; ++y) {
-+ for (x = 0; x < w; ++x) {
-+ pipe.shape = *p++;
-+ drawAAPixel(&pipe, xDest + x, yDest + y);
-+ }
-+ }
-+ } else {
-+ pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL,
-+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
-+ p = src->getDataPtr();
-+ if (clipRes == splashClipAllInside) {
-+ for (y = 0; y < h; ++y) {
-+ pipeSetXY(&pipe, xDest, yDest + y);
-+ for (x = 0; x < w; ++x) {
-+ if (*p) {
-+ pipe.shape = *p;
-+ (this->*pipe.run)(&pipe);
-+ } else {
-+ pipeIncX(&pipe);
-+ }
-+ ++p;
-+ }
-+ }
-+ updateModX(xDest);
-+ updateModX(xDest + w - 1);
-+ updateModY(yDest);
-+ updateModY(yDest + h - 1);
-+ } else {
-+ for (y = 0; y < h; ++y) {
-+ pipeSetXY(&pipe, xDest, yDest + y);
-+ for (x = 0; x < w; ++x) {
-+ if (*p && state->clip->test(xDest + x, yDest + y)) {
-+ pipe.shape = *p;
-+ (this->*pipe.run)(&pipe);
-+ updateModX(xDest + x);
-+ updateModY(yDest + y);
-+ } else {
-+ pipeIncX(&pipe);
-+ }
-+ ++p;
-+ }
-+ }
-+ }
-+ }
- }
-
- SplashError Splash::drawImage(SplashImageSource src, void *srcData,
- SplashColorMode srcMode, GBool srcAlpha,
- int w, int h, SplashCoord *mat) {
-- SplashPipe pipe;
-- GBool ok, rot;
-- SplashCoord xScale, yScale, xShear, yShear, yShear1;
-- int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
-- int ulx, uly, llx, lly, urx, ury, lrx, lry;
-- int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
-- int xMin, xMax, yMin, yMax;
-- SplashClipResult clipRes, clipRes2;
-- int yp, yq, yt, yStep, lastYStep;
-- int xp, xq, xt, xStep, xSrc;
-- int k1, spanXMin, spanXMax, spanY;
-- SplashColorPtr colorBuf, p;
-- SplashColor pix;
-- Guchar *alphaBuf, *q;
--#if SPLASH_CMYK
-- int pixAcc0, pixAcc1, pixAcc2, pixAcc3;
--#else
-- int pixAcc0, pixAcc1, pixAcc2;
--#endif
-- int alphaAcc;
-- SplashCoord pixMul, alphaMul, alpha;
-- int x, y, x1, x2, y2;
-- SplashCoord y1;
-- int nComps, n, m, i, j;
-+ GBool ok;
-+ SplashBitmap *scaledImg;
-+ SplashClipResult clipRes;
-+ GBool minorAxisZero;
-+ int x0, y0, x1, y1, scaledWidth, scaledHeight;
-+ int nComps;
-
- if (debugMode) {
- printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
-@@ -2106,666 +3155,1170 @@
- nComps = 4;
- break;
- #endif
-+ default:
-+ ok = gFalse;
-+ break;
- }
- if (!ok) {
- return splashErrModeMismatch;
- }
-
- // check for singular matrix
-- if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
-+ if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
- return splashErrSingularMatrix;
- }
-
-- // compute scale, shear, rotation, translation parameters
-- rot = splashAbs(mat[1]) > splashAbs(mat[0]);
-- if (rot) {
-- xScale = -mat[1];
-- yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
-- xShear = -mat[3] / yScale;
-- yShear = -mat[0] / mat[1];
-- } else {
-- xScale = mat[0];
-- yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
-- xShear = mat[2] / yScale;
-- yShear = mat[1] / mat[0];
-- }
-- // Note 1: The PDF spec says that all pixels whose *centers* lie
-- // within the region get painted -- but that doesn't seem to match
-- // up with what Acrobat actually does: it ends up leaving gaps
-- // between image stripes. So we use the same rule here as for
-- // fills: any pixel that overlaps the region gets painted.
-- // Note 2: The +/-0.01 in these computations is to avoid floating
-- // point precision problems which can lead to gaps between image
-- // stripes (it can cause image stripes to overlap, but that's a much
-- // less visible problem).
-- if (xScale >= 0) {
-- tx = splashFloor(mat[4] - 0.01);
-- tx2 = splashFloor(mat[4] + xScale + 0.01);
-- } else {
-- tx = splashFloor(mat[4] + 0.01);
-- tx2 = splashFloor(mat[4] + xScale - 0.01);
-- }
-- scaledWidth = abs(tx2 - tx) + 1;
-- if (yScale >= 0) {
-- ty = splashFloor(mat[5] - 0.01);
-- ty2 = splashFloor(mat[5] + yScale + 0.01);
-- } else {
-- ty = splashFloor(mat[5] + 0.01);
-- ty2 = splashFloor(mat[5] + yScale - 0.01);
-- }
-- scaledHeight = abs(ty2 - ty) + 1;
-- xSign = (xScale < 0) ? -1 : 1;
-- ySign = (yScale < 0) ? -1 : 1;
-- yShear1 = (SplashCoord)xSign * yShear;
-+ minorAxisZero = mat[1] == 0 && mat[2] == 0;
-+
-+ // scaling only
-+ if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
-+ x0 = imgCoordMungeLower(mat[4]);
-+ y0 = imgCoordMungeLower(mat[5]);
-+ x1 = imgCoordMungeUpper(mat[0] + mat[4]);
-+ y1 = imgCoordMungeUpper(mat[3] + mat[5]);
-+ // make sure narrow images cover at least one pixel
-+ if (x0 == x1) {
-+ ++x1;
-+ }
-+ if (y0 == y1) {
-+ ++y1;
-+ }
-+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
-+ opClipRes = clipRes;
-+ if (clipRes != splashClipAllOutside) {
-+ scaledWidth = x1 - x0;
-+ scaledHeight = y1 - y0;
-+ scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
-+ scaledWidth, scaledHeight);
-+ blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
-+ delete scaledImg;
-+ }
-+
-+ // scaling plus vertical flip
-+ } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
-+ x0 = imgCoordMungeLower(mat[4]);
-+ y0 = imgCoordMungeLower(mat[3] + mat[5]);
-+ x1 = imgCoordMungeUpper(mat[0] + mat[4]);
-+ y1 = imgCoordMungeUpper(mat[5]);
-+ if (x0 == x1) {
-+ if (mat[4] + mat[0] * 0.5 < x0) {
-+ --x0;
-+ } else {
-+ ++x1;
-+ }
-+ }
-+ if (y0 == y1) {
-+ if (mat[5] + mat[1] * 0.5 < y0) {
-+ --y0;
-+ } else {
-+ ++y1;
-+ }
-+ }
-+ clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
-+ opClipRes = clipRes;
-+ if (clipRes != splashClipAllOutside) {
-+ scaledWidth = x1 - x0;
-+ scaledHeight = y1 - y0;
-+ scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
-+ scaledWidth, scaledHeight);
-+ vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
-+ blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
-+ delete scaledImg;
-+ }
-+
-+ // all other cases
-+ } else {
-+ arbitraryTransformImage(src, srcData, srcMode, nComps, srcAlpha,
-+ w, h, mat);
-+ }
-+
-+ return splashOk;
-+}
-+
-+void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData,
-+ SplashColorMode srcMode, int nComps,
-+ GBool srcAlpha,
-+ int srcWidth, int srcHeight,
-+ SplashCoord *mat) {
-+ SplashBitmap *scaledImg;
-+ SplashClipResult clipRes, clipRes2;
-+ SplashPipe pipe;
-+ SplashColor pixel;
-+ int scaledWidth, scaledHeight, t0, t1;
-+ SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11;
-+ SplashCoord vx[4], vy[4];
-+ int xMin, yMin, xMax, yMax;
-+ ImageSection section[3];
-+ int nSections;
-+ int y, xa, xb, x, i, xx, yy;
-+
-+ // compute the four vertices of the target quadrilateral
-+ vx[0] = mat[4]; vy[0] = mat[5];
-+ vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5];
-+ vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5];
-+ vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5];
-
- // clipping
-- ulx1 = 0;
-- uly1 = 0;
-- urx1 = xSign * (scaledWidth - 1);
-- ury1 = (int)(yShear * urx1);
-- llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
-- lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
-- lrx1 = xSign * (scaledWidth - 1) +
-- splashRound(xShear * ySign * (scaledHeight - 1));
-- lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
-- if (rot) {
-- ulx = tx + uly1; uly = ty - ulx1;
-- urx = tx + ury1; ury = ty - urx1;
-- llx = tx + lly1; lly = ty - llx1;
-- lrx = tx + lry1; lry = ty - lrx1;
-- } else {
-- ulx = tx + ulx1; uly = ty + uly1;
-- urx = tx + urx1; ury = ty + ury1;
-- llx = tx + llx1; lly = ty + lly1;
-- lrx = tx + lrx1; lry = ty + lry1;
-- }
-- xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
-- : (llx < lrx) ? llx : lrx
-- : (urx < llx) ? (urx < lrx) ? urx : lrx
-- : (llx < lrx) ? llx : lrx;
-- xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
-- : (llx > lrx) ? llx : lrx
-- : (urx > llx) ? (urx > lrx) ? urx : lrx
-- : (llx > lrx) ? llx : lrx;
-- yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
-- : (lly < lry) ? lly : lry
-- : (ury < lly) ? (ury < lry) ? ury : lry
-- : (lly < lry) ? lly : lry;
-- yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
-- : (lly > lry) ? lly : lry
-- : (ury > lly) ? (ury > lry) ? ury : lry
-- : (lly > lry) ? lly : lry;
-- clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
-+ xMin = imgCoordMungeLower(vx[0]);
-+ xMax = imgCoordMungeUpper(vx[0]);
-+ yMin = imgCoordMungeLower(vy[0]);
-+ yMax = imgCoordMungeUpper(vy[0]);
-+ for (i = 1; i < 4; ++i) {
-+ t0 = imgCoordMungeLower(vx[i]);
-+ if (t0 < xMin) {
-+ xMin = t0;
-+ }
-+ t0 = imgCoordMungeUpper(vx[i]);
-+ if (t0 > xMax) {
-+ xMax = t0;
-+ }
-+ t1 = imgCoordMungeLower(vy[i]);
-+ if (t1 < yMin) {
-+ yMin = t1;
-+ }
-+ t1 = imgCoordMungeUpper(vy[i]);
-+ if (t1 > yMax) {
-+ yMax = t1;
-+ }
-+ }
-+ clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1);
- opClipRes = clipRes;
- if (clipRes == splashClipAllOutside) {
-- return splashOk;
-+ return;
- }
-
-- // compute Bresenham parameters for x and y scaling
-- yp = h / scaledHeight;
-- yq = h % scaledHeight;
-- xp = w / scaledWidth;
-- xq = w % scaledWidth;
--
-- // allocate pixel buffers
-- colorBuf = (SplashColorPtr)gmalloc((yp + 1) * w * nComps);
-- if (srcAlpha) {
-- alphaBuf = (Guchar *)gmalloc((yp + 1) * w);
-+ // compute the scale factors
-+ if (mat[0] >= 0) {
-+ t0 = imgCoordMungeUpper(mat[0] + mat[4]) - imgCoordMungeLower(mat[4]);
-+ } else {
-+ t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[0] + mat[4]);
-+ }
-+ if (mat[1] >= 0) {
-+ t1 = imgCoordMungeUpper(mat[1] + mat[5]) - imgCoordMungeLower(mat[5]);
-+ } else {
-+ t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[1] + mat[5]);
-+ }
-+ scaledWidth = t0 > t1 ? t0 : t1;
-+ if (mat[2] >= 0) {
-+ t0 = imgCoordMungeUpper(mat[2] + mat[4]) - imgCoordMungeLower(mat[4]);
-+ } else {
-+ t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[2] + mat[4]);
-+ }
-+ if (mat[3] >= 0) {
-+ t1 = imgCoordMungeUpper(mat[3] + mat[5]) - imgCoordMungeLower(mat[5]);
- } else {
-- alphaBuf = NULL;
-+ t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[3] + mat[5]);
-+ }
-+ scaledHeight = t0 > t1 ? t0 : t1;
-+ if (scaledWidth == 0) {
-+ scaledWidth = 1;
-+ }
-+ if (scaledHeight == 0) {
-+ scaledHeight = 1;
-+ }
-+
-+ // compute the inverse transform (after scaling) matrix
-+ r00 = mat[0] / scaledWidth;
-+ r01 = mat[1] / scaledWidth;
-+ r10 = mat[2] / scaledHeight;
-+ r11 = mat[3] / scaledHeight;
-+ det = r00 * r11 - r01 * r10;
-+ if (splashAbs(det) < 1e-6) {
-+ // this should be caught by the singular matrix check in drawImage
-+ return;
- }
-+ ir00 = r11 / det;
-+ ir01 = -r01 / det;
-+ ir10 = -r10 / det;
-+ ir11 = r00 / det;
-+
-+ // scale the input image
-+ scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha,
-+ srcWidth, srcHeight, scaledWidth, scaledHeight);
-
-- pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy
--#if SPLASH_CMYK
-- pixAcc3 = 0; // make gcc happy
--#endif
-+ // construct the three sections
-+ i = 0;
-+ if (vy[1] < vy[i]) {
-+ i = 1;
-+ }
-+ if (vy[2] < vy[i]) {
-+ i = 2;
-+ }
-+ if (vy[3] < vy[i]) {
-+ i = 3;
-+ }
-+ // NB: if using fixed point, 0.000001 will be truncated to zero,
-+ // so these two comparisons must be <=, not <
-+ if (splashAbs(vy[i] - vy[(i-1) & 3]) <= 0.000001 &&
-+ vy[(i-1) & 3] < vy[(i+1) & 3]) {
-+ i = (i-1) & 3;
-+ }
-+ if (splashAbs(vy[i] - vy[(i+1) & 3]) <= 0.000001) {
-+ section[0].y0 = imgCoordMungeLower(vy[i]);
-+ section[0].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1;
-+ if (vx[i] < vx[(i+1) & 3]) {
-+ section[0].ia0 = i;
-+ section[0].ia1 = (i+3) & 3;
-+ section[0].ib0 = (i+1) & 3;
-+ section[0].ib1 = (i+2) & 3;
-+ } else {
-+ section[0].ia0 = (i+1) & 3;
-+ section[0].ia1 = (i+2) & 3;
-+ section[0].ib0 = i;
-+ section[0].ib1 = (i+3) & 3;
-+ }
-+ nSections = 1;
-+ } else {
-+ section[0].y0 = imgCoordMungeLower(vy[i]);
-+ section[2].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1;
-+ section[0].ia0 = section[0].ib0 = i;
-+ section[2].ia1 = section[2].ib1 = (i+2) & 3;
-+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
-+ section[0].ia1 = section[2].ia0 = (i+1) & 3;
-+ section[0].ib1 = section[2].ib0 = (i+3) & 3;
-+ } else {
-+ section[0].ia1 = section[2].ia0 = (i+3) & 3;
-+ section[0].ib1 = section[2].ib0 = (i+1) & 3;
-+ }
-+ if (vy[(i+1) & 3] < vy[(i+3) & 3]) {
-+ section[1].y0 = imgCoordMungeLower(vy[(i+1) & 3]);
-+ section[2].y0 = imgCoordMungeUpper(vy[(i+3) & 3]);
-+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
-+ section[1].ia0 = (i+1) & 3;
-+ section[1].ia1 = (i+2) & 3;
-+ section[1].ib0 = i;
-+ section[1].ib1 = (i+3) & 3;
-+ } else {
-+ section[1].ia0 = i;
-+ section[1].ia1 = (i+3) & 3;
-+ section[1].ib0 = (i+1) & 3;
-+ section[1].ib1 = (i+2) & 3;
-+ }
-+ } else {
-+ section[1].y0 = imgCoordMungeLower(vy[(i+3) & 3]);
-+ section[2].y0 = imgCoordMungeUpper(vy[(i+1) & 3]);
-+ if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
-+ section[1].ia0 = i;
-+ section[1].ia1 = (i+1) & 3;
-+ section[1].ib0 = (i+3) & 3;
-+ section[1].ib1 = (i+2) & 3;
-+ } else {
-+ section[1].ia0 = (i+3) & 3;
-+ section[1].ia1 = (i+2) & 3;
-+ section[1].ib0 = i;
-+ section[1].ib1 = (i+1) & 3;
-+ }
-+ }
-+ section[0].y1 = section[1].y0 - 1;
-+ section[1].y1 = section[2].y0 - 1;
-+ nSections = 3;
-+ }
-+ for (i = 0; i < nSections; ++i) {
-+ section[i].xa0 = vx[section[i].ia0];
-+ section[i].ya0 = vy[section[i].ia0];
-+ section[i].xa1 = vx[section[i].ia1];
-+ section[i].ya1 = vy[section[i].ia1];
-+ section[i].xb0 = vx[section[i].ib0];
-+ section[i].yb0 = vy[section[i].ib0];
-+ section[i].xb1 = vx[section[i].ib1];
-+ section[i].yb1 = vy[section[i].ib1];
-+ section[i].dxdya = (section[i].xa1 - section[i].xa0) /
-+ (section[i].ya1 - section[i].ya0);
-+ section[i].dxdyb = (section[i].xb1 - section[i].xb0) /
-+ (section[i].yb1 - section[i].yb0);
-+ }
-
- // initialize the pixel pipe
-- pipeInit(&pipe, 0, 0, NULL, pix, state->fillAlpha,
-+ pipeInit(&pipe, 0, 0, NULL, pixel,
-+ (Guchar)splashRound(state->fillAlpha * 255),
- srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
- gFalse);
- if (vectorAntialias) {
- drawAAPixelInit();
- }
-
-+ // make sure narrow images cover at least one pixel
-+ if (nSections == 1) {
-+ if (section[0].y0 == section[0].y1) {
-+ ++section[0].y1;
-+ clipRes = opClipRes = splashClipPartial;
-+ }
-+ } else {
-+ if (section[0].y0 == section[2].y1) {
-+ ++section[1].y1;
-+ clipRes = opClipRes = splashClipPartial;
-+ }
-+ }
-+
-+ // scan all pixels inside the target region
-+ for (i = 0; i < nSections; ++i) {
-+ for (y = section[i].y0; y <= section[i].y1; ++y) {
-+ xa = imgCoordMungeLower(section[i].xa0 +
-+ ((SplashCoord)y + 0.5 - section[i].ya0) *
-+ section[i].dxdya);
-+ xb = imgCoordMungeUpper(section[i].xb0 +
-+ ((SplashCoord)y + 0.5 - section[i].yb0) *
-+ section[i].dxdyb);
-+ // make sure narrow images cover at least one pixel
-+ if (xa == xb) {
-+ ++xb;
-+ }
-+ if (clipRes != splashClipAllInside) {
-+ clipRes2 = state->clip->testSpan(xa, xb - 1, y);
-+ } else {
-+ clipRes2 = clipRes;
-+ }
-+ for (x = xa; x < xb; ++x) {
-+ // map (x+0.5, y+0.5) back to the scaled image
-+ xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 +
-+ ((SplashCoord)y + 0.5 - mat[5]) * ir10);
-+ yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 +
-+ ((SplashCoord)y + 0.5 - mat[5]) * ir11);
-+ // xx should always be within bounds, but floating point
-+ // inaccuracy can cause problems
-+ if (xx < 0) {
-+ xx = 0;
-+ } else if (xx >= scaledWidth) {
-+ xx = scaledWidth - 1;
-+ }
-+ if (yy < 0) {
-+ yy = 0;
-+ } else if (yy >= scaledHeight) {
-+ yy = scaledHeight - 1;
-+ }
-+ scaledImg->getPixel(xx, yy, pixel);
-+ if (srcAlpha) {
-+ pipe.shape = scaledImg->alpha[yy * scaledWidth + xx];
-+ } else {
-+ pipe.shape = 255;
-+ }
-+ if (vectorAntialias && clipRes2 != splashClipAllInside) {
-+ drawAAPixel(&pipe, x, y);
-+ } else {
-+ drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside);
-+ }
-+ }
-+ }
-+ }
-+
-+ delete scaledImg;
-+}
-+
-+// Scale an image into a SplashBitmap.
-+SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData,
-+ SplashColorMode srcMode, int nComps,
-+ GBool srcAlpha, int srcWidth, int srcHeight,
-+ int scaledWidth, int scaledHeight) {
-+ SplashBitmap *dest;
-+
-+ dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha);
-+ if (scaledHeight < srcHeight) {
-+ if (scaledWidth < srcWidth) {
-+ scaleImageYdXd(src, srcData, srcMode, nComps, srcAlpha,
-+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
-+ } else {
-+ scaleImageYdXu(src, srcData, srcMode, nComps, srcAlpha,
-+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
-+ }
-+ } else {
-+ if (scaledWidth < srcWidth) {
-+ scaleImageYuXd(src, srcData, srcMode, nComps, srcAlpha,
-+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
-+ } else {
-+ scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha,
-+ srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
-+ }
-+ }
-+ return dest;
-+}
-+
-+void Splash::scaleImageYdXd(SplashImageSource src, void *srcData,
-+ SplashColorMode srcMode, int nComps,
-+ GBool srcAlpha, int srcWidth, int srcHeight,
-+ int scaledWidth, int scaledHeight,
-+ SplashBitmap *dest) {
-+ Guchar *lineBuf, *alphaLineBuf;
-+ Guint *pixBuf, *alphaPixBuf;
-+ Guint pix0, pix1, pix2;
-+#if SPLASH_CMYK
-+ Guint pix3;
-+#endif
-+ Guint alpha;
-+ Guchar *destPtr, *destAlphaPtr;
-+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1;
-+ int i, j;
-+
-+ // Bresenham parameters for y scale
-+ yp = srcHeight / scaledHeight;
-+ yq = srcHeight % scaledHeight;
-+
-+ // Bresenham parameters for x scale
-+ xp = srcWidth / scaledWidth;
-+ xq = srcWidth % scaledWidth;
-+
-+ // allocate buffers
-+ lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
-+ pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int));
- if (srcAlpha) {
-+ alphaLineBuf = (Guchar *)gmalloc(srcWidth);
-+ alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
-+ } else {
-+ alphaLineBuf = NULL;
-+ alphaPixBuf = NULL;
-+ }
-
-- // init y scale Bresenham
-- yt = 0;
-- lastYStep = 1;
-+ // init y scale Bresenham
-+ yt = 0;
-
-- for (y = 0; y < scaledHeight; ++y) {
-+ destPtr = dest->data;
-+ destAlphaPtr = dest->alpha;
-+ for (y = 0; y < scaledHeight; ++y) {
-
-- // y scale Bresenham
-+ // y scale Bresenham
-+ if ((yt += yq) >= scaledHeight) {
-+ yt -= scaledHeight;
-+ yStep = yp + 1;
-+ } else {
- yStep = yp;
-- yt += yq;
-- if (yt >= scaledHeight) {
-- yt -= scaledHeight;
-- ++yStep;
-- }
--
-- // read row(s) from image
-- n = (yp > 0) ? yStep : lastYStep;
-- if (n > 0) {
-- p = colorBuf;
-- q = alphaBuf;
-- for (i = 0; i < n; ++i) {
-- (*src)(srcData, p, q);
-- p += w * nComps;
-- q += w;
-- }
-- }
-- lastYStep = yStep;
--
-- // loop-invariant constants
-- k1 = splashRound(xShear * ySign * y);
--
-- // clipping test
-- if (clipRes != splashClipAllInside &&
-- !rot &&
-- (int)(yShear * k1) ==
-- (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
-- if (xSign > 0) {
-- spanXMin = tx + k1;
-- spanXMax = spanXMin + (scaledWidth - 1);
-- } else {
-- spanXMax = tx + k1;
-- spanXMin = spanXMax - (scaledWidth - 1);
-+ }
-+
-+ // read rows from image
-+ memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
-+ if (srcAlpha) {
-+ memset(alphaPixBuf, 0, srcWidth * sizeof(int));
-+ }
-+ for (i = 0; i < yStep; ++i) {
-+ (*src)(srcData, lineBuf, alphaLineBuf);
-+ for (j = 0; j < srcWidth * nComps; ++j) {
-+ pixBuf[j] += lineBuf[j];
-+ }
-+ if (srcAlpha) {
-+ for (j = 0; j < srcWidth; ++j) {
-+ alphaPixBuf[j] += alphaLineBuf[j];
- }
-- spanY = ty + ySign * y + (int)(yShear * k1);
-- clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
-- if (clipRes2 == splashClipAllOutside) {
-- continue;
-+ }
-+ }
-+
-+ // init x scale Bresenham
-+ xt = 0;
-+ d0 = (1 << 23) / (yStep * xp);
-+ d1 = (1 << 23) / (yStep * (xp + 1));
-+
-+ xx = xxa = 0;
-+ for (x = 0; x < scaledWidth; ++x) {
-+
-+ // x scale Bresenham
-+ if ((xt += xq) >= scaledWidth) {
-+ xt -= scaledWidth;
-+ xStep = xp + 1;
-+ d = d1;
-+ } else {
-+ xStep = xp;
-+ d = d0;
-+ }
-+
-+ switch (srcMode) {
-+
-+ case splashModeMono8:
-+
-+ // compute the final pixel
-+ pix0 = 0;
-+ for (i = 0; i < xStep; ++i) {
-+ pix0 += pixBuf[xx++];
-+ }
-+ // pix / xStep * yStep
-+ pix0 = (pix0 * d) >> 23;
-+
-+ // store the pixel
-+ *destPtr++ = (Guchar)pix0;
-+ break;
-+
-+ case splashModeRGB8:
-+
-+ // compute the final pixel
-+ pix0 = pix1 = pix2 = 0;
-+ for (i = 0; i < xStep; ++i) {
-+ pix0 += pixBuf[xx];
-+ pix1 += pixBuf[xx+1];
-+ pix2 += pixBuf[xx+2];
-+ xx += 3;
-+ }
-+ // pix / xStep * yStep
-+ pix0 = (pix0 * d) >> 23;
-+ pix1 = (pix1 * d) >> 23;
-+ pix2 = (pix2 * d) >> 23;
-+
-+ // store the pixel
-+ *destPtr++ = (Guchar)pix0;
-+ *destPtr++ = (Guchar)pix1;
-+ *destPtr++ = (Guchar)pix2;
-+ break;
-+
-+ case splashModeBGR8:
-+
-+ // compute the final pixel
-+ pix0 = pix1 = pix2 = 0;
-+ for (i = 0; i < xStep; ++i) {
-+ pix0 += pixBuf[xx];
-+ pix1 += pixBuf[xx+1];
-+ pix2 += pixBuf[xx+2];
-+ xx += 3;
-+ }
-+ // pix / xStep * yStep
-+ pix0 = (pix0 * d) >> 23;
-+ pix1 = (pix1 * d) >> 23;
-+ pix2 = (pix2 * d) >> 23;
-+
-+ // store the pixel
-+ *destPtr++ = (Guchar)pix2;
-+ *destPtr++ = (Guchar)pix1;
-+ *destPtr++ = (Guchar)pix0;
-+ break;
-+
-+#if SPLASH_CMYK
-+ case splashModeCMYK8:
-+
-+ // compute the final pixel
-+ pix0 = pix1 = pix2 = pix3 = 0;
-+ for (i = 0; i < xStep; ++i) {
-+ pix0 += pixBuf[xx];
-+ pix1 += pixBuf[xx+1];
-+ pix2 += pixBuf[xx+2];
-+ pix3 += pixBuf[xx+3];
-+ xx += 4;
-+ }
-+ // pix / xStep * yStep
-+ pix0 = (pix0 * d) >> 23;
-+ pix1 = (pix1 * d) >> 23;
-+ pix2 = (pix2 * d) >> 23;
-+ pix3 = (pix3 * d) >> 23;
-+
-+ // store the pixel
-+ *destPtr++ = (Guchar)pix0;
-+ *destPtr++ = (Guchar)pix1;
-+ *destPtr++ = (Guchar)pix2;
-+ *destPtr++ = (Guchar)pix3;
-+ break;
-+#endif
-+
-+
-+ case splashModeMono1: // mono1 is not allowed
-+ default:
-+ break;
-+ }
-+
-+ // process alpha
-+ if (srcAlpha) {
-+ alpha = 0;
-+ for (i = 0; i < xStep; ++i, ++xxa) {
-+ alpha += alphaPixBuf[xxa];
-+ }
-+ // alpha / xStep * yStep
-+ alpha = (alpha * d) >> 23;
-+ *destAlphaPtr++ = (Guchar)alpha;
-+ }
-+ }
-+ }
-+
-+ gfree(alphaPixBuf);
-+ gfree(alphaLineBuf);
-+ gfree(pixBuf);
-+ gfree(lineBuf);
-+}
-+
-+void Splash::scaleImageYdXu(SplashImageSource src, void *srcData,
-+ SplashColorMode srcMode, int nComps,
-+ GBool srcAlpha, int srcWidth, int srcHeight,
-+ int scaledWidth, int scaledHeight,
-+ SplashBitmap *dest) {
-+ Guchar *lineBuf, *alphaLineBuf;
-+ Guint *pixBuf, *alphaPixBuf;
-+ Guint pix[splashMaxColorComps];
-+ Guint alpha;
-+ Guchar *destPtr, *destAlphaPtr;
-+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d;
-+ int i, j;
-+
-+ // Bresenham parameters for y scale
-+ yp = srcHeight / scaledHeight;
-+ yq = srcHeight % scaledHeight;
-+
-+ // Bresenham parameters for x scale
-+ xp = scaledWidth / srcWidth;
-+ xq = scaledWidth % srcWidth;
-+
-+ // allocate buffers
-+ lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
-+ pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int));
-+ if (srcAlpha) {
-+ alphaLineBuf = (Guchar *)gmalloc(srcWidth);
-+ alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
-+ } else {
-+ alphaLineBuf = NULL;
-+ alphaPixBuf = NULL;
-+ }
-+
-+ // init y scale Bresenham
-+ yt = 0;
-+
-+ destPtr = dest->data;
-+ destAlphaPtr = dest->alpha;
-+ for (y = 0; y < scaledHeight; ++y) {
-+
-+ // y scale Bresenham
-+ if ((yt += yq) >= scaledHeight) {
-+ yt -= scaledHeight;
-+ yStep = yp + 1;
-+ } else {
-+ yStep = yp;
-+ }
-+
-+ // read rows from image
-+ memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
-+ if (srcAlpha) {
-+ memset(alphaPixBuf, 0, srcWidth * sizeof(int));
-+ }
-+ for (i = 0; i < yStep; ++i) {
-+ (*src)(srcData, lineBuf, alphaLineBuf);
-+ for (j = 0; j < srcWidth * nComps; ++j) {
-+ pixBuf[j] += lineBuf[j];
-+ }
-+ if (srcAlpha) {
-+ for (j = 0; j < srcWidth; ++j) {
-+ alphaPixBuf[j] += alphaLineBuf[j];
- }
-+ }
-+ }
-+
-+ // init x scale Bresenham
-+ xt = 0;
-+ d = (1 << 23) / yStep;
-+
-+ for (x = 0; x < srcWidth; ++x) {
-+
-+ // x scale Bresenham
-+ if ((xt += xq) >= srcWidth) {
-+ xt -= srcWidth;
-+ xStep = xp + 1;
- } else {
-- clipRes2 = clipRes;
-+ xStep = xp;
-+ }
-+
-+ // compute the final pixel
-+ for (i = 0; i < nComps; ++i) {
-+ // pixBuf[] / yStep
-+ pix[i] = (pixBuf[x * nComps + i] * d) >> 23;
-+ }
-+
-+ // store the pixel
-+ switch (srcMode) {
-+ case splashModeMono1: // mono1 is not allowed
-+ break;
-+ case splashModeMono8:
-+ for (i = 0; i < xStep; ++i) {
-+ *destPtr++ = (Guchar)pix[0];
-+ }
-+ break;
-+ case splashModeRGB8:
-+ for (i = 0; i < xStep; ++i) {
-+ *destPtr++ = (Guchar)pix[0];
-+ *destPtr++ = (Guchar)pix[1];
-+ *destPtr++ = (Guchar)pix[2];
-+ }
-+ break;
-+ case splashModeBGR8:
-+ for (i = 0; i < xStep; ++i) {
-+ *destPtr++ = (Guchar)pix[2];
-+ *destPtr++ = (Guchar)pix[1];
-+ *destPtr++ = (Guchar)pix[0];
-+ }
-+ break;
-+#if SPLASH_CMYK
-+ case splashModeCMYK8:
-+ for (i = 0; i < xStep; ++i) {
-+ *destPtr++ = (Guchar)pix[0];
-+ *destPtr++ = (Guchar)pix[1];
-+ *destPtr++ = (Guchar)pix[2];
-+ *destPtr++ = (Guchar)pix[3];
-+ }
-+ break;
-+#endif
-+ }
-+
-+ // process alpha
-+ if (srcAlpha) {
-+ // alphaPixBuf[] / yStep
-+ alpha = (alphaPixBuf[x] * d) >> 23;
-+ for (i = 0; i < xStep; ++i) {
-+ *destAlphaPtr++ = (Guchar)alpha;
-+ }
- }
-+ }
-+ }
-
-- // init x scale Bresenham
-- xt = 0;
-- xSrc = 0;
--
-- // x shear
-- x1 = k1;
--
-- // y shear
-- y1 = (SplashCoord)ySign * y + yShear * x1;
-- // this is a kludge: if yShear1 is negative, then (int)y1 would
-- // change immediately after the first pixel, which is not what
-- // we want
-- if (yShear1 < 0) {
-- y1 += 0.999;
-- }
-+ gfree(alphaPixBuf);
-+ gfree(alphaLineBuf);
-+ gfree(pixBuf);
-+ gfree(lineBuf);
-+}
-
-- // loop-invariant constants
-- n = yStep > 0 ? yStep : 1;
-+void Splash::scaleImageYuXd(SplashImageSource src, void *srcData,
-+ SplashColorMode srcMode, int nComps,
-+ GBool srcAlpha, int srcWidth, int srcHeight,
-+ int scaledWidth, int scaledHeight,
-+ SplashBitmap *dest) {
-+ Guchar *lineBuf, *alphaLineBuf;
-+ Guint pix[splashMaxColorComps];
-+ Guint alpha;
-+ Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr;
-+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1;
-+ int i, j;
-+
-+ // Bresenham parameters for y scale
-+ yp = scaledHeight / srcHeight;
-+ yq = scaledHeight % srcHeight;
-+
-+ // Bresenham parameters for x scale
-+ xp = srcWidth / scaledWidth;
-+ xq = srcWidth % scaledWidth;
-
-- switch (srcMode) {
-+ // allocate buffers
-+ lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
-+ if (srcAlpha) {
-+ alphaLineBuf = (Guchar *)gmalloc(srcWidth);
-+ } else {
-+ alphaLineBuf = NULL;
-+ }
-
-- case splashModeMono1:
-- case splashModeMono8:
-- for (x = 0; x < scaledWidth; ++x) {
-+ // init y scale Bresenham
-+ yt = 0;
-
-- // x scale Bresenham
-- xStep = xp;
-- xt += xq;
-- if (xt >= scaledWidth) {
-- xt -= scaledWidth;
-- ++xStep;
-- }
-+ destPtr0 = dest->data;
-+ destAlphaPtr0 = dest->alpha;
-+ for (y = 0; y < srcHeight; ++y) {
-
-- // rotation
-- if (rot) {
-- x2 = (int)y1;
-- y2 = -x1;
-- } else {
-- x2 = x1;
-- y2 = (int)y1;
-- }
-+ // y scale Bresenham
-+ if ((yt += yq) >= srcHeight) {
-+ yt -= srcHeight;
-+ yStep = yp + 1;
-+ } else {
-+ yStep = yp;
-+ }
-
-- // compute the filtered pixel at (x,y) after the x and y scaling
-- // operations
-- m = xStep > 0 ? xStep : 1;
-- alphaAcc = 0;
-- p = colorBuf + xSrc;
-- q = alphaBuf + xSrc;
-- pixAcc0 = 0;
-- for (i = 0; i < n; ++i) {
-- for (j = 0; j < m; ++j) {
-- pixAcc0 += *p++;
-- alphaAcc += *q++;
-- }
-- p += w - m;
-- q += w - m;
-- }
-- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
-- alphaMul = pixMul * (1.0 / 255.0);
-- alpha = (SplashCoord)alphaAcc * alphaMul;
-+ // read row from image
-+ (*src)(srcData, lineBuf, alphaLineBuf);
-
-- if (alpha > 0) {
-- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
-+ // init x scale Bresenham
-+ xt = 0;
-+ d0 = (1 << 23) / xp;
-+ d1 = (1 << 23) / (xp + 1);
-
-- // set pixel
-- pipe.shape = alpha;
-- if (vectorAntialias && clipRes != splashClipAllInside) {
-- drawAAPixel(&pipe, tx + x2, ty + y2);
-- } else {
-- drawPixel(&pipe, tx + x2, ty + y2,
-- clipRes2 == splashClipAllInside);
-- }
-- }
-+ xx = xxa = 0;
-+ for (x = 0; x < scaledWidth; ++x) {
-
-- // x scale Bresenham
-- xSrc += xStep;
-+ // x scale Bresenham
-+ if ((xt += xq) >= scaledWidth) {
-+ xt -= scaledWidth;
-+ xStep = xp + 1;
-+ d = d1;
-+ } else {
-+ xStep = xp;
-+ d = d0;
-+ }
-
-- // x shear
-- x1 += xSign;
-+ // compute the final pixel
-+ for (i = 0; i < nComps; ++i) {
-+ pix[i] = 0;
-+ }
-+ for (i = 0; i < xStep; ++i) {
-+ for (j = 0; j < nComps; ++j, ++xx) {
-+ pix[j] += lineBuf[xx];
-+ }
-+ }
-+ for (i = 0; i < nComps; ++i) {
-+ // pix[] / xStep
-+ pix[i] = (pix[i] * d) >> 23;
-+ }
-
-- // y shear
-- y1 += yShear1;
-+ // store the pixel
-+ switch (srcMode) {
-+ case splashModeMono1: // mono1 is not allowed
-+ break;
-+ case splashModeMono8:
-+ for (i = 0; i < yStep; ++i) {
-+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
-+ *destPtr++ = (Guchar)pix[0];
- }
- break;
--
- case splashModeRGB8:
-+ for (i = 0; i < yStep; ++i) {
-+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
-+ *destPtr++ = (Guchar)pix[0];
-+ *destPtr++ = (Guchar)pix[1];
-+ *destPtr++ = (Guchar)pix[2];
-+ }
-+ break;
- case splashModeBGR8:
-- for (x = 0; x < scaledWidth; ++x) {
--
-- // x scale Bresenham
-- xStep = xp;
-- xt += xq;
-- if (xt >= scaledWidth) {
-- xt -= scaledWidth;
-- ++xStep;
-- }
--
-- // rotation
-- if (rot) {
-- x2 = (int)y1;
-- y2 = -x1;
-- } else {
-- x2 = x1;
-- y2 = (int)y1;
-- }
--
-- // compute the filtered pixel at (x,y) after the x and y scaling
-- // operations
-- m = xStep > 0 ? xStep : 1;
-- alphaAcc = 0;
-- p = colorBuf + xSrc * 3;
-- q = alphaBuf + xSrc;
-- pixAcc0 = pixAcc1 = pixAcc2 = 0;
-- for (i = 0; i < n; ++i) {
-- for (j = 0; j < m; ++j) {
-- pixAcc0 += *p++;
-- pixAcc1 += *p++;
-- pixAcc2 += *p++;
-- alphaAcc += *q++;
-- }
-- p += 3 * (w - m);
-- q += w - m;
-- }
-- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
-- alphaMul = pixMul * (1.0 / 255.0);
-- alpha = (SplashCoord)alphaAcc * alphaMul;
--
-- if (alpha > 0) {
-- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
-- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
-- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
--
-- // set pixel
-- pipe.shape = alpha;
-- if (vectorAntialias && clipRes != splashClipAllInside) {
-- drawAAPixel(&pipe, tx + x2, ty + y2);
-- } else {
-- drawPixel(&pipe, tx + x2, ty + y2,
-- clipRes2 == splashClipAllInside);
-- }
-- }
--
-- // x scale Bresenham
-- xSrc += xStep;
--
-- // x shear
-- x1 += xSign;
--
-- // y shear
-- y1 += yShear1;
-+ for (i = 0; i < yStep; ++i) {
-+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
-+ *destPtr++ = (Guchar)pix[2];
-+ *destPtr++ = (Guchar)pix[1];
-+ *destPtr++ = (Guchar)pix[0];
- }
- break;
--
- #if SPLASH_CMYK
- case splashModeCMYK8:
-- for (x = 0; x < scaledWidth; ++x) {
-+ for (i = 0; i < yStep; ++i) {
-+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
-+ *destPtr++ = (Guchar)pix[0];
-+ *destPtr++ = (Guchar)pix[1];
-+ *destPtr++ = (Guchar)pix[2];
-+ *destPtr++ = (Guchar)pix[3];
-+ }
-+ break;
-+#endif
-+ }
-
-- // x scale Bresenham
-- xStep = xp;
-- xt += xq;
-- if (xt >= scaledWidth) {
-- xt -= scaledWidth;
-- ++xStep;
-- }
-+ // process alpha
-+ if (srcAlpha) {
-+ alpha = 0;
-+ for (i = 0; i < xStep; ++i, ++xxa) {
-+ alpha += alphaLineBuf[xxa];
-+ }
-+ // alpha / xStep
-+ alpha = (alpha * d) >> 23;
-+ for (i = 0; i < yStep; ++i) {
-+ destAlphaPtr = destAlphaPtr0 + i * scaledWidth + x;
-+ *destAlphaPtr = (Guchar)alpha;
-+ }
-+ }
-+ }
-
-- // rotation
-- if (rot) {
-- x2 = (int)y1;
-- y2 = -x1;
-- } else {
-- x2 = x1;
-- y2 = (int)y1;
-- }
-+ destPtr0 += yStep * scaledWidth * nComps;
-+ if (srcAlpha) {
-+ destAlphaPtr0 += yStep * scaledWidth;
-+ }
-+ }
-
-- // compute the filtered pixel at (x,y) after the x and y scaling
-- // operations
-- m = xStep > 0 ? xStep : 1;
-- alphaAcc = 0;
-- p = colorBuf + xSrc * 4;
-- q = alphaBuf + xSrc;
-- pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
-- for (i = 0; i < n; ++i) {
-- for (j = 0; j < m; ++j) {
-- pixAcc0 += *p++;
-- pixAcc1 += *p++;
-- pixAcc2 += *p++;
-- pixAcc3 += *p++;
-- alphaAcc += *q++;
-- }
-- p += 4 * (w - m);
-- q += w - m;
-- }
-- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
-- alphaMul = pixMul * (1.0 / 255.0);
-- alpha = (SplashCoord)alphaAcc * alphaMul;
--
-- if (alpha > 0) {
-- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
-- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
-- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
-- pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
-+ gfree(alphaLineBuf);
-+ gfree(lineBuf);
-+}
-+
-+void Splash::scaleImageYuXu(SplashImageSource src, void *srcData,
-+ SplashColorMode srcMode, int nComps,
-+ GBool srcAlpha, int srcWidth, int srcHeight,
-+ int scaledWidth, int scaledHeight,
-+ SplashBitmap *dest) {
-+ Guchar *lineBuf, *alphaLineBuf;
-+ Guint pix[splashMaxColorComps];
-+ Guint alpha;
-+ Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr;
-+ int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx;
-+ int i, j;
-+
-+ // Bresenham parameters for y scale
-+ yp = scaledHeight / srcHeight;
-+ yq = scaledHeight % srcHeight;
-+
-+ // Bresenham parameters for x scale
-+ xp = scaledWidth / srcWidth;
-+ xq = scaledWidth % srcWidth;
-
-- // set pixel
-- pipe.shape = alpha;
-- if (vectorAntialias && clipRes != splashClipAllInside) {
-- drawAAPixel(&pipe, tx + x2, ty + y2);
-- } else {
-- drawPixel(&pipe, tx + x2, ty + y2,
-- clipRes2 == splashClipAllInside);
-- }
-- }
-+ // allocate buffers
-+ lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
-+ if (srcAlpha) {
-+ alphaLineBuf = (Guchar *)gmalloc(srcWidth);
-+ } else {
-+ alphaLineBuf = NULL;
-+ }
-
-- // x scale Bresenham
-- xSrc += xStep;
-+ // init y scale Bresenham
-+ yt = 0;
-
-- // x shear
-- x1 += xSign;
-+ destPtr0 = dest->data;
-+ destAlphaPtr0 = dest->alpha;
-+ for (y = 0; y < srcHeight; ++y) {
-
-- // y shear
-- y1 += yShear1;
-- }
-- break;
--#endif // SPLASH_CMYK
-- }
-+ // y scale Bresenham
-+ if ((yt += yq) >= srcHeight) {
-+ yt -= srcHeight;
-+ yStep = yp + 1;
-+ } else {
-+ yStep = yp;
- }
-
-- } else {
-+ // read row from image
-+ (*src)(srcData, lineBuf, alphaLineBuf);
-
-- // init y scale Bresenham
-- yt = 0;
-- lastYStep = 1;
-+ // init x scale Bresenham
-+ xt = 0;
-
-- for (y = 0; y < scaledHeight; ++y) {
-+ xx = 0;
-+ for (x = 0; x < srcWidth; ++x) {
-
-- // y scale Bresenham
-- yStep = yp;
-- yt += yq;
-- if (yt >= scaledHeight) {
-- yt -= scaledHeight;
-- ++yStep;
-- }
--
-- // read row(s) from image
-- n = (yp > 0) ? yStep : lastYStep;
-- if (n > 0) {
-- p = colorBuf;
-- for (i = 0; i < n; ++i) {
-- (*src)(srcData, p, NULL);
-- p += w * nComps;
-- }
-- }
-- lastYStep = yStep;
--
-- // loop-invariant constants
-- k1 = splashRound(xShear * ySign * y);
--
-- // clipping test
-- if (clipRes != splashClipAllInside &&
-- !rot &&
-- (int)(yShear * k1) ==
-- (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
-- if (xSign > 0) {
-- spanXMin = tx + k1;
-- spanXMax = spanXMin + (scaledWidth - 1);
-- } else {
-- spanXMax = tx + k1;
-- spanXMin = spanXMax - (scaledWidth - 1);
-- }
-- spanY = ty + ySign * y + (int)(yShear * k1);
-- clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
-- if (clipRes2 == splashClipAllOutside) {
-- continue;
-- }
-+ // x scale Bresenham
-+ if ((xt += xq) >= srcWidth) {
-+ xt -= srcWidth;
-+ xStep = xp + 1;
- } else {
-- clipRes2 = clipRes;
-+ xStep = xp;
- }
-
-- // init x scale Bresenham
-- xt = 0;
-- xSrc = 0;
--
-- // x shear
-- x1 = k1;
--
-- // y shear
-- y1 = (SplashCoord)ySign * y + yShear * x1;
-- // this is a kludge: if yShear1 is negative, then (int)y1 would
-- // change immediately after the first pixel, which is not what
-- // we want
-- if (yShear1 < 0) {
-- y1 += 0.999;
-+ // compute the final pixel
-+ for (i = 0; i < nComps; ++i) {
-+ pix[i] = lineBuf[x * nComps + i];
- }
-
-- // loop-invariant constants
-- n = yStep > 0 ? yStep : 1;
--
-+ // store the pixel
- switch (srcMode) {
--
-- case splashModeMono1:
-+ case splashModeMono1: // mono1 is not allowed
-+ break;
- case splashModeMono8:
-- for (x = 0; x < scaledWidth; ++x) {
--
-- // x scale Bresenham
-- xStep = xp;
-- xt += xq;
-- if (xt >= scaledWidth) {
-- xt -= scaledWidth;
-- ++xStep;
-+ for (i = 0; i < yStep; ++i) {
-+ for (j = 0; j < xStep; ++j) {
-+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
-+ *destPtr++ = (Guchar)pix[0];
- }
--
-- // rotation
-- if (rot) {
-- x2 = (int)y1;
-- y2 = -x1;
-- } else {
-- x2 = x1;
-- y2 = (int)y1;
-+ }
-+ break;
-+ case splashModeRGB8:
-+ for (i = 0; i < yStep; ++i) {
-+ for (j = 0; j < xStep; ++j) {
-+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
-+ *destPtr++ = (Guchar)pix[0];
-+ *destPtr++ = (Guchar)pix[1];
-+ *destPtr++ = (Guchar)pix[2];
- }
--
-- // compute the filtered pixel at (x,y) after the x and y scaling
-- // operations
-- m = xStep > 0 ? xStep : 1;
-- p = colorBuf + xSrc;
-- pixAcc0 = 0;
-- for (i = 0; i < n; ++i) {
-- for (j = 0; j < m; ++j) {
-- pixAcc0 += *p++;
-- }
-- p += w - m;
-+ }
-+ break;
-+ case splashModeBGR8:
-+ for (i = 0; i < yStep; ++i) {
-+ for (j = 0; j < xStep; ++j) {
-+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
-+ *destPtr++ = (Guchar)pix[2];
-+ *destPtr++ = (Guchar)pix[1];
-+ *destPtr++ = (Guchar)pix[0];
- }
-- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
--
-- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
--
-- // set pixel
-- if (vectorAntialias && clipRes != splashClipAllInside) {
-- pipe.shape = (SplashCoord)1;
-- drawAAPixel(&pipe, tx + x2, ty + y2);
-- } else {
-- drawPixel(&pipe, tx + x2, ty + y2,
-- clipRes2 == splashClipAllInside);
-+ }
-+ break;
-+#if SPLASH_CMYK
-+ case splashModeCMYK8:
-+ for (i = 0; i < yStep; ++i) {
-+ for (j = 0; j < xStep; ++j) {
-+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
-+ *destPtr++ = (Guchar)pix[0];
-+ *destPtr++ = (Guchar)pix[1];
-+ *destPtr++ = (Guchar)pix[2];
-+ *destPtr++ = (Guchar)pix[3];
- }
--
-- // x scale Bresenham
-- xSrc += xStep;
--
-- // x shear
-- x1 += xSign;
--
-- // y shear
-- y1 += yShear1;
- }
- break;
-+#endif
-+ }
-
-- case splashModeRGB8:
-- case splashModeBGR8:
-- for (x = 0; x < scaledWidth; ++x) {
--
-- // x scale Bresenham
-- xStep = xp;
-- xt += xq;
-- if (xt >= scaledWidth) {
-- xt -= scaledWidth;
-- ++xStep;
-+ // process alpha
-+ if (srcAlpha) {
-+ alpha = alphaLineBuf[x];
-+ for (i = 0; i < yStep; ++i) {
-+ for (j = 0; j < xStep; ++j) {
-+ destAlphaPtr = destAlphaPtr0 + i * scaledWidth + xx + j;
-+ *destAlphaPtr = (Guchar)alpha;
- }
-+ }
-+ }
-
-- // rotation
-- if (rot) {
-- x2 = (int)y1;
-- y2 = -x1;
-- } else {
-- x2 = x1;
-- y2 = (int)y1;
-- }
-+ xx += xStep;
-+ }
-
-- // compute the filtered pixel at (x,y) after the x and y scaling
-- // operations
-- m = xStep > 0 ? xStep : 1;
-- p = colorBuf + xSrc * 3;
-- pixAcc0 = pixAcc1 = pixAcc2 = 0;
-- for (i = 0; i < n; ++i) {
-- for (j = 0; j < m; ++j) {
-- pixAcc0 += *p++;
-- pixAcc1 += *p++;
-- pixAcc2 += *p++;
-- }
-- p += 3 * (w - m);
-- }
-- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
-+ destPtr0 += yStep * scaledWidth * nComps;
-+ if (srcAlpha) {
-+ destAlphaPtr0 += yStep * scaledWidth;
-+ }
-+ }
-
-- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
-- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
-- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
--
-- // set pixel
-- if (vectorAntialias && clipRes != splashClipAllInside) {
-- pipe.shape = (SplashCoord)1;
-- drawAAPixel(&pipe, tx + x2, ty + y2);
-- } else {
-- drawPixel(&pipe, tx + x2, ty + y2,
-- clipRes2 == splashClipAllInside);
-- }
-+ gfree(alphaLineBuf);
-+ gfree(lineBuf);
-+}
-+
-+void Splash::vertFlipImage(SplashBitmap *img, int width, int height,
-+ int nComps) {
-+ Guchar *lineBuf;
-+ Guchar *p0, *p1;
-+ int w;
-+
-+ w = width * nComps;
-+ lineBuf = (Guchar *)gmalloc(w);
-+ for (p0 = img->data, p1 = img->data + (height - 1) * w;
-+ p0 < p1;
-+ p0 += w, p1 -= w) {
-+ memcpy(lineBuf, p0, w);
-+ memcpy(p0, p1, w);
-+ memcpy(p1, lineBuf, w);
-+ }
-+ if (img->alpha) {
-+ for (p0 = img->alpha, p1 = img->alpha + (height - 1) * width;
-+ p0 < p1;
-+ p0 += width, p1 -= width) {
-+ memcpy(lineBuf, p0, width);
-+ memcpy(p0, p1, width);
-+ memcpy(p1, lineBuf, width);
-+ }
-+ }
-+ gfree(lineBuf);
-+}
-
-- // x scale Bresenham
-- xSrc += xStep;
-+void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
-+ SplashClipResult clipRes) {
-+ SplashPipe pipe;
-+ SplashColor pixel;
-+ Guchar *ap;
-+ int w, h, x0, y0, x1, y1, x, y;
-
-- // x shear
-- x1 += xSign;
-+ // split the image into clipped and unclipped regions
-+ w = src->getWidth();
-+ h = src->getHeight();
-+ if (clipRes == splashClipAllInside) {
-+ x0 = 0;
-+ y0 = 0;
-+ x1 = w;
-+ y1 = h;
-+ } else {
-+ if (state->clip->getNumPaths()) {
-+ x0 = x1 = w;
-+ y0 = y1 = h;
-+ } else {
-+ if ((x0 = splashCeil(state->clip->getXMin()) - xDest) < 0) {
-+ x0 = 0;
-+ }
-+ if ((y0 = splashCeil(state->clip->getYMin()) - yDest) < 0) {
-+ y0 = 0;
-+ }
-+ if ((x1 = splashFloor(state->clip->getXMax()) - xDest) > w) {
-+ x1 = w;
-+ }
-+ if (x1 < x0) {
-+ x1 = x0;
-+ }
-+ if ((y1 = splashFloor(state->clip->getYMax()) - yDest) > h) {
-+ y1 = h;
-+ }
-+ if (y1 < y0) {
-+ y1 = y0;
-+ }
-+ }
-+ }
-
-- // y shear
-- y1 += yShear1;
-+ // draw the unclipped region
-+ if (x0 < w && y0 < h && x0 < x1 && y0 < y1) {
-+ pipeInit(&pipe, xDest + x0, yDest + y0, NULL, pixel,
-+ (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse);
-+ if (srcAlpha) {
-+ for (y = y0; y < y1; ++y) {
-+ pipeSetXY(&pipe, xDest + x0, yDest + y);
-+ ap = src->getAlphaPtr() + y * w + x0;
-+ for (x = x0; x < x1; ++x) {
-+ src->getPixel(x, y, pixel);
-+ pipe.shape = *ap++;
-+ (this->*pipe.run)(&pipe);
- }
-- break;
-+ }
-+ } else {
-+ for (y = y0; y < y1; ++y) {
-+ pipeSetXY(&pipe, xDest + x0, yDest + y);
-+ for (x = x0; x < x1; ++x) {
-+ src->getPixel(x, y, pixel);
-+ (this->*pipe.run)(&pipe);
-+ }
-+ }
-+ }
-+ updateModX(xDest + x0);
-+ updateModX(xDest + x1 - 1);
-+ updateModY(yDest + y0);
-+ updateModY(yDest + y1 - 1);
-+ }
-
--#if SPLASH_CMYK
-- case splashModeCMYK8:
-- for (x = 0; x < scaledWidth; ++x) {
-+ // draw the clipped regions
-+ if (y0 > 0) {
-+ blitImageClipped(src, srcAlpha, 0, 0, xDest, yDest, w, y0);
-+ }
-+ if (y1 < h) {
-+ blitImageClipped(src, srcAlpha, 0, y1, xDest, yDest + y1, w, h - y1);
-+ }
-+ if (x0 > 0 && y0 < y1) {
-+ blitImageClipped(src, srcAlpha, 0, y0, xDest, yDest + y0, x0, y1 - y0);
-+ }
-+ if (x1 < w && y0 < y1) {
-+ blitImageClipped(src, srcAlpha, x1, y0, xDest + x1, yDest + y0,
-+ w - x1, y1 - y0);
-+ }
-+}
-
-- // x scale Bresenham
-- xStep = xp;
-- xt += xq;
-- if (xt >= scaledWidth) {
-- xt -= scaledWidth;
-- ++xStep;
-- }
-+void Splash::blitImageClipped(SplashBitmap *src, GBool srcAlpha,
-+ int xSrc, int ySrc, int xDest, int yDest,
-+ int w, int h) {
-+ SplashPipe pipe;
-+ SplashColor pixel;
-+ Guchar *ap;
-+ int x, y;
-
-- // rotation
-- if (rot) {
-- x2 = (int)y1;
-- y2 = -x1;
-+ if (vectorAntialias) {
-+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
-+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
-+ drawAAPixelInit();
-+ if (srcAlpha) {
-+ for (y = 0; y < h; ++y) {
-+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
-+ for (x = 0; x < w; ++x) {
-+ src->getPixel(xSrc + x, ySrc + y, pixel);
-+ pipe.shape = *ap++;
-+ drawAAPixel(&pipe, xDest + x, yDest + y);
-+ }
-+ }
-+ } else {
-+ for (y = 0; y < h; ++y) {
-+ for (x = 0; x < w; ++x) {
-+ src->getPixel(xSrc + x, ySrc + y, pixel);
-+ pipe.shape = 255;
-+ drawAAPixel(&pipe, xDest + x, yDest + y);
-+ }
-+ }
-+ }
-+ } else {
-+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
-+ (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse);
-+ if (srcAlpha) {
-+ for (y = 0; y < h; ++y) {
-+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
-+ pipeSetXY(&pipe, xDest, yDest + y);
-+ for (x = 0; x < w; ++x) {
-+ if (state->clip->test(xDest + x, yDest + y)) {
-+ src->getPixel(xSrc + x, ySrc + y, pixel);
-+ pipe.shape = *ap++;
-+ (this->*pipe.run)(&pipe);
-+ updateModX(xDest + x);
-+ updateModY(yDest + y);
- } else {
-- x2 = x1;
-- y2 = (int)y1;
-- }
--
-- // compute the filtered pixel at (x,y) after the x and y scaling
-- // operations
-- m = xStep > 0 ? xStep : 1;
-- p = colorBuf + xSrc * 4;
-- pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
-- for (i = 0; i < n; ++i) {
-- for (j = 0; j < m; ++j) {
-- pixAcc0 += *p++;
-- pixAcc1 += *p++;
-- pixAcc2 += *p++;
-- pixAcc3 += *p++;
-- }
-- p += 4 * (w - m);
-+ pipeIncX(&pipe);
-+ ++ap;
- }
-- pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
--
-- pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
-- pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
-- pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
-- pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
--
-- // set pixel
-- if (vectorAntialias && clipRes != splashClipAllInside) {
-- pipe.shape = (SplashCoord)1;
-- drawAAPixel(&pipe, tx + x2, ty + y2);
-+ }
-+ }
-+ } else {
-+ for (y = 0; y < h; ++y) {
-+ pipeSetXY(&pipe, xDest, yDest + y);
-+ for (x = 0; x < w; ++x) {
-+ if (state->clip->test(xDest + x, yDest + y)) {
-+ src->getPixel(xSrc + x, ySrc + y, pixel);
-+ (this->*pipe.run)(&pipe);
-+ updateModX(xDest + x);
-+ updateModY(yDest + y);
- } else {
-- drawPixel(&pipe, tx + x2, ty + y2,
-- clipRes2 == splashClipAllInside);
-+ pipeIncX(&pipe);
- }
--
-- // x scale Bresenham
-- xSrc += xStep;
--
-- // x shear
-- x1 += xSign;
--
-- // y shear
-- y1 += yShear1;
- }
-- break;
--#endif // SPLASH_CMYK
- }
- }
--
- }
--
-- gfree(colorBuf);
-- gfree(alphaBuf);
--
-- return splashOk;
- }
-
- SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
-@@ -2782,39 +4335,72 @@
- }
-
- if (src->alpha) {
-- pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
-- gTrue, nonIsolated);
-- for (y = 0; y < h; ++y) {
-- pipeSetXY(&pipe, xDest, yDest + y);
-- ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
-- for (x = 0; x < w; ++x) {
-- src->getPixel(xSrc + x, ySrc + y, pixel);
-- alpha = *ap++;
-- if (noClip || state->clip->test(xDest + x, yDest + y)) {
-+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
-+ (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated);
-+ if (noClip) {
-+ for (y = 0; y < h; ++y) {
-+ pipeSetXY(&pipe, xDest, yDest + y);
-+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
-+ for (x = 0; x < w; ++x) {
-+ src->getPixel(xSrc + x, ySrc + y, pixel);
-+ alpha = *ap++;
- // this uses shape instead of alpha, which isn't technically
- // correct, but works out the same
-- pipe.shape = (SplashCoord)(alpha / 255.0);
-- pipeRun(&pipe);
-- updateModX(xDest + x);
-- updateModY(yDest + y);
-- } else {
-- pipeIncX(&pipe);
-+ pipe.shape = alpha;
-+ (this->*pipe.run)(&pipe);
-+ }
-+ }
-+ updateModX(xDest);
-+ updateModX(xDest + w - 1);
-+ updateModY(yDest);
-+ updateModY(yDest + h - 1);
-+ } else {
-+ for (y = 0; y < h; ++y) {
-+ pipeSetXY(&pipe, xDest, yDest + y);
-+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
-+ for (x = 0; x < w; ++x) {
-+ src->getPixel(xSrc + x, ySrc + y, pixel);
-+ alpha = *ap++;
-+ if (state->clip->test(xDest + x, yDest + y)) {
-+ // this uses shape instead of alpha, which isn't technically
-+ // correct, but works out the same
-+ pipe.shape = alpha;
-+ (this->*pipe.run)(&pipe);
-+ updateModX(xDest + x);
-+ updateModY(yDest + y);
-+ } else {
-+ pipeIncX(&pipe);
-+ }
- }
- }
- }
- } else {
-- pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
-- gFalse, nonIsolated);
-- for (y = 0; y < h; ++y) {
-- pipeSetXY(&pipe, xDest, yDest + y);
-- for (x = 0; x < w; ++x) {
-- src->getPixel(xSrc + x, ySrc + y, pixel);
-- if (noClip || state->clip->test(xDest + x, yDest + y)) {
-- pipeRun(&pipe);
-- updateModX(xDest + x);
-- updateModY(yDest + y);
-- } else {
-- pipeIncX(&pipe);
-+ pipeInit(&pipe, xDest, yDest, NULL, pixel,
-+ (Guchar)splashRound(state->fillAlpha * 255), gFalse, nonIsolated);
-+ if (noClip) {
-+ for (y = 0; y < h; ++y) {
-+ pipeSetXY(&pipe, xDest, yDest + y);
-+ for (x = 0; x < w; ++x) {
-+ src->getPixel(xSrc + x, ySrc + y, pixel);
-+ (this->*pipe.run)(&pipe);
-+ }
-+ }
-+ updateModX(xDest);
-+ updateModX(xDest + w - 1);
-+ updateModY(yDest);
-+ updateModY(yDest + h - 1);
-+ } else {
-+ for (y = 0; y < h; ++y) {
-+ pipeSetXY(&pipe, xDest, yDest + y);
-+ for (x = 0; x < w; ++x) {
-+ src->getPixel(xSrc + x, ySrc + y, pixel);
-+ if (state->clip->test(xDest + x, yDest + y)) {
-+ (this->*pipe.run)(&pipe);
-+ updateModX(xDest + x);
-+ updateModY(yDest + y);
-+ } else {
-+ pipeIncX(&pipe);
-+ }
- }
- }
- }
-@@ -2826,7 +4412,10 @@
- void Splash::compositeBackground(SplashColorPtr color) {
- SplashColorPtr p;
- Guchar *q;
-- Guchar alpha, alpha1, c, color0, color1, color2, color3;
-+ Guchar alpha, alpha1, c, color0, color1, color2;
-+#if SPLASH_CMYK
-+ Guchar color3;
-+#endif
- int x, y, mask;
-
- switch (bitmap->mode) {
-@@ -2911,10 +4500,8 @@
-
- SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
- int xDest, int yDest, int w, int h) {
-- SplashColor pixel;
-- SplashColorPtr p;
-- Guchar *q;
-- int x, y, mask;
-+ SplashColorPtr p, q;
-+ int x, y, mask, srcMask;
-
- if (src->mode != bitmap->mode) {
- return splashErrModeMismatch;
-@@ -2925,9 +4512,10 @@
- for (y = 0; y < h; ++y) {
- p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)];
- mask = 0x80 >> (xDest & 7);
-+ q = &src->data[(ySrc + y) * src->rowSize + (xSrc >> 3)];
-+ srcMask = 0x80 >> (xSrc & 7);
- for (x = 0; x < w; ++x) {
-- src->getPixel(xSrc + x, ySrc + y, pixel);
-- if (pixel[0]) {
-+ if (*q & srcMask) {
- *p |= mask;
- } else {
- *p &= ~mask;
-@@ -2936,15 +4524,19 @@
- mask = 0x80;
- ++p;
- }
-+ if (!(srcMask >>= 1)) {
-+ srcMask = 0x80;
-+ ++q;
-+ }
- }
- }
- break;
- case splashModeMono8:
- for (y = 0; y < h; ++y) {
- p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest];
-+ q = &src->data[(ySrc + y) * src->rowSize + xSrc];
- for (x = 0; x < w; ++x) {
-- src->getPixel(xSrc + x, ySrc + y, pixel);
-- *p++ = pixel[0];
-+ *p++ = *q++;
- }
- }
- break;
-@@ -2952,11 +4544,11 @@
- case splashModeBGR8:
- for (y = 0; y < h; ++y) {
- p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest];
-+ q = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc];
- for (x = 0; x < w; ++x) {
-- src->getPixel(xSrc + x, ySrc + y, pixel);
-- *p++ = pixel[0];
-- *p++ = pixel[1];
-- *p++ = pixel[2];
-+ *p++ = *q++;
-+ *p++ = *q++;
-+ *p++ = *q++;
- }
- }
- break;
-@@ -2964,12 +4556,12 @@
- case splashModeCMYK8:
- for (y = 0; y < h; ++y) {
- p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
-+ q = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc];
- for (x = 0; x < w; ++x) {
-- src->getPixel(xSrc + x, ySrc + y, pixel);
-- *p++ = pixel[0];
-- *p++ = pixel[1];
-- *p++ = pixel[2];
-- *p++ = pixel[3];
-+ *p++ = *q++;
-+ *p++ = *q++;
-+ *p++ = *q++;
-+ *p++ = *q++;
- }
- }
- break;
-diff -ru xpdf-3.02/splash/SplashFTFont.cc xpdf-3.03/splash/SplashFTFont.cc
---- xpdf-3.02/splash/SplashFTFont.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/splash/SplashFTFont.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -20,6 +20,7 @@
- #include "SplashMath.h"
- #include "SplashGlyphBitmap.h"
- #include "SplashPath.h"
-+#include "SplashFontEngine.h"
- #include "SplashFTFontEngine.h"
- #include "SplashFTFontFile.h"
- #include "SplashFTFont.h"
-@@ -157,6 +219,7 @@
- FT_Vector offset;
- FT_GlyphSlot slot;
- FT_UInt gid;
-+ FT_Int32 flags;
- int rowSize;
- Guchar *p, *q;
- int i;
-@@ -174,30 +237,39 @@
- } else {
- gid = (FT_UInt)c;
- }
- if (ff->trueType && gid < 0) {
- // skip the TrueType notdef glyph
- return gFalse;
- }
-
-- // if we have the FT2 bytecode interpreter, autohinting won't be used
--#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
-- if (FT_Load_Glyph(ff->face, gid,
-- aa ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT)) {
-+ flags = 0;
-+ if (aa) {
-+ flags |= FT_LOAD_NO_BITMAP;
-+ }
-+ if (ff->engine->flags & splashFTNoHinting) {
-+ flags |= FT_LOAD_NO_HINTING;
-+ } else if (ff->trueType) {
-+ // FT2's autohinting doesn't always work very well (especially with
-+ // font subsets), so turn it off if anti-aliasing is enabled; if
-+ // anti-aliasing is disabled, this seems to be a tossup - some fonts
-+ // look better with hinting, some without, so leave hinting on
-+ if (aa) {
-+ flags |= FT_LOAD_NO_AUTOHINT;
-+ }
-+ } else if (ff->type1) {
-+ // Type 1 fonts seem to look better with 'light' hinting mode
-+ flags |= FT_LOAD_TARGET_LIGHT;
-+ }
-+ if (FT_Load_Glyph(ff->face, gid, flags)) {
- return gFalse;
- }
--#else
-- // FT2's autohinting doesn't always work very well (especially with
-- // font subsets), so turn it off if anti-aliasing is enabled; if
-- // anti-aliasing is disabled, this seems to be a tossup - some fonts
-- // look better with hinting, some without, so leave hinting on
-- if (FT_Load_Glyph(ff->face, gid,
-- aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP
-- : FT_LOAD_DEFAULT)) {
-+ if (FT_Render_Glyph(slot, aa ? FT_RENDER_MODE_NORMAL
-+ : FT_RENDER_MODE_MONO)) {
- return gFalse;
- }
--#endif
-- if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal
-- : ft_render_mode_mono)) {
-+ if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) {
-+ // this can happen if (a) the glyph is really tiny or (b) the
-+ // metrics in the TrueType file are broken
- return gFalse;
- }
-
-@@ -258,7 +330,7 @@
- } else {
- gid = (FT_UInt)c;
- }
-- if (ff->trueType && gid == 0) {
-+ if (ff->trueType && gid < 0) {
- // skip the TrueType notdef glyph
- return NULL;
- }
-diff -ru xpdf-3.02/splash/Splash.h xpdf-3.03/splash/Splash.h
---- xpdf-3.02/splash/Splash.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/splash/Splash.h 2011-08-15 23:08:53.000000000 +0200
-@@ -43,11 +43,11 @@
- //------------------------------------------------------------------------
-
- enum SplashPipeResultColorCtrl {
-+ splashPipeResultColorNoAlphaBlendMono,
-+ splashPipeResultColorNoAlphaBlendRGB,
- #if SPLASH_CMYK
- splashPipeResultColorNoAlphaBlendCMYK,
- #endif
-- splashPipeResultColorNoAlphaBlendRGB,
-- splashPipeResultColorNoAlphaBlendMono,
- splashPipeResultColorAlphaNoBlendMono,
- splashPipeResultColorAlphaNoBlendRGB,
- #if SPLASH_CMYK
-@@ -232,17 +240,30 @@
- void setDebugMode(GBool debugModeA) { debugMode = debugModeA; }
-
- #if 1 //~tmp: turn off anti-aliasing temporarily
-- GBool getVectorAntialias() { return vectorAntialias; }
-- void setVectorAntialias(GBool vaa) { vectorAntialias = vaa; }
- void setInShading(GBool sh) { inShading = sh; }
- #endif
-
- private:
-
-@@ -283,10 +365,12 @@
- SplashBitmap *alpha0Bitmap; // for non-isolated groups, this is the
- // bitmap containing the alpha0 values
- int alpha0X, alpha0Y; // offset within alpha0Bitmap
-- SplashCoord aaGamma[splashAASize * splashAASize + 1];
-+ Guchar aaGamma[splashAASize * splashAASize + 1];
- SplashCoord minLineWidth;
-diff -ru xpdf-3.02/splash/SplashState.cc xpdf-3.03/splash/SplashState.cc
---- xpdf-3.02/splash/SplashState.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/splash/SplashState.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -50,16 +54,28 @@
- lineDashLength = 0;
- lineDashPhase = 0;
- strokeAdjust = gFalse;
-- clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias);
-+ clip = new SplashClip(0, 0, width, height, vectorAntialias);
- softMask = NULL;
- deleteSoftMask = gFalse;
- inNonIsolatedGroup = gFalse;
-@@ -80,10 +96,21 @@
- lineDashLength = 0;
- lineDashPhase = 0;
- strokeAdjust = gFalse;
-- clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias);
-+ clip = new SplashClip(0, 0, width, height, vectorAntialias);
- softMask = NULL;
- deleteSoftMask = gFalse;
- inNonIsolatedGroup = gFalse;
-diff -ru xpdf-3.02/splash/SplashXPath.cc xpdf-3.03/splash/SplashXPath.cc
---- xpdf-3.02/splash/SplashXPath.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/splash/SplashXPath.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -49,14 +52,13 @@
- // SplashXPath
- //------------------------------------------------------------------------
-
- SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
- SplashCoord flatness, GBool closeSubpaths) {
- SplashPathHint *hint;
- SplashXPathPoint *pts;
- SplashXPathAdjust *adjusts, *adjust;
- SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp;
-- SplashCoord adj0, adj1, w;
-- int ww;
-+ SplashCoord adj0, adj1;
- int curSubpath, curSubpathX, i, j;
-
- // transform the points
-@@ -98,19 +95,24 @@
- adj0 = adj1;
- adj1 = x0;
- }
-- w = adj1 - adj0;
-- ww = splashRound(w);
-- if (ww == 0) {
-- ww = 1;
-- }
- adjusts[i].x0a = adj0 - 0.01;
- adjusts[i].x0b = adj0 + 0.01;
- adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - 0.01;
- adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + 0.01;
- adjusts[i].x1a = adj1 - 0.01;
- adjusts[i].x1b = adj1 + 0.01;
-- adjusts[i].x0 = (SplashCoord)splashRound(adj0);
-- adjusts[i].x1 = adjusts[i].x0 + ww - 0.01;
-+ // rounding both edge coordinates can result in lines of
-+ // different widths (e.g., adj=10.1, adj1=11.3 --> x0=10, x1=11;
-+ // adj0=10.4, adj1=11.6 --> x0=10, x1=12), but it has the
-+ // benefit of making adjacent strokes/fills line up without any
-+ // gaps between them
-+ x0 = splashRound(adj0);
-+ x1 = splashRound(adj1);
-+ if (x1 == x0) {
-+ x1 = x1 + 1;
-+ }
-+ adjusts[i].x0 = (SplashCoord)x0;
-+ adjusts[i].x1 = (SplashCoord)x1 - 0.01;
- adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1);
- adjusts[i].firstPt = hint->firstPt;
- adjusts[i].lastPt = hint->lastPt;
-diff -ru xpdf-3.02/xpdf/Annot.cc xpdf-3.03/xpdf/Annot.cc
---- xpdf-3.02/xpdf/Annot.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/Annot.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -466,45 +496,41 @@
- // radio button
- if (ff & fieldFlagRadio) {
- //~ Acrobat doesn't draw a caption if there is no AP dict (?)
-- if (fieldLookup(field, "V", &obj1)->isName()) {
-- if (annot->lookup("AS", &obj2)->isName(obj1.getName())) {
-- if (caption) {
-- drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter,
-- gFalse, gTrue);
-- } else {
-- if (mkDict) {
-- if (mkDict->lookup("BC", &obj3)->isArray() &&
-- obj3.arrayGetLength() > 0) {
-- dx = xMax - xMin;
-- dy = yMax - yMin;
-- setColor(obj3.getArray(), gTrue, 0);
-- drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy),
-- gTrue);
-- }
-- obj3.free();
-+ if (fieldLookup(field, acroForm, "V", &obj1)
-+ ->isName(appearanceState->getCString())) {
-+ if (caption) {
-+ drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter,
-+ gFalse, gTrue);
-+ } else {
-+ if (mkDict) {
-+ if (mkDict->lookup("BC", &obj2)->isArray() &&
-+ obj2.arrayGetLength() > 0) {
-+ dx = xMax - xMin;
-+ dy = yMax - yMin;
-+ setColor(obj2.getArray(), gTrue, 0);
-+ drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy),
-+ gTrue);
- }
-+ obj2.free();
- }
- }
-- obj2.free();
- }
- obj1.free();
- // pushbutton
- } else if (ff & fieldFlagPushbutton) {
- if (caption) {
- drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter,
- gFalse, gFalse);
- }
- // checkbox
- } else {
-- // According to the PDF spec the off state must be named "Off",
-- // and the on state can be named anything, but Acrobat apparently
-- // looks for "Yes" and treats anything else as off.
-- if (fieldLookup(field, "V", &obj1)->isName("Yes")) {
-+ fieldLookup(field, acroForm, "V", &obj1);
-+ if (obj1.isName() && !obj1.isName("Off")) {
- if (!caption) {
- caption = new GString("3"); // ZapfDingbats checkmark
- }
- drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter,
- gFalse, gTrue);
- }
- obj1.free();
- }
-@@ -699,10 +729,12 @@
- // Draw the variable text or caption for a field.
- void Annot::drawText(GString *text, GString *da, GfxFontDict *fontDict,
- GBool multiline, int comb, int quadding,
- GBool txField, GBool forceZapfDingbats) {
-+ GString *text2;
- GList *daToks;
- GString *tok;
- GfxFont *font;
- double dx, dy;
- double fontSize, fontSize2, border, x, xPrev, y, w, w2, wMax;
- int tfPos, tmPos, i, j, k, c;
-
-@@ -710,6 +742,23 @@
- //~ and only replace the marked content portion of it
- //~ (this is only relevant for Tx fields)
-
-+ // check for a Unicode string
-+ //~ this currently drops all non-Latin1 characters
-+ if (text->getLength() >= 2 &&
-+ text->getChar(0) == '\xfe' && text->getChar(1) == '\xff') {
-+ text2 = new GString();
-+ for (i = 2; i+1 < text->getLength(); i += 2) {
-+ c = ((text->getChar(i) & 0xff) << 8) + (text->getChar(i+1) & 0xff);
-+ if (c <= 0xff) {
-+ text2->append((char)c);
-+ } else {
-+ text2->append('?');
-+ }
-+ }
-+ } else {
-+ text2 = text;
-+ }
-+
- // parse the default appearance string
- tfPos = tmPos = -1;
- if (da) {
-@@ -776,22 +826,39 @@
- // compute font autosize
- if (fontSize == 0) {
- for (fontSize = 20; fontSize > 1; --fontSize) {
- y = dy - 3;
- w2 = 0;
- i = 0;
-- while (i < text->getLength()) {
-- getNextLine(text, i, font, fontSize, wMax, &j, &w, &k);
-+ while (i < text2->getLength()) {
-+ getNextLine(text2, i, font, fontSize, wMax, &j, &w, &k);
- if (w > w2) {
- w2 = w;
- }
-@@ -840,9 +907,9 @@
- // write a series of lines of text
- i = 0;
- xPrev = 0;
-- while (i < text->getLength()) {
-+ while (i < text2->getLength()) {
-
-- getNextLine(text, i, font, fontSize, wMax, &j, &w, &k);
-+ getNextLine(text2, i, font, fontSize, wMax, &j, &w, &k);
-
- // compute text start position
- switch (quadding) {
-@@ -862,7 +929,7 @@
- appearBuf->appendf("{0:.2f} {1:.2f} Td\n", x - xPrev, -fontSize);
- appearBuf->append('(');
- for (; i < j; ++i) {
-- c = text->getChar(i) & 0xff;
-+ c = text2->getChar(i) & 0xff;
- if (c == '(' || c == ')' || c == '\\') {
- appearBuf->append('\\');
- appearBuf->append(c);
-@@ -910,13 +977,13 @@
- x = border + 2;
- break;
- case fieldQuadCenter:
-- x = border + 2 + 0.5 * (comb - text->getLength()) * w;
-+ x = border + 2 + 0.5 * (comb - text2->getLength()) * w;
- break;
- case fieldQuadRight:
-- x = border + 2 + (comb - text->getLength()) * w;
-+ x = border + 2 + (comb - text2->getLength()) * w;
- break;
- }
- y = 0.5 * dy - 0.4 * fontSize;
-
- // set the font matrix
- if (tmPos >= 0) {
-@@ -943,12 +1010,12 @@
- // write the text string
- //~ this should center (instead of left-justify) each character within
- //~ its comb cell
-- for (i = 0; i < text->getLength(); ++i) {
-+ for (i = 0; i < text2->getLength(); ++i) {
- if (i > 0) {
- appearBuf->appendf("{0:.2f} 0 Td\n", w);
- }
- appearBuf->append('(');
-- c = text->getChar(i) & 0xff;
-+ c = text2->getChar(i) & 0xff;
- if (c == '(' || c == ')' || c == '\\') {
- appearBuf->append('\\');
- appearBuf->append(c);
-@@ -966,18 +1033,18 @@
- // compute string width
- if (font && !font->isCIDFont()) {
- w = 0;
-- for (i = 0; i < text->getLength(); ++i) {
-- w += ((Gfx8BitFont *)font)->getWidth(text->getChar(i));
-+ for (i = 0; i < text2->getLength(); ++i) {
-+ w += ((Gfx8BitFont *)font)->getWidth(text2->getChar(i));
- }
- } else {
- // otherwise, make a crude estimate
-- w = text->getLength() * 0.5;
-+ w = text2->getLength() * 0.5;
- }
-
-@@ -1029,8 +1096,8 @@
-
- // write the text string
- appearBuf->append('(');
-- for (i = 0; i < text->getLength(); ++i) {
-- c = text->getChar(i) & 0xff;
-+ for (i = 0; i < text2->getLength(); ++i) {
-+ c = text2->getChar(i) & 0xff;
- if (c == '(' || c == ')' || c == '\\') {
- appearBuf->append('\\');
- appearBuf->append(c);
-@@ -1054,6 +1121,9 @@
- if (daToks) {
- deleteGList(daToks, GString);
- }
-+ if (text2 != text) {
-+ delete text2;
-+ }
- }
-
- // Draw the variable text or caption for a field.
-diff -ru xpdf-3.02/xpdf/Annot.h xpdf-3.03/xpdf/Annot.h
---- xpdf-3.02/xpdf/Annot.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/Annot.h 2011-08-15 23:08:53.000000000 +0200
-@@ -106,6 +117,7 @@
- xMax, yMax;
- Guint flags;
- AnnotBorderStyle *borderStyle;
-+ Object ocObj; // optional content entry
- GBool ok;
- };
-
-diff -ru xpdf-3.02/xpdf/Catalog.cc xpdf-3.03/xpdf/Catalog.cc
---- xpdf-3.02/xpdf/Catalog.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/Catalog.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -12,80 +12,111 @@
- #pragma implementation
- #endif
-
-+#include <string.h>
- #include <stddef.h>
-+#include <limits.h>
- #include "gmem.h"
-+#include "gfile.h"
-+#include "GList.h"
- #include "Object.h"
-+#include "CharTypes.h"
- #include "PDFDoc.h"
- #include "XRef.h"
- #include "Array.h"
- #include "Dict.h"
- #include "Page.h"
- #include "Error.h"
- #include "Link.h"
-+#include "PDFDocEncoding.h"
- #include "Catalog.h"
-
- //------------------------------------------------------------------------
-+// PageTreeNode
-+//------------------------------------------------------------------------
-+
-+class PageTreeNode {
-+public:
-+
-+ PageTreeNode(Ref refA, int countA, PageTreeNode *parentA);
-+ ~PageTreeNode();
-+
-+ Ref ref;
-+ int count;
-+ PageTreeNode *parent;
-+ GList *kids; // [PageTreeNode]
-+ PageAttrs *attrs;
-+};
-+
-+PageTreeNode::PageTreeNode(Ref refA, int countA, PageTreeNode *parentA) {
-+ ref = refA;
-+ count = countA;
-+ parent = parentA;
-+ kids = NULL;
-+ attrs = NULL;
-+}
-+
-+PageTreeNode::~PageTreeNode() {
-+ delete attrs;
-+ if (kids) {
-+ deleteGList(kids, PageTreeNode);
-+ }
-+}
-+
-+
-+//------------------------------------------------------------------------
- // Catalog
- //------------------------------------------------------------------------
-
- Catalog::Catalog(PDFDoc *docA) {
-- Object catDict, pagesDict, pagesDictRef;
-+ Object catDict;
- Object obj, obj2;
-- char *alreadyRead;
-- int numPages0;
-- int i;
-
- ok = gTrue;
- doc = docA;
- xref = doc->getXRef();
-+ pageTree = NULL;
- pages = NULL;
- pageRefs = NULL;
-- numPages = pagesSize = 0;
-+ numPages = 0;
- baseURI = NULL;
-
- xref->getCatalog(&catDict);
- if (!catDict.isDict()) {
-- error(errSyntaxError, -1, "Catalog object is wrong type (%s)", catDict.getTypeName());
-+ error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName());
- }
-
- // read page tree
-- catDict.dictLookup("Pages", &pagesDict);
-- // This should really be isDict("Pages"), but I've seen at least one
-- // PDF file where the /Type entry is missing.
-- if (!pagesDict.isDict()) {
-- error(-1, "Top-level pages object is wrong type (%s)",
-- pagesDict.getTypeName());
-- goto err2;
-- }
-- pagesDict.dictLookup("Count", &obj);
-- // some PDF files actually use real numbers here ("/Count 9.0")
-- if (!obj.isNum()) {
-- error(-1, "Page count in top-level pages object is wrong type (%s)",
-- obj.getTypeName());
-- goto err3;
-- }
-- pagesSize = numPages0 = (int)obj.getNum();
-- obj.free();
-- pages = (Page **)gmallocn(pagesSize, sizeof(Page *));
-- pageRefs = (Ref *)gmallocn(pagesSize, sizeof(Ref));
-- for (i = 0; i < pagesSize; ++i) {
-- pages[i] = NULL;
-- pageRefs[i].num = -1;
-- pageRefs[i].gen = -1;
-- }
-- alreadyRead = (char *)gmalloc(xref->getNumObjects());
-- memset(alreadyRead, 0, xref->getNumObjects());
-- if (catDict.dictLookupNF("Pages", &pagesDictRef)->isRef() &&
-- pagesDictRef.getRefNum() >= 0 &&
-- pagesDictRef.getRefNum() < xref->getNumObjects()) {
-- alreadyRead[pagesDictRef.getRefNum()] = 1;
-- }
-- pagesDictRef.free();
-- numPages = readPageTree(pagesDict.getDict(), NULL, 0, alreadyRead);
-- gfree(alreadyRead);
-- if (numPages != numPages0) {
-- error(-1, "Page count in top-level pages object is incorrect");
-+ if (!readPageTree(&catDict)) {
-+ goto err1;
- }
-- pagesDict.free();
-
- // read named destination dictionary
- catDict.dictLookup("Dests", &dests);
-@@ -105,6 +137,21 @@
- obj2.free();
- }
- obj.free();
-+ if (!baseURI || baseURI->getLength() == 0) {
-+ if (baseURI) {
-+ delete baseURI;
-+ }
-+ if (doc->getFileName()) {
-+ baseURI = makePathAbsolute(grabPath(doc->getFileName()->getCString()));
-+ if (baseURI->getChar(0) == '/') {
-+ baseURI->insert(0, "file://localhost");
-+ } else {
-+ baseURI->insert(0, "file://localhost/");
-+ }
-+ } else {
-+ baseURI = new GString("file://localhost/");
-+ }
-+ }
-
- // get the metadata stream
- catDict.dictLookup("Metadata", &metadata);
-@@ -118,13 +165,15 @@
- // get the AcroForm dictionary
- catDict.dictLookup("AcroForm", &acroForm);
-
-+ // get the OCProperties dictionary
-+ catDict.dictLookup("OCProperties", &ocProperties);
-+
- catDict.free();
- return;
-
-- err3:
-- obj.free();
-- err2:
-- pagesDict.free();
- err1:
- catDict.free();
- dests.initNull();
-@@ -135,8 +184,11 @@
- Catalog::~Catalog() {
- int i;
-
-+ if (pageTree) {
-+ delete pageTree;
-+ }
- if (pages) {
-- for (i = 0; i < pagesSize; ++i) {
-+ for (i = 0; i < numPages; ++i) {
- if (pages[i]) {
- delete pages[i];
- }
-@@ -153,6 +205,31 @@
- structTreeRoot.free();
- outline.free();
- acroForm.free();
-+ ocProperties.free();
-+}
-+
-+Page *Catalog::getPage(int i) {
-+ if (!pages[i-1]) {
-+ loadPage(i);
-+ }
-+ return pages[i-1];
-+}
-+
-+Ref *Catalog::getPageRef(int i) {
-+ if (!pages[i-1]) {
-+ loadPage(i);
-+ }
-+ return &pageRefs[i-1];
-+}
-+
-+void Catalog::doneWithPage(int i) {
-+ if (pages[i-1]) {
-+ delete pages[i-1];
-+ pages[i-1] = NULL;
-+ }
- }
-
- GString *Catalog::readMetadata() {
-@@ -179,90 +256,13 @@
- return s;
- }
-
--int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start,
-- char *alreadyRead) {
-- Object kids;
-- Object kid;
-- Object kidRef;
-- PageAttrs *attrs1, *attrs2;
-- Page *page;
-- int i, j;
--
-- attrs1 = new PageAttrs(attrs, pagesDict);
-- pagesDict->lookup("Kids", &kids);
-- if (!kids.isArray()) {
-- error(-1, "Kids object (page %d) is wrong type (%s)",
-- start+1, kids.getTypeName());
-- goto err1;
-- }
-- for (i = 0; i < kids.arrayGetLength(); ++i) {
-- kids.arrayGetNF(i, &kidRef);
-- if (kidRef.isRef() &&
-- kidRef.getRefNum() >= 0 &&
-- kidRef.getRefNum() < xref->getNumObjects()) {
-- if (alreadyRead[kidRef.getRefNum()]) {
-- error(-1, "Loop in Pages tree");
-- kidRef.free();
-- continue;
-- }
-- alreadyRead[kidRef.getRefNum()] = 1;
-- }
-- kids.arrayGet(i, &kid);
-- if (kid.isDict("Page")) {
-- attrs2 = new PageAttrs(attrs1, kid.getDict());
-- page = new Page(xref, start+1, kid.getDict(), attrs2);
-- if (!page->isOk()) {
-- ++start;
-- goto err3;
-- }
-- if (start >= pagesSize) {
-- pagesSize += 32;
-- pages = (Page **)greallocn(pages, pagesSize, sizeof(Page *));
-- pageRefs = (Ref *)greallocn(pageRefs, pagesSize, sizeof(Ref));
-- for (j = pagesSize - 32; j < pagesSize; ++j) {
-- pages[j] = NULL;
-- pageRefs[j].num = -1;
-- pageRefs[j].gen = -1;
-- }
-- }
-- pages[start] = page;
-- if (kidRef.isRef()) {
-- pageRefs[start].num = kidRef.getRefNum();
-- pageRefs[start].gen = kidRef.getRefGen();
-- }
-- ++start;
-- // This should really be isDict("Pages"), but I've seen at least one
-- // PDF file where the /Type entry is missing.
-- } else if (kid.isDict()) {
-- if ((start = readPageTree(kid.getDict(), attrs1, start, alreadyRead))
-- < 0)
-- goto err2;
-- } else {
-- error(-1, "Kid object (page %d) is wrong type (%s)",
-- start+1, kid.getTypeName());
-- }
-- kid.free();
-- kidRef.free();
-- }
-- delete attrs1;
-- kids.free();
-- return start;
--
-- err3:
-- delete page;
-- err2:
-- kid.free();
-- err1:
-- kids.free();
-- delete attrs1;
-- ok = gFalse;
-- return -1;
--}
--
- int Catalog::findPage(int num, int gen) {
- int i;
-
- for (i = 0; i < numPages; ++i) {
-+ if (!pages[i]) {
-+ loadPage(i+1);
-+ }
- if (pageRefs[i].num == num && pageRefs[i].gen == gen)
- return i + 1;
- }
-@@ -372,3 +372,367 @@
-
- return obj;
- }
-+
-+GBool Catalog::readPageTree(Object *catDict) {
-+ Object topPagesRef, topPagesObj, countObj;
-+ int i;
-+
-+ if (!catDict->dictLookupNF("Pages", &topPagesRef)->isRef()) {
-+ error(errSyntaxError, -1, "Top-level pages reference is wrong type ({0:s})",
-+ topPagesRef.getTypeName());
-+ topPagesRef.free();
-+ return gFalse;
-+ }
-+ if (!topPagesRef.fetch(xref, &topPagesObj)->isDict()) {
-+ error(errSyntaxError, -1, "Top-level pages object is wrong type ({0:s})",
-+ topPagesObj.getTypeName());
-+ topPagesObj.free();
-+ topPagesRef.free();
-+ return gFalse;
-+ }
-+ if (topPagesObj.dictLookup("Count", &countObj)->isInt()) {
-+ numPages = countObj.getInt();
-+ if (numPages == 0) {
-+ // Acrobat apparently scans the page tree if it sees a zero count
-+ numPages = countPageTree(&topPagesObj);
-+ }
-+ } else {
-+ // assume we got a Page node instead of a Pages node
-+ numPages = 1;
-+ }
-+ countObj.free();
-+ if (numPages < 0) {
-+ error(errSyntaxError, -1, "Invalid page count");
-+ topPagesObj.free();
-+ topPagesRef.free();
-+ numPages = 0;
-+ return gFalse;
-+ }
-+ pageTree = new PageTreeNode(topPagesRef.getRef(), numPages, NULL);
-+ topPagesObj.free();
-+ topPagesRef.free();
-+ pages = (Page **)greallocn(pages, numPages, sizeof(Page *));
-+ pageRefs = (Ref *)greallocn(pageRefs, numPages, sizeof(Ref));
-+ for (i = 0; i < numPages; ++i) {
-+ pages[i] = NULL;
-+ pageRefs[i].num = -1;
-+ pageRefs[i].gen = -1;
-+ }
-+ return gTrue;
-+}
-+
-+int Catalog::countPageTree(Object *pagesObj) {
-+ Object kids, kid;
-+ int n, n2, i;
-+
-+ if (!pagesObj->isDict()) {
-+ return 0;
-+ }
-+ if (pagesObj->dictLookup("Kids", &kids)->isArray()) {
-+ n = 0;
-+ for (i = 0; i < kids.arrayGetLength(); ++i) {
-+ kids.arrayGet(i, &kid);
-+ n2 = countPageTree(&kid);
-+ if (n2 < INT_MAX - n) {
-+ n += n2;
-+ } else {
-+ error(errSyntaxError, -1, "Page tree contains too many pages");
-+ n = INT_MAX;
-+ }
-+ kid.free();
-+ }
-+ } else {
-+ n = 1;
-+ }
-+ kids.free();
-+ return n;
-+}
-+
-+void Catalog::loadPage(int pg) {
-+ loadPage2(pg, pg - 1, pageTree);
-+}
-+
-+void Catalog::loadPage2(int pg, int relPg, PageTreeNode *node) {
-+ Object pageRefObj, pageObj, kidsObj, kidRefObj, kidObj, countObj;
-+ PageTreeNode *kidNode, *p;
-+ PageAttrs *attrs;
-+ int count, i;
-+
-+ if (relPg >= node->count) {
-+ error(errSyntaxError, -1, "Internal error in page tree");
-+ pages[pg-1] = new Page(doc, pg);
-+ return;
-+ }
-+
-+ // if this node has not been filled in yet, it's either a leaf node
-+ // or an unread internal node
-+ if (!node->kids) {
-+
-+ // check for a loop in the page tree
-+ for (p = node->parent; p; p = p->parent) {
-+ if (node->ref.num == p->ref.num && node->ref.gen == p->ref.gen) {
-+ error(errSyntaxError, -1, "Loop in Pages tree");
-+ pages[pg-1] = new Page(doc, pg);
-+ return;
-+ }
-+ }
-+
-+ // fetch the Page/Pages object
-+ pageRefObj.initRef(node->ref.num, node->ref.gen);
-+ if (!pageRefObj.fetch(xref, &pageObj)->isDict()) {
-+ error(errSyntaxError, -1, "Page tree object is wrong type ({0:s})",
-+ pageObj.getTypeName());
-+ pageObj.free();
-+ pageRefObj.free();
-+ pages[pg-1] = new Page(doc, pg);
-+ return;
-+ }
-+
-+ // merge the PageAttrs
-+ attrs = new PageAttrs(node->parent ? node->parent->attrs
-+ : (PageAttrs *)NULL,
-+ pageObj.getDict());
-+
-+ // if "Kids" exists, it's an internal node
-+ if (pageObj.dictLookup("Kids", &kidsObj)->isArray()) {
-+
-+ // save the PageAttrs
-+ node->attrs = attrs;
-+
-+ // read the kids
-+ node->kids = new GList();
-+ for (i = 0; i < kidsObj.arrayGetLength(); ++i) {
-+ if (kidsObj.arrayGetNF(i, &kidRefObj)->isRef()) {
-+ if (kidRefObj.fetch(xref, &kidObj)->isDict()) {
-+ if (kidObj.dictLookup("Count", &countObj)->isInt()) {
-+ count = countObj.getInt();
-+ } else {
-+ count = 1;
-+ }
-+ countObj.free();
-+ node->kids->append(new PageTreeNode(kidRefObj.getRef(), count,
-+ node));
-+ } else {
-+ error(errSyntaxError, -1, "Page tree object is wrong type ({0:s})",
-+ kidObj.getTypeName());
-+ }
-+ kidObj.free();
-+ } else {
-+ error(errSyntaxError, -1,
-+ "Page tree reference is wrong type ({0:s})",
-+ kidRefObj.getTypeName());
-+ }
-+ kidRefObj.free();
-+ }
-+
-+ } else {
-+
-+ // create the Page object
-+ pageRefs[pg-1] = node->ref;
-+ pages[pg-1] = new Page(doc, pg, pageObj.getDict(), attrs);
-+ if (!pages[pg-1]->isOk()) {
-+ delete pages[pg-1];
-+ pages[pg-1] = new Page(doc, pg);
-+ }
-+
-+ }
-+
-+ kidsObj.free();
-+ pageObj.free();
-+ pageRefObj.free();
-+ }
-+
-+ // recursively descend the tree
-+ if (node->kids) {
-+ for (i = 0; i < node->kids->getLength(); ++i) {
-+ kidNode = (PageTreeNode *)node->kids->get(i);
-+ if (relPg < kidNode->count) {
-+ loadPage2(pg, relPg, kidNode);
-+ break;
-+ }
-+ relPg -= kidNode->count;
-+ }
-+
-+ // this will only happen if the page tree is invalid
-+ // (i.e., parent count > sum of children counts)
-+ if (i == node->kids->getLength()) {
-+ error(errSyntaxError, -1, "Invalid page count in page tree");
-+ pages[pg-1] = new Page(doc, pg);
-+ }
-+ }
-+}
-+
-diff -ru xpdf-3.02/xpdf/Catalog.h xpdf-3.03/xpdf/Catalog.h
---- xpdf-3.02/xpdf/Catalog.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/Catalog.h 2011-08-15 23:08:53.000000000 +0200
-@@ -15,12 +15,17 @@
- #pragma interface
- #endif
-
-+#include "CharTypes.h"
-+
-+class GList;
- class PDFDoc;
- class XRef;
- class Object;
- class Page;
- class PageAttrs;
- struct Ref;
- class LinkDest;
-+class PageTreeNode;
-
- //------------------------------------------------------------------------
- // Catalog
-@@ -42,10 +47,14 @@
- int getNumPages() { return numPages; }
-
- // Get a page.
-- Page *getPage(int i) { return pages[i-1]; }
-+ Page *getPage(int i);
-
- // Get the reference for a page object.
-- Ref *getPageRef(int i) { return &pageRefs[i-1]; }
-+ Ref *getPageRef(int i);
-+
-+ // Remove a page from the catalog. (It can be reloaded later by
-+ // calling getPage).
-+ void doneWithPage(int i);
-
- // Return base URI, or NULL if none.
- GString *getBaseURI() { return baseURI; }
-@@ -73,9 +82,19 @@
-
- Object *getAcroForm() { return &acroForm; }
-
-+ Object *getOCProperties() { return &ocProperties; }
-+
- private:
-
- PDFDoc *doc;
- XRef *xref; // the xref table for this PDF file
-+ PageTreeNode *pageTree; // the page tree
- Page **pages; // array of pages
- Ref *pageRefs; // object ID for each page
- int numPages; // number of pages
-@@ -87,11 +106,20 @@
- Object structTreeRoot; // structure tree root dictionary
- Object outline; // outline dictionary
- Object acroForm; // AcroForm dictionary
-+ Object ocProperties; // OCProperties dictionary
- GBool ok; // true if catalog is valid
-
-- int readPageTree(Dict *pages, PageAttrs *attrs, int start,
-- char *alreadyRead);
- Object *findDestInTree(Object *tree, GString *name, Object *obj);
-+ GBool readPageTree(Object *catDict);
-+ int countPageTree(Object *pagesObj);
-+ void loadPage(int pg);
-+ void loadPage2(int pg, int relPg, PageTreeNode *node);
- };
-
- #endif
-diff -ru xpdf-3.02/xpdf/Gfx.cc xpdf-3.03/xpdf/Gfx.cc
---- xpdf-3.02/xpdf/Gfx.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/Gfx.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -18,9 +18,12 @@
- #include <string.h>
- #include <math.h>
- #include "gmem.h"
-+#include "GString.h"
-+#include "GList.h"
- #include "GlobalParams.h"
- #include "CharTypes.h"
- #include "Object.h"
- #include "PDFDoc.h"
- #include "Array.h"
- #include "Dict.h"
- #include "Stream.h"
-@@ -31,7 +34,9 @@
- #include "OutputDev.h"
- #include "Page.h"
- #include "Annot.h"
-+#include "OptionalContent.h"
- #include "Error.h"
-+#include "PDFDocEncoding.h"
- #include "Gfx.h"
-
- // the MSVC math.h doesn't define this
-@@ -461,6 +487,10 @@
- baseMatrix[i] = state->getCTM()[i];
- }
- formDepth = 0;
-+ textClipBBoxEmpty = gTrue;
-+ markedContentStack = new GList();
-+ ocState = gTrue;
-+ parser = NULL;
- abortCheckCbk = abortCheckCbkA;
- abortCheckCbkData = abortCheckCbkDataA;
-
-@@ -500,6 +531,10 @@
- baseMatrix[i] = state->getCTM()[i];
- }
- formDepth = 0;
-+ textClipBBoxEmpty = gTrue;
-+ markedContentStack = new GList();
-+ ocState = gTrue;
-+ parser = NULL;
- abortCheckCbk = abortCheckCbkA;
- abortCheckCbkData = abortCheckCbkDataA;
-
-@@ -517,18 +552,17 @@
- }
-
- Gfx::~Gfx() {
-- while (state->hasSaves()) {
-- restoreState();
-- }
- if (!subPage) {
- out->endPage();
- }
-+ while (state->hasSaves()) {
-+ restoreState();
-+ }
-+ delete state;
- while (res) {
- popResources();
- }
-- if (state) {
-- delete state;
-- }
-+ deleteGList(markedContentStack, GfxMarkedContent);
- }
-
- void Gfx::display(Object *obj, GBool topLevel) {
-@@ -562,7 +596,8 @@
- int lastAbortCheck;
-
- // scan a sequence of objects
-- updateLevel = lastAbortCheck = 0;
-+ updateLevel = 1; // make sure even empty pages trigger a call to dump()
-+ lastAbortCheck = 0;
- numArgs = 0;
- parser->getObj(&obj);
- while (!obj.isEOF()) {
-@@ -695,6 +734,7 @@
-
- a = -1;
- b = numOps;
-+ cmp = 0; // make gcc happy
- // invariant: opTab[a] < name < opTab[b]
- while (b - a > 1) {
- m = (a + b) / 2;
-@@ -801,6 +841,7 @@
-
- void Gfx::opSetExtGState(Object args[], int numArgs) {
- Object obj1, obj2, obj3, obj4, obj5;
-+ Object args2[2];
- GfxBlendMode mode;
- GBool haveFillOP;
- Function *funcs[4];
-@@ -808,9 +849,10 @@
- GBool haveBackdropColor;
- GfxColorSpace *blendingColorSpace;
- GBool alpha, isolated, knockout;
-+ double opac;
- int i;
-
- if (!res->lookupGState(args[0].getName(), &obj1)) {
- return;
- }
- if (!obj1.isDict()) {
-@@ -824,28 +867,77 @@
- printf("\n");
- }
-
-+ // parameters that are also set by individual PDF operators
-+ if (obj1.dictLookup("LW", &obj2)->isNum()) {
-+ opSetLineWidth(&obj2, 1);
-+ }
-+ obj2.free();
-+ if (obj1.dictLookup("LC", &obj2)->isInt()) {
-+ opSetLineCap(&obj2, 1);
-+ }
-+ obj2.free();
-+ if (obj1.dictLookup("LJ", &obj2)->isInt()) {
-+ opSetLineJoin(&obj2, 1);
-+ }
-+ obj2.free();
-+ if (obj1.dictLookup("ML", &obj2)->isNum()) {
-+ opSetMiterLimit(&obj2, 1);
-+ }
-+ obj2.free();
-+ if (obj1.dictLookup("D", &obj2)->isArray() &&
-+ obj2.arrayGetLength() == 2) {
-+ obj2.arrayGet(0, &args2[0]);
-+ obj2.arrayGet(1, &args2[1]);
-+ if (args2[0].isArray() && args2[1].isNum()) {
-+ opSetDash(args2, 2);
-+ }
-+ args2[0].free();
-+ 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("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);
-+ }
-+ args2[0].free();
-+ args2[1].free();
-+ }
-+ obj2.free();
-+#endif
-+ if (obj1.dictLookup("FL", &obj2)->isNum()) {
-+ opSetFlat(&obj2, 1);
-+ }
-+ obj2.free();
-+
- // transparency support: blend mode, fill/stroke opacity
- if (!obj1.dictLookup("BM", &obj2)->isNull()) {
- if (state->parseBlendMode(&obj2, &mode)) {
- state->setBlendMode(mode);
- out->updateBlendMode(state);
- } else {
- error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
- }
- }
- obj2.free();
- if (obj1.dictLookup("ca", &obj2)->isNum()) {
-- state->setFillOpacity(obj2.getNum());
-+ opac = obj2.getNum();
-+ state->setFillOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
- out->updateFillOpacity(state);
- }
- obj2.free();
- if (obj1.dictLookup("CA", &obj2)->isNum()) {
-- state->setStrokeOpacity(obj2.getNum());
-+ opac = obj2.getNum();
-+ state->setStrokeOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
- out->updateStrokeOpacity(state);
- }
- obj2.free();
-
-- // fill/stroke overprint
-+ // fill/stroke overprint, overprint mode
- if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) {
- state->setFillOverprint(obj2.getBool());
- out->updateFillOverprint(state);
-@@ -860,6 +952,11 @@
- }
- }
- obj2.free();
-+ if (obj1.dictLookup("OPM", &obj2)->isInt()) {
-+ state->setOverprintMode(obj2.getInt());
-+ out->updateOverprintMode(state);
-+ }
-+ obj2.free();
-
- // stroke adjust
- if (obj1.dictLookup("SA", &obj2)->isBool()) {
-@@ -915,13 +1012,18 @@
- obj3.free();
- funcs[0] = NULL;
- if (!obj2.dictLookup("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");
-- delete funcs[0];
-+ if (obj3.isName("Default") ||
-+ obj3.isName("Identity")) {
- funcs[0] = NULL;
-+ } else {
-+ funcs[0] = Function::parse(&obj3);
-+ if (funcs[0]->getInputSize() != 1 ||
-+ funcs[0]->getOutputSize() != 1) {
-+ error(errSyntaxError, getPos(),
-+ "Invalid transfer function in soft mask in ExtGState");
-+ delete funcs[0];
-+ funcs[0] = NULL;
-+ }
- }
- }
- obj3.free();
-@@ -1045,9 +1149,9 @@
-
- // draw it
- ++formDepth;
-- doForm1(str, resDict, m, bbox, gTrue, gTrue,
-- blendingColorSpace, isolated, knockout,
-- alpha, transferFunc, backdropColor);
-+ drawForm(str, resDict, m, bbox, gTrue, gTrue,
-+ blendingColorSpace, isolated, knockout,
-+ alpha, transferFunc, backdropColor);
- --formDepth;
-
- if (blendingColorSpace) {
-@@ -1402,14 +1512,16 @@
-
- void Gfx::opStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
-- //error(getPos(), "No path in stroke");
-+ //error(errSyntaxError, getPos(), "No path in stroke");
- return;
- }
- if (state->isPath()) {
-- if (state->getStrokeColorSpace()->getMode() == csPattern) {
-- doPatternStroke();
-- } else {
-- out->stroke(state);
-+ if (ocState) {
-+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
-+ doPatternStroke();
-+ } else {
-+ out->stroke(state);
-+ }
- }
- }
- doEndPath();
-@@ -1417,15 +1529,17 @@
-
- void Gfx::opCloseStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
-- //error(getPos(), "No path in closepath/stroke");
-+ //error(errSyntaxError, getPos(), "No path in closepath/stroke");
- return;
- }
- if (state->isPath()) {
- state->closePath();
-- if (state->getStrokeColorSpace()->getMode() == csPattern) {
-- doPatternStroke();
-- } else {
-- out->stroke(state);
-+ if (ocState) {
-+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
-+ doPatternStroke();
-+ } else {
-+ out->stroke(state);
-+ }
- }
- }
- doEndPath();
-@@ -1433,14 +1547,16 @@
-
- void Gfx::opFill(Object args[], int numArgs) {
- if (!state->isCurPt()) {
-- //error(getPos(), "No path in fill");
-+ //error(errSyntaxError, getPos(), "No path in fill");
- return;
- }
- if (state->isPath()) {
-- if (state->getFillColorSpace()->getMode() == csPattern) {
-- doPatternFill(gFalse);
-- } else {
-- out->fill(state);
-+ if (ocState) {
-+ if (state->getFillColorSpace()->getMode() == csPattern) {
-+ doPatternFill(gFalse);
-+ } else {
-+ out->fill(state);
-+ }
- }
- }
- doEndPath();
-@@ -1448,14 +1564,16 @@
-
- void Gfx::opEOFill(Object args[], int numArgs) {
- if (!state->isCurPt()) {
-- //error(getPos(), "No path in eofill");
-+ //error(errSyntaxError, getPos(), "No path in eofill");
- return;
- }
- if (state->isPath()) {
-- if (state->getFillColorSpace()->getMode() == csPattern) {
-- doPatternFill(gTrue);
-- } else {
-- out->eoFill(state);
-+ if (ocState) {
-+ if (state->getFillColorSpace()->getMode() == csPattern) {
-+ doPatternFill(gTrue);
-+ } else {
-+ out->eoFill(state);
-+ }
- }
- }
- doEndPath();
-@@ -1463,19 +1581,21 @@
-
- void Gfx::opFillStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
-- //error(getPos(), "No path in fill/stroke");
-+ //error(errSyntaxError, getPos(), "No path in fill/stroke");
- return;
- }
- if (state->isPath()) {
-- if (state->getFillColorSpace()->getMode() == csPattern) {
-- doPatternFill(gFalse);
-- } else {
-- out->fill(state);
-- }
-- if (state->getStrokeColorSpace()->getMode() == csPattern) {
-- doPatternStroke();
-- } else {
-- out->stroke(state);
-+ if (ocState) {
-+ if (state->getFillColorSpace()->getMode() == csPattern) {
-+ doPatternFill(gFalse);
-+ } else {
-+ out->fill(state);
-+ }
-+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
-+ doPatternStroke();
-+ } else {
-+ out->stroke(state);
-+ }
- }
- }
- doEndPath();
-@@ -1483,20 +1603,22 @@
-
- void Gfx::opCloseFillStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
-- //error(getPos(), "No path in closepath/fill/stroke");
-+ //error(errSyntaxError, getPos(), "No path in closepath/fill/stroke");
- return;
- }
- if (state->isPath()) {
- state->closePath();
-- if (state->getFillColorSpace()->getMode() == csPattern) {
-- doPatternFill(gFalse);
-- } else {
-- out->fill(state);
-- }
-- if (state->getStrokeColorSpace()->getMode() == csPattern) {
-- doPatternStroke();
-- } else {
-- out->stroke(state);
-+ if (ocState) {
-+ if (state->getFillColorSpace()->getMode() == csPattern) {
-+ doPatternFill(gFalse);
-+ } else {
-+ out->fill(state);
-+ }
-+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
-+ doPatternStroke();
-+ } else {
-+ out->stroke(state);
-+ }
- }
- }
- doEndPath();
-@@ -1504,19 +1626,21 @@
-
- void Gfx::opEOFillStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
-- //error(getPos(), "No path in eofill/stroke");
-+ //error(errSyntaxError, getPos(), "No path in eofill/stroke");
- return;
- }
- if (state->isPath()) {
-- if (state->getFillColorSpace()->getMode() == csPattern) {
-- doPatternFill(gTrue);
-- } else {
-- out->eoFill(state);
-- }
-- if (state->getStrokeColorSpace()->getMode() == csPattern) {
-- doPatternStroke();
-- } else {
-- out->stroke(state);
-+ if (ocState) {
-+ if (state->getFillColorSpace()->getMode() == csPattern) {
-+ doPatternFill(gTrue);
-+ } else {
-+ out->eoFill(state);
-+ }
-+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
-+ doPatternStroke();
-+ } else {
-+ out->stroke(state);
-+ }
- }
- }
- doEndPath();
-@@ -1524,20 +1648,22 @@
-
- void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
-- //error(getPos(), "No path in closepath/eofill/stroke");
-+ //error(errSyntaxError, getPos(), "No path in closepath/eofill/stroke");
- return;
- }
- if (state->isPath()) {
- state->closePath();
-- if (state->getFillColorSpace()->getMode() == csPattern) {
-- doPatternFill(gTrue);
-- } else {
-- out->eoFill(state);
-- }
-- if (state->getStrokeColorSpace()->getMode() == csPattern) {
-- doPatternStroke();
-- } else {
-- out->stroke(state);
-+ if (ocState) {
-+ if (state->getFillColorSpace()->getMode() == csPattern) {
-+ doPatternFill(gTrue);
-+ } else {
-+ out->eoFill(state);
-+ }
-+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
-+ doPatternStroke();
-+ } else {
-+ out->stroke(state);
-+ }
- }
- }
- doEndPath();
-@@ -1558,13 +1684,13 @@
- }
- switch (pattern->getType()) {
- case 1:
-- doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, eoFill);
-+ doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, eoFill, gFalse);
- break;
- case 2:
-- doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, eoFill);
-+ doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, eoFill, gFalse);
- break;
- default:
-- error(getPos(), "Unimplemented pattern type (%d) in fill",
-+ error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in fill",
- pattern->getType());
- break;
- }
-@@ -1585,23 +1711,68 @@
- }
- switch (pattern->getType()) {
- case 1:
-- doTilingPatternFill((GfxTilingPattern *)pattern, gTrue, gFalse);
-+ doTilingPatternFill((GfxTilingPattern *)pattern, gTrue, gFalse, gFalse);
-+ break;
-+ case 2:
-+ doShadingPatternFill((GfxShadingPattern *)pattern, gTrue, gFalse, gFalse);
-+ break;
-+ default:
-+ error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in stroke",
-+ pattern->getType());
-+ break;
-+ }
-+}
-+
-+void Gfx::doPatternText() {
-+ GfxPattern *pattern;
-+
-+ // this is a bit of a kludge -- patterns can be really slow, so we
-+ // skip them if we're only doing text extraction, since they almost
-+ // certainly don't contain any text
-+ if (!out->needNonText()) {
-+ return;
-+ }
-+
-+ if (!(pattern = state->getFillPattern())) {
-+ return;
-+ }
-+ switch (pattern->getType()) {
-+ case 1:
-+ doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, gFalse, gTrue);
- break;
- case 2:
-- doShadingPatternFill((GfxShadingPattern *)pattern, gTrue, gFalse);
-+ doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, gFalse, gTrue);
- break;
- default:
-- error(getPos(), "Unimplemented pattern type (%d) in stroke",
-+ error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in fill",
- pattern->getType());
- break;
- }
- }
-
-+void Gfx::doPatternImageMask(Object *ref, Stream *str, int width, int height,
-+ GBool invert, GBool inlineImg) {
-+ saveState();
-+
-+ out->setSoftMaskFromImageMask(state, ref, str,
-+ width, height, invert, inlineImg);
-+
-+ state->clearPath();
-+ state->moveTo(0, 0);
-+ state->lineTo(1, 0);
-+ state->lineTo(1, 1);
-+ state->lineTo(0, 1);
-+ state->closePath();
-+ doPatternFill(gTrue);
-+
-+ restoreState();
-+}
-+
- void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
-- GBool stroke, GBool eoFill) {
-+ GBool stroke, GBool eoFill, GBool text) {
- GfxPatternColorSpace *patCS;
- GfxColorSpace *cs;
-- GfxPath *savedPath;
-+ GfxState *savedState;
- double xMin, yMin, xMax, yMax, x, y, x1, y1;
- double cxMin, cyMin, cxMax, cyMax;
- int xi0, yi0, xi1, yi1, xi, yi;
-@@ -1652,28 +1823,27 @@
- imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det;
-
- // save current graphics state
-- savedPath = state->getPath()->copy();
-- saveState();
-+ savedState = saveStateStack();
-
- // set underlying color space (for uncolored tiling patterns); set
- // various other parameters (stroke color, line width) to match
- // Adobe's behavior
-+ state->setFillPattern(NULL);
-+ state->setStrokePattern(NULL);
- if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) {
- state->setFillColorSpace(cs->copy());
- out->updateFillColorSpace(state);
- state->setStrokeColorSpace(cs->copy());
- out->updateStrokeColorSpace(state);
- state->setStrokeColor(state->getFillColor());
-+ out->updateFillColor(state);
-+ out->updateStrokeColor(state);
- } else {
- state->setFillColorSpace(new GfxDeviceGrayColorSpace());
- out->updateFillColorSpace(state);
- state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
- out->updateStrokeColorSpace(state);
- }
-- state->setFillPattern(NULL);
-- out->updateFillColor(state);
-- state->setStrokePattern(NULL);
-- out->updateStrokeColor(state);
- if (!stroke) {
- state->setLineWidth(0);
- out->updateLineWidth(state);
-@@ -1683,7 +1853,7 @@
- if (stroke) {
- state->clipToStrokePath();
- out->clipToStrokePath(state);
-- } else {
-+ } else if (!text) {
- state->clip();
- if (eoFill) {
- out->eoClip(state);
-@@ -1754,7 +1924,7 @@
- if (out->useTilingPatternFill()) {
- m1[4] = m[4];
- m1[5] = m[5];
-- out->tilingPatternFill(state, tPat->getContentStream(),
-+ out->tilingPatternFill(state, this, tPat->getContentStream(),
- tPat->getPaintType(), tPat->getResDict(),
- m1, tPat->getBBox(),
- xi0, yi0, xi1, yi1, xstep, ystep);
-@@ -1765,22 +1935,21 @@
- y = yi * ystep;
- m1[4] = x * m[0] + y * m[2] + m[4];
- m1[5] = x * m[1] + y * m[3] + m[5];
-- doForm1(tPat->getContentStream(), tPat->getResDict(),
-- m1, tPat->getBBox());
-+ drawForm(tPat->getContentStream(), tPat->getResDict(),
-+ m1, tPat->getBBox());
- }
- }
- }
-
- // restore graphics state
- err:
-- restoreState();
-- state->setPath(savedPath);
-+ restoreStateStack(savedState);
- }
-
- void Gfx::doShadingPatternFill(GfxShadingPattern *sPat,
-- GBool stroke, GBool eoFill) {
-+ GBool stroke, GBool eoFill, GBool text) {
- GfxShading *shading;
-- GfxPath *savedPath;
-+ GfxState *savedState;
- double *ctm, *btm, *ptm;
- double m[6], ictm[6], m1[6];
- double xMin, yMin, xMax, yMax;
-@@ -1789,27 +1958,13 @@
- shading = sPat->getShading();
-
- // save current graphics state
-- savedPath = state->getPath()->copy();
-- saveState();
--
-- // clip to bbox
-- if (shading->getHasBBox()) {
-- shading->getBBox(&xMin, &yMin, &xMax, &yMax);
-- state->moveTo(xMin, yMin);
-- state->lineTo(xMax, yMin);
-- state->lineTo(xMax, yMax);
-- state->lineTo(xMin, yMax);
-- state->closePath();
-- state->clip();
-- out->clip(state);
-- state->setPath(savedPath->copy());
-- }
-+ savedState = saveStateStack();
-
- // clip to current path
- if (stroke) {
- state->clipToStrokePath();
- out->clipToStrokePath(state);
-- } else {
-+ } else if (!text) {
- state->clip();
- if (eoFill) {
- out->eoClip(state);
-@@ -1817,17 +1972,6 @@
- out->clip(state);
- }
- }
--
-- // set the color space
-- state->setFillColorSpace(shading->getColorSpace()->copy());
-- out->updateFillColorSpace(state);
--
-- // background color fill
-- if (shading->getHasBackground()) {
-- state->setFillColor(shading->getBackground());
-- out->updateFillColor(state);
-- out->fill(state);
-- }
- state->clearPath();
-
- // construct a (pattern space) -> (current space) transform matrix
-@@ -1861,11 +2005,39 @@
- state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
- out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]);
-
--#if 1 //~tmp: turn off anti-aliasing temporarily
-- GBool vaa = out->getVectorAntialias();
-- if (vaa) {
-- out->setVectorAntialias(gFalse);
-+ // clip to bbox
-+ if (shading->getHasBBox()) {
-+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
-+ state->moveTo(xMin, yMin);
-+ state->lineTo(xMax, yMin);
-+ state->lineTo(xMax, yMax);
-+ state->lineTo(xMin, yMax);
-+ state->closePath();
-+ state->clip();
-+ out->clip(state);
-+ state->clearPath();
-+ }
-+
-+ // set the color space
-+ state->setFillColorSpace(shading->getColorSpace()->copy());
-+ out->updateFillColorSpace(state);
-+
-+ // background color fill
-+ if (shading->getHasBackground()) {
-+ state->setFillColor(shading->getBackground());
-+ out->updateFillColor(state);
-+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
-+ state->moveTo(xMin, yMin);
-+ state->lineTo(xMax, yMin);
-+ state->lineTo(xMax, yMax);
-+ state->lineTo(xMin, yMax);
-+ state->closePath();
-+ out->fill(state);
-+ state->clearPath();
- }
-+
-+#if 1 //~tmp: turn off anti-aliasing temporarily
-+ out->setInShading(gTrue);
- #endif
-
- // do shading type-specific operations
-@@ -1890,28 +2062,28 @@
- }
-
- #if 1 //~tmp: turn off anti-aliasing temporarily
-- if (vaa) {
-- out->setVectorAntialias(gTrue);
-- }
-+ out->setInShading(gFalse);
- #endif
-
- // restore graphics state
-- restoreState();
-- state->setPath(savedPath);
-+ restoreStateStack(savedState);
- }
-
- void Gfx::opShFill(Object args[], int numArgs) {
- GfxShading *shading;
-- GfxPath *savedPath;
-+ GfxState *savedState;
- double xMin, yMin, xMax, yMax;
-
-+ if (!ocState) {
-+ return;
-+ }
-+
- if (!(shading = res->lookupShading(args[0].getName()))) {
- return;
- }
-
- // save current graphics state
-- savedPath = state->getPath()->copy();
-- saveState();
-+ savedState = saveStateStack();
-
- // clip to bbox
- if (shading->getHasBBox()) {
-@@ -1931,10 +2103,7 @@
- out->updateFillColorSpace(state);
-
- #if 1 //~tmp: turn off anti-aliasing temporarily
-- GBool vaa = out->getVectorAntialias();
-- if (vaa) {
-- out->setVectorAntialias(gFalse);
-- }
-+ out->setInShading(gTrue);
- #endif
-
- // do shading type-specific operations
-@@ -1959,14 +2128,11 @@
- }
-
- #if 1 //~tmp: turn off anti-aliasing temporarily
-- if (vaa) {
-- out->setVectorAntialias(gTrue);
-- }
-+ out->setInShading(gFalse);
- #endif
-
- // restore graphics state
-- restoreState();
-- state->setPath(savedPath);
-+ restoreStateStack(savedState);
-
- delete shading;
- }
-@@ -2100,16 +2266,16 @@
- double xMin, yMin, xMax, yMax;
- double x0, y0, x1, y1;
- double dx, dy, mul;
-- GBool dxZero, dyZero;
-+ GBool dxdyZero, horiz;
- double tMin, tMax, t, tx, ty;
-- double s[4], sMin, sMax, tmp;
-+ double sMin, sMax, tmp;
- double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1;
- double t0, t1, tt;
- double ta[axialMaxSplits + 1];
- int next[axialMaxSplits + 1];
- GfxColor color0, color1;
- int nComps;
-- int i, j, k, kk;
-+ int i, j, k;
-
- if (out->useShadedFills() &&
- out->axialShadedFill(state, shading)) {
-@@ -2124,9 +2290,9 @@
- shading->getCoords(&x0, &y0, &x1, &y1);
- dx = x1 - x0;
- dy = y1 - y0;
-- dxZero = fabs(dx) < 0.01;
-- dyZero = fabs(dy) < 0.01;
-- if (dxZero && dyZero) {
-+ dxdyZero = fabs(dx) < 0.01 && fabs(dy) < 0.01;
-+ horiz = fabs(dy) < fabs(dx);
-+ if (dxdyZero) {
- tMin = tMax = 0;
- } else {
- mul = 1 / (dx * dx + dy * dy);
-@@ -2170,18 +2336,16 @@
- // y(s) = ty + s * dx --> s = (y - ty) / dx
- //
- // Then look at the intersection of this line with the bounding box
-- // (xMin, yMin, xMax, yMax). In the general case, there are four
-- // intersection points:
-+ // (xMin, yMin, xMax, yMax). For -1 < |dy/dx| < 1, look at the
-+ // intersection with yMin, yMax:
- //
-- // s0 = (xMin - tx) / -dy
-- // s1 = (xMax - tx) / -dy
-- // s2 = (yMin - ty) / dx
-- // s3 = (yMax - ty) / dx
-+ // s0 = (yMin - ty) / dx
-+ // s1 = (yMax - ty) / dx
- //
-- // and we want the middle two s values.
-+ // else look at the intersection with xMin, xMax:
- //
-- // In the case where dx = 0, take s0 and s1; in the case where dy =
-- // 0, take s2 and s3.
-+ // s0 = (xMin - tx) / -dy
-+ // s1 = (xMax - tx) / -dy
- //
- // Each filled polygon is bounded by two of these line segments
- // perpdendicular to the t axis.
-@@ -2190,13 +2354,10 @@
- // difference across a region is small enough, and then the region
- // is painted with a single color.
-
-- // set up: require at least one split to avoid problems when the two
-- // ends of the t axis have the same color
-+ // set up
- nComps = shading->getColorSpace()->getNComps();
- ta[0] = tMin;
-- next[0] = axialMaxSplits / 2;
-- ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax);
-- next[axialMaxSplits / 2] = axialMaxSplits;
-+ next[0] = axialMaxSplits;
- ta[axialMaxSplits] = tMax;
-
- // compute the color at t = tMin
-@@ -2214,32 +2375,19 @@
- // bounding box
- tx = x0 + tMin * dx;
- ty = y0 + tMin * dy;
-- if (dxZero && dyZero) {
-+ if (dxdyZero) {
- sMin = sMax = 0;
-- } else if (dxZero) {
-- sMin = (xMin - tx) / -dy;
-- sMax = (xMax - tx) / -dy;
-- if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
-- } else if (dyZero) {
-- sMin = (yMin - ty) / dx;
-- sMax = (yMax - ty) / dx;
-- if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
- } else {
-- s[0] = (yMin - ty) / dx;
-- s[1] = (yMax - ty) / dx;
-- s[2] = (xMin - tx) / -dy;
-- s[3] = (xMax - tx) / -dy;
-- for (j = 0; j < 3; ++j) {
-- kk = j;
-- for (k = j + 1; k < 4; ++k) {
-- if (s[k] < s[kk]) {
-- kk = k;
-- }
-- }
-- tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
-+ if (horiz) {
-+ sMin = (yMin - ty) / dx;
-+ sMax = (yMax - ty) / dx;
-+ } else {
-+ sMin = (xMin - tx) / -dy;
-+ sMax = (xMax - tx) / -dy;
-+ }
-+ if (sMin > sMax) {
-+ tmp = sMin; sMin = sMax; sMax = tmp;
- }
-- sMin = s[1];
-- sMax = s[2];
- }
- ux0 = tx - sMin * dy;
- uy0 = ty + sMin * dx;
-@@ -2260,15 +2408,19 @@
- } else {
- tt = t0 + (t1 - t0) * ta[j];
- }
-- shading->getColor(tt, &color1);
-- for (k = 0; k < nComps; ++k) {
-- if (abs(color1.c[k] - color0.c[k]) > axialColorDelta) {
-+ // require at least two splits (to avoid problems where the
-+ // color doesn't change smoothly along the t axis)
-+ if (j - i <= axialMaxSplits / 4) {
-+ shading->getColor(tt, &color1);
-+ for (k = 0; k < nComps; ++k) {
-+ if (abs(color1.c[k] - color0.c[k]) > axialColorDelta) {
-+ break;
-+ }
-+ }
-+ if (k == nComps) {
- break;
- }
- }
-- if (k == nComps) {
-- break;
-- }
- k = (i + j) / 2;
- ta[k] = 0.5 * (ta[i] + ta[j]);
- next[i] = k;
-@@ -2286,32 +2438,19 @@
- // bounding box
- tx = x0 + ta[j] * dx;
- ty = y0 + ta[j] * dy;
-- if (dxZero && dyZero) {
-+ if (dxdyZero) {
- sMin = sMax = 0;
-- } else if (dxZero) {
-- sMin = (xMin - tx) / -dy;
-- sMax = (xMax - tx) / -dy;
-- if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
-- } else if (dyZero) {
-- sMin = (yMin - ty) / dx;
-- sMax = (yMax - ty) / dx;
-- if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
- } else {
-- s[0] = (yMin - ty) / dx;
-- s[1] = (yMax - ty) / dx;
-- s[2] = (xMin - tx) / -dy;
-- s[3] = (xMax - tx) / -dy;
-- for (j = 0; j < 3; ++j) {
-- kk = j;
-- for (k = j + 1; k < 4; ++k) {
-- if (s[k] < s[kk]) {
-- kk = k;
-- }
-- }
-- tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
-+ if (horiz) {
-+ sMin = (yMin - ty) / dx;
-+ sMax = (yMax - ty) / dx;
-+ } else {
-+ sMin = (xMin - tx) / -dy;
-+ sMax = (xMax - tx) / -dy;
-+ }
-+ if (sMin > sMax) {
-+ tmp = sMin; sMin = sMax; sMax = tmp;
- }
-- sMin = s[1];
-- sMax = s[2];
- }
- ux1 = tx - sMin * dy;
- uy1 = ty + sMin * dx;
-@@ -2348,7 +2487,10 @@
- GfxColor colorA, colorB;
- double xa, ya, xb, yb, ra, rb;
- double ta, tb, sa, sb;
-- double sz, xz, yz, sMin, sMax;
-+ double sz, sMin, sMax, h;
-+ double sLeft, sRight, sTop, sBottom, sZero, sDiag;
-+ GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero;
-+ GBool haveSMin, haveSMax;
- GBool enclosed;
- int ia, ib, k, n;
- double *ctm;
-@@ -2367,23 +2509,23 @@
-
- // Compute the point at which r(s) = 0; check for the enclosed
- // circles case; and compute the angles for the tangent lines.
-- if (x0 == x1 && y0 == y1) {
-+ h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
-+ if (h == 0) {
- enclosed = gTrue;
- theta = 0; // make gcc happy
- sz = 0; // make gcc happy
-- } else if (r0 == r1) {
-+ } else if (r1 - r0 == 0) {
- enclosed = gFalse;
- theta = 0;
- sz = 0; // make gcc happy
-+ } else if (fabs(r1 - r0) >= h) {
-+ enclosed = gTrue;
-+ theta = 0; // make gcc happy
-+ sz = 0; // make gcc happy
- } else {
-+ enclosed = gFalse;
- sz = -r0 / (r1 - r0);
-- xz = x0 + sz * (x1 - x0);
-- yz = y0 + sz * (y1 - y0);
-- enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
-- theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
-- if (r0 > r1) {
-- theta = -theta;
-- }
-+ theta = asin((r1 - r0) / h);
- }
- if (enclosed) {
- alpha = 0;
-@@ -2397,59 +2539,101 @@
- sMin = 0;
- sMax = 1;
- } else {
-- sMin = 1;
-- sMax = 0;
-- // solve for x(s) + r(s) = xMin
-- if ((x1 + r1) - (x0 + r0) != 0) {
-- sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
-- if (sa < sMin) {
-- sMin = sa;
-- } else if (sa > sMax) {
-- sMax = sa;
-- }
-- }
-- // solve for x(s) - r(s) = xMax
-- if ((x1 - r1) - (x0 - r0) != 0) {
-- sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
-- if (sa < sMin) {
-- sMin = sa;
-- } else if (sa > sMax) {
-- sMax = sa;
-- }
-- }
-- // solve for y(s) + r(s) = yMin
-- if ((y1 + r1) - (y0 + r0) != 0) {
-- sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
-- if (sa < sMin) {
-- sMin = sa;
-- } else if (sa > sMax) {
-- sMax = sa;
-- }
-- }
-- // solve for y(s) - r(s) = yMax
-- if ((y1 - r1) - (y0 - r0) != 0) {
-- sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
-- if (sa < sMin) {
-- sMin = sa;
-- } else if (sa > sMax) {
-- sMax = sa;
-- }
-- }
-- // check against sz
-- if (r0 < r1) {
-- if (sMin < sz) {
-- sMin = sz;
-- }
-- } else if (r0 > r1) {
-- if (sMax > sz) {
-- sMax = sz;
-- }
-+ // solve x(sLeft) + r(sLeft) = xMin
-+ if ((haveSLeft = fabs((x1 + r1) - (x0 + r0)) > 0.000001)) {
-+ sLeft = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
-+ } else {
-+ sLeft = 0; // make gcc happy
- }
-- // check the 'extend' flags
-- if (!shading->getExtend0() && sMin < 0) {
-+ // solve x(sRight) - r(sRight) = xMax
-+ if ((haveSRight = fabs((x1 - r1) - (x0 - r0)) > 0.000001)) {
-+ sRight = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
-+ } else {
-+ sRight = 0; // make gcc happy
-+ }
-+ // solve y(sBottom) + r(sBottom) = yMin
-+ if ((haveSBottom = fabs((y1 + r1) - (y0 + r0)) > 0.000001)) {
-+ sBottom = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
-+ } else {
-+ sBottom = 0; // make gcc happy
-+ }
-+ // solve y(sTop) - r(sTop) = yMax
-+ if ((haveSTop = fabs((y1 - r1) - (y0 - r0)) > 0.000001)) {
-+ sTop = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
-+ } else {
-+ sTop = 0; // make gcc happy
-+ }
-+ // solve r(sZero) = 0
-+ if ((haveSZero = fabs(r1 - r0) > 0.000001)) {
-+ sZero = -r0 / (r1 - r0);
-+ } else {
-+ sZero = 0; // make gcc happy
-+ }
-+ // solve r(sDiag) = sqrt((xMax-xMin)^2 + (yMax-yMin)^2)
-+ if (haveSZero) {
-+ sDiag = (sqrt((xMax - xMin) * (xMax - xMin) +
-+ (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
-+ } else {
-+ sDiag = 0; // make gcc happy
-+ }
-+ // compute sMin
-+ if (shading->getExtend0()) {
-+ sMin = 0;
-+ haveSMin = gFalse;
-+ if (x0 < x1 && haveSLeft && sLeft < 0) {
-+ sMin = sLeft;
-+ haveSMin = gTrue;
-+ } else if (x0 > x1 && haveSRight && sRight < 0) {
-+ sMin = sRight;
-+ haveSMin = gTrue;
-+ }
-+ if (y0 < y1 && haveSBottom && sBottom < 0) {
-+ if (!haveSMin || sBottom > sMin) {
-+ sMin = sBottom;
-+ haveSMin = gTrue;
-+ }
-+ } else if (y0 > y1 && haveSTop && sTop < 0) {
-+ if (!haveSMin || sTop > sMin) {
-+ sMin = sTop;
-+ haveSMin = gTrue;
-+ }
-+ }
-+ if (haveSZero && sZero < 0) {
-+ if (!haveSMin || sZero > sMin) {
-+ sMin = sZero;
-+ }
-+ }
-+ } else {
- sMin = 0;
- }
-- if (!shading->getExtend1() && sMax > 1) {
-+ // compute sMax
-+ if (shading->getExtend1()) {
-+ sMax = 1;
-+ haveSMax = gFalse;
-+ if (x1 < x0 && haveSLeft && sLeft > 1) {
-+ sMax = sLeft;
-+ haveSMax = gTrue;
-+ } else if (x1 > x0 && haveSRight && sRight > 1) {
-+ sMax = sRight;
-+ haveSMax = gTrue;
-+ }
-+ if (y1 < y0 && haveSBottom && sBottom > 1) {
-+ if (!haveSMax || sBottom < sMax) {
-+ sMax = sBottom;
-+ haveSMax = gTrue;
-+ }
-+ } else if (y1 > y0 && haveSTop && sTop > 1) {
-+ if (!haveSMax || sTop < sMax) {
-+ sMax = sTop;
-+ haveSMax = gTrue;
-+ }
-+ }
-+ if (haveSZero && sDiag > 1) {
-+ if (!haveSMax || sDiag < sMax) {
-+ sMax = sDiag;
-+ }
-+ }
-+ } else {
- sMax = 1;
- }
- }
-@@ -2922,6 +3106,7 @@
- out->updateTextMat(state);
- out->updateTextPos(state);
- fontChanged = gTrue;
-+ textClipBBoxEmpty = gTrue;
- }
-
- void Gfx::opEndText(Object args[], int numArgs) {
-@@ -3028,19 +3213,23 @@
-
- void Gfx::opShowText(Object args[], int numArgs) {
- if (!state->getFont()) {
-- error(getPos(), "No font in show");
-+ error(errSyntaxError, getPos(), "No font in show");
- return;
- }
- if (fontChanged) {
- out->updateFont(state);
- fontChanged = gFalse;
- }
-- out->beginStringOp(state);
-- doShowText(args[0].getString());
-- out->endStringOp(state);
-+ if (ocState) {
-+ out->beginStringOp(state);
-+ doShowText(args[0].getString());
-+ out->endStringOp(state);
-+ } else {
-+ doIncCharCount(args[0].getString());
-+ }
- }
-
- void Gfx::opMoveShowText(Object args[], int numArgs) {
- double tx, ty;
-
- if (!state->getFont()) {
-@@ -3055,12 +3244,16 @@
- ty = state->getLineY() - state->getLeading();
- state->textMoveTo(tx, ty);
- out->updateTextPos(state);
-- out->beginStringOp(state);
-- doShowText(args[0].getString());
-- out->endStringOp(state);
-+ if (ocState) {
-+ out->beginStringOp(state);
-+ doShowText(args[0].getString());
-+ out->endStringOp(state);
-+ } else {
-+ doIncCharCount(args[0].getString());
-+ }
- }
-
- void Gfx::opMoveSetShowText(Object args[], int numArgs) {
- double tx, ty;
-
- if (!state->getFont()) {
-@@ -3079,9 +3272,13 @@
- out->updateWordSpace(state);
- out->updateCharSpace(state);
- out->updateTextPos(state);
-- out->beginStringOp(state);
-- doShowText(args[2].getString());
-- out->endStringOp(state);
-+ if (ocState) {
-+ out->beginStringOp(state);
-+ doShowText(args[2].getString());
-+ out->endStringOp(state);
-+ } else {
-+ doIncCharCount(args[2].getString());
-+ }
- }
-
- void Gfx::opShowSpaceText(Object args[], int numArgs) {
-@@ -3091,37 +3288,48 @@
- int i;
-
- if (!state->getFont()) {
-- error(getPos(), "No font in show/space");
-+ error(errSyntaxError, getPos(), "No font in show/space");
- return;
- }
- if (fontChanged) {
- out->updateFont(state);
- fontChanged = gFalse;
- }
-- out->beginStringOp(state);
-- wMode = state->getFont()->getWMode();
-- a = args[0].getArray();
-- for (i = 0; i < a->getLength(); ++i) {
-- a->get(i, &obj);
-- if (obj.isNum()) {
-- // this uses the absolute value of the font size to match
-- // Acrobat's behavior
-- if (wMode) {
-- state->textShift(0, -obj.getNum() * 0.001 *
-- fabs(state->getFontSize()));
-+ if (ocState) {
-+ out->beginStringOp(state);
-+ wMode = state->getFont()->getWMode();
-+ a = args[0].getArray();
-+ for (i = 0; i < a->getLength(); ++i) {
-+ a->get(i, &obj);
-+ if (obj.isNum()) {
-+ if (wMode) {
-+ state->textShift(0, -obj.getNum() * 0.001 *
-+ state->getFontSize());
-+ } else {
-+ state->textShift(-obj.getNum() * 0.001 *
-+ state->getFontSize() *
-+ state->getHorizScaling(), 0);
-+ }
-+ out->updateTextShift(state, obj.getNum());
-+ } else if (obj.isString()) {
-+ doShowText(obj.getString());
- } else {
-- state->textShift(-obj.getNum() * 0.001 *
-- fabs(state->getFontSize()), 0);
-+ error(errSyntaxError, getPos(),
-+ "Element of show/space array must be number or string");
- }
-- out->updateTextShift(state, obj.getNum());
-- } else if (obj.isString()) {
-- doShowText(obj.getString());
-- } else {
-- error(getPos(), "Element of show/space array must be number or string");
-+ obj.free();
-+ }
-+ out->endStringOp(state);
-+ } else {
-+ a = args[0].getArray();
-+ for (i = 0; i < a->getLength(); ++i) {
-+ a->get(i, &obj);
-+ if (obj.isString()) {
-+ doIncCharCount(obj.getString());
-+ }
-+ obj.free();
- }
-- obj.free();
- }
-- out->endStringOp(state);
- }
-
- void Gfx::doShowText(GString *s) {
-@@ -3130,14 +3338,18 @@
- double riseX, riseY;
- CharCode code;
- Unicode u[8];
-- double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, lineX, lineY;
-+ double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, ddx, ddy;
- double originX, originY, tOriginX, tOriginY;
-+ double x0, y0, x1, y1;
- double oldCTM[6], newCTM[6];
- double *mat;
- Object charProc;
- Dict *resDict;
- Parser *oldParser;
-+ GfxState *savedState;
- char *p;
-+ int render;
-+ GBool patternFill;
- int len, n, uLen, nChars, nSpaces, i;
-
- font = state->getFont();
-@@ -3147,6 +3359,28 @@
- out->beginString(state, s);
- }
-
-+ // if we're doing a pattern fill, set up clipping
-+ render = state->getRender();
-+ if (!(render & 1) &&
-+ state->getFillColorSpace()->getMode() == csPattern) {
-+ patternFill = gTrue;
-+ saveState();
-+ // disable fill, enable clipping, leave stroke unchanged
-+ if ((render ^ (render >> 1)) & 1) {
-+ render = 5;
-+ } else {
-+ render = 7;
-+ }
-+ state->setRender(render);
-+ out->updateRender(state);
-+ } else {
-+ patternFill = gFalse;
-+ }
-+
-+ state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
-+ x0 = state->getCurX() + riseX;
-+ y0 = state->getCurY() + riseY;
-+
- // handle a Type 3 char
- if (font->getType() == fontType3 && out->interpretType3Chars()) {
- mat = state->getCTM();
-@@ -3169,11 +3403,8 @@
- newCTM[3] *= state->getFontSize();
- newCTM[0] *= state->getHorizScaling();
- newCTM[2] *= state->getHorizScaling();
-- state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
- curX = state->getCurX();
- curY = state->getCurY();
-- lineX = state->getLineX();
-- lineY = state->getLineY();
- oldParser = parser;
- p = s->getCString();
- len = s->getLength();
-@@ -3189,11 +3420,12 @@
- dy *= state->getFontSize();
- state->textTransformDelta(dx, dy, &tdx, &tdy);
- state->transform(curX + riseX, curY + riseY, &x, &y);
-- saveState();
-+ savedState = saveStateStack();
- state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
- //~ the CTM concat values here are wrong (but never used)
- out->updateCTM(state, 1, 0, 0, 1, 0, 0);
-- if (!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy,
-+ state->transformDelta(dx, dy, &ddx, &ddy);
-+ if (!out->beginType3Char(state, curX + riseX, curY + riseY, ddx, ddy,
- code, u, uLen)) {
- ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
- if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
-@@ -3210,20 +3443,16 @@
- }
- charProc.free();
- }
-- restoreState();
-- // GfxState::restore() does *not* restore the current position,
-- // so we deal with it here using (curX, curY) and (lineX, lineY)
-+ restoreStateStack(savedState);
- curX += tdx;
- curY += tdy;
- state->moveTo(curX, curY);
-- state->textSetPos(lineX, lineY);
- p += n;
- len -= n;
- }
- parser = oldParser;
-
- } else if (out->useDrawChar()) {
-- state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
- p = s->getCString();
- len = s->getLength();
- while (len > 0) {
-@@ -3294,9 +3523,52 @@
- out->endString(state);
- }
-
-+ if (patternFill) {
-+ out->saveTextPos(state);
-+ // tell the OutputDev to do the clipping
-+ out->endTextObject(state);
-+ // set up a clipping bbox so doPatternText will work -- assume
-+ // that the text bounding box does not extend past the baseline in
-+ // any direction by more than twice the font size
-+ x1 = state->getCurX() + riseX;
-+ y1 = state->getCurY() + riseY;
-+ if (x0 > x1) {
-+ x = x0; x0 = x1; x1 = x;
-+ }
-+ if (y0 > y1) {
-+ y = y0; y0 = y1; y1 = y;
-+ }
-+ state->textTransformDelta(0, state->getFontSize(), &dx, &dy);
-+ state->textTransformDelta(state->getFontSize(), 0, &dx2, &dy2);
-+ dx = fabs(dx);
-+ dx2 = fabs(dx2);
-+ if (dx2 > dx) {
-+ dx = dx2;
-+ }
-+ dy = fabs(dy);
-+ dy2 = fabs(dy2);
-+ if (dy2 > dy) {
-+ dy = dy2;
-+ }
-+ state->clipToRect(x0 - 2 * dx, y0 - 2 * dy, x1 + 2 * dx, y1 + 2 * dy);
-+ // set render mode to fill-only
-+ state->setRender(0);
-+ out->updateRender(state);
-+ doPatternText();
-+ restoreState();
-+ out->restoreTextPos(state);
-+ }
-+
- updateLevel += 10 * s->getLength();
- }
-
-+// NB: this is only called when ocState is false.
-+void Gfx::doIncCharCount(GString *s) {
-+ if (out->needCharCount()) {
-+ out->incCharCount(s->getLength());
-+ }
-+}
-+
- //------------------------------------------------------------------------
- // XObject operators
- //------------------------------------------------------------------------
-@@ -3308,8 +3580,11 @@
- Object opiDict;
- #endif
-
-+ if (!ocState && !out->needCharCount()) {
-+ return;
-+ }
- name = args[0].getName();
- if (!res->lookupXObject(name, &obj1)) {
- return;
- }
- if (!obj1.isStream()) {
-@@ -3373,7 +3650,7 @@
- GBool maskInvert;
- Stream *maskStr;
- Object obj1, obj2;
-- int i;
-+ int i, n;
-
- // get info from the stream
- bits = 0;
-@@ -3389,19 +3666,27 @@
- obj1.free();
- dict->lookup("W", &obj1);
- }
-- if (!obj1.isInt())
-+ if (!obj1.isInt()) {
- goto err2;
-+ }
- width = obj1.getInt();
- obj1.free();
-+ if (width <= 0) {
-+ goto err1;
-+ }
- dict->lookup("Height", &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup("H", &obj1);
- }
-- if (!obj1.isInt())
-+ if (!obj1.isInt()) {
- goto err2;
-+ }
- height = obj1.getInt();
- obj1.free();
-+ if (height <= 0) {
-+ goto err1;
-+ }
-
- // image or mask?
- dict->lookup("ImageMask", &obj1);
-@@ -3447,16 +3732,30 @@
- }
- if (obj1.isArray()) {
- obj1.arrayGet(0, &obj2);
-- if (obj2.isInt() && obj2.getInt() == 1)
-- invert = gTrue;
-+ invert = obj2.isNum() && obj2.getNum() == 1;
- obj2.free();
- } else if (!obj1.isNull()) {
- goto err2;
- }
- obj1.free();
-
-+ // if drawing is disabled, skip over inline image data
-+ if (!ocState) {
-+ str->reset();
-+ n = height * ((width + 7) / 8);
-+ for (i = 0; i < n; ++i) {
-+ str->getChar();
-+ }
-+ str->close();
-+
- // draw it
-- out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
-+ } else {
-+ if (state->getFillColorSpace()->getMode() == csPattern) {
-+ doPatternImageMask(ref, str, width, height, invert, inlineImg);
-+ } else {
-+ out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
-+ }
-+ }
-
- } else {
-
-@@ -3581,14 +3880,36 @@
- haveSoftMask = gTrue;
- } else if (maskObj.isArray()) {
- // color key mask
-+ haveColorKeyMask = gTrue;
- for (i = 0;
-- i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
-- ++i) {
-+ i+1 < maskObj.arrayGetLength() && i+1 < 2*gfxColorMaxComps;
-+ i += 2) {
- maskObj.arrayGet(i, &obj1);
-+ if (!obj1.isInt()) {
-+ obj1.free();
-+ haveColorKeyMask = gFalse;
-+ break;
-+ }
- maskColors[i] = obj1.getInt();
- obj1.free();
-+ if (maskColors[i] < 0 || maskColors[i] >= (1 << bits)) {
-+ haveColorKeyMask = gFalse;
-+ break;
-+ }
-+ maskObj.arrayGet(i+1, &obj1);
-+ if (!obj1.isInt()) {
-+ obj1.free();
-+ haveColorKeyMask = gFalse;
-+ break;
-+ }
-+ maskColors[i+1] = obj1.getInt();
-+ obj1.free();
-+ if (maskColors[i+1] < 0 || maskColors[i+1] >= (1 << bits) ||
-+ maskColors[i] > maskColors[i+1]) {
-+ haveColorKeyMask = gFalse;
-+ break;
-+ }
- }
-- haveColorKeyMask = gTrue;
- } else if (maskObj.isStream()) {
- // explicit mask
- if (inlineImg) {
-@@ -3633,9 +3954,7 @@
- }
- if (obj1.isArray()) {
- obj1.arrayGet(0, &obj2);
-- if (obj2.isInt() && obj2.getInt() == 1) {
-- maskInvert = gTrue;
-- }
-+ maskInvert = obj2.isNum() && obj2.getNum() == 1;
- obj2.free();
- } else if (!obj1.isNull()) {
- goto err2;
-@@ -3644,20 +3963,32 @@
- haveExplicitMask = gTrue;
- }
-
-+ // if drawing is disabled, skip over inline image data
-+ if (!ocState) {
-+ str->reset();
-+ n = height * ((width * colorMap->getNumPixelComps() *
-+ colorMap->getBits() + 7) / 8);
-+ for (i = 0; i < n; ++i) {
-+ str->getChar();
-+ }
-+ str->close();
-+
- // draw it
-- if (haveSoftMask) {
-- out->drawSoftMaskedImage(state, ref, 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);
- } else {
-- out->drawImage(state, ref, str, width, height, colorMap,
-- haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
-+ if (haveSoftMask) {
-+ out->drawSoftMaskedImage(state, ref, 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);
-+ } else {
-+ out->drawImage(state, ref, str, width, height, colorMap,
-+ haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
-+ }
- }
-- delete colorMap;
-
-+ delete colorMap;
- maskObj.free();
- smaskObj.free();
- }
-@@ -3683,11 +4014,12 @@
- double m[6], bbox[4];
- Object resObj;
- Dict *resDict;
-+ GBool oc, ocSaved;
- Object obj1, obj2, obj3;
- int i;
-
- // check for excessive recursion
- if (formDepth > 100) {
- return;
- }
-
-@@ -3697,7 +4029,20 @@
- // check form type
- dict->lookup("FormType", &obj1);
- if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
- error(errSyntaxError, getPos(), "Unknown form type");
-+ }
-+ obj1.free();
-+
-+ // check for optional content key
-+ ocSaved = ocState;
-+ dict->lookupNF("OC", &obj1);
-+ if (doc->getOptionalContent()->evalOCObject(&obj1, &oc) && !oc) {
-+ obj1.free();
-+ if (out->needCharCount()) {
-+ ocState = gFalse;
-+ } else {
-+ return;
-+ }
- }
- obj1.free();
-
-@@ -3705,7 +4050,8 @@
- dict->lookup("BBox", &bboxObj);
- if (!bboxObj.isArray()) {
- bboxObj.free();
- error(errSyntaxError, getPos(), "Bad form bounding box");
-+ ocState = ocSaved;
- return;
- }
- for (i = 0; i < 4; ++i) {
-@@ -3759,23 +4105,26 @@
-
- // draw it
- ++formDepth;
-- doForm1(str, resDict, m, bbox,
-- transpGroup, gFalse, blendingColorSpace, isolated, knockout);
-+ drawForm(str, resDict, m, bbox,
-+ transpGroup, gFalse, blendingColorSpace, isolated, knockout);
- --formDepth;
-
- if (blendingColorSpace) {
- delete blendingColorSpace;
- }
- resObj.free();
-+
-+ ocState = ocSaved;
- }
-
--void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
-- GBool transpGroup, GBool softMask,
-- GfxColorSpace *blendingColorSpace,
-- GBool isolated, GBool knockout,
-- GBool alpha, Function *transferFunc,
-- GfxColor *backdropColor) {
-+void Gfx::drawForm(Object *str, Dict *resDict, double *matrix, double *bbox,
-+ GBool transpGroup, GBool softMask,
-+ GfxColorSpace *blendingColorSpace,
-+ GBool isolated, GBool knockout,
-+ GBool alpha, Function *transferFunc,
-+ GfxColor *backdropColor) {
- Parser *oldParser;
-+ GfxState *savedState;
- double oldBaseMatrix[6];
- int i;
-
-@@ -3783,7 +4132,7 @@
- pushResources(resDict);
-
- // save current graphics state
-- saveState();
-+ savedState = saveStateStack();
-
- // kill any pre-existing path
- state->clearPath();
-@@ -3847,7 +4196,7 @@
- parser = oldParser;
-
- // restore graphics state
-- restoreState();
-+ restoreStateStack(savedState);
-
- // pop resource stack
- popResources();
-@@ -3869,6 +4218,9 @@
- Stream *str;
- int c1, c2;
-
-+ // NB: this function is run even if ocState is false -- doImage() is
-+ // responsible for skipping over the inline image data
-+
- // build dict/stream
- str = buildImageStream();
-
-@@ -3921,18 +4274,23 @@
- obj.free();
-
- // make stream
-- str = new EmbedStream(parser->getStream(), &dict, gFalse, 0);
-+ if (!(str = parser->getStream())) {
-+ error(errSyntaxError, getPos(), "Invalid inline image data");
-+ dict.free();
-+ return NULL;
-+ }
-+ str = new EmbedStream(str, &dict, gFalse, 0);
- str = str->addFilters(&dict);
-
- return str;
- }
-
- void Gfx::opImageData(Object args[], int numArgs) {
- error(errInternal, getPos(), "Got 'ID' operator");
- }
-
- void Gfx::opEndImage(Object args[], int numArgs) {
- error(errInternal, getPos(), "Got 'EI' operator");
- }
-
- //------------------------------------------------------------------------
-@@ -3967,23 +4325,88 @@
- //------------------------------------------------------------------------
-
- void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
-+ GfxMarkedContent *mc;
-+ Object obj;
-+ GBool ocStateNew;
-+ GString *s;
-+ Unicode *u;
-+ int uLen, i;
-+ GfxMarkedContentKind mcKind;
-+
- if (printCommands) {
- printf(" marked content: %s ", args[0].getName());
-- if (numArgs == 2)
-- args[2].print(stdout);
-+ if (numArgs == 2) {
-+ args[1].print(stdout);
-+ }
- printf("\n");
- fflush(stdout);
- }
-+ mcKind = gfxMCOther;
-+ if (args[0].isName("OC") && numArgs == 2 && args[1].isName() &&
-+ res->lookupPropertiesNF(args[1].getName(), &obj)) {
-+ if (doc->getOptionalContent()->evalOCObject(&obj, &ocStateNew)) {
-+ ocState = ocStateNew;
-+ }
-+ obj.free();
-+ mcKind = gfxMCOptionalContent;
- }
-
- void Gfx::opEndMarkedContent(Object args[], int numArgs) {
-+ GfxMarkedContent *mc;
-+ GfxMarkedContentKind mcKind;
-+
-+ if (markedContentStack->getLength() > 0) {
-+ mc = (GfxMarkedContent *)
-+ markedContentStack->del(markedContentStack->getLength() - 1);
-+ mcKind = mc->kind;
-+ delete mc;
-+ if (mcKind == gfxMCOptionalContent) {
-+ if (markedContentStack->getLength() > 0) {
-+ mc = (GfxMarkedContent *)
-+ markedContentStack->get(markedContentStack->getLength() - 1);
-+ ocState = mc->ocState;
-+ } else {
-+ ocState = gTrue;
-+ }
-
-
- void Gfx::opMarkPoint(Object args[], int numArgs) {
- if (printCommands) {
- printf(" mark point: %s ", args[0].getName());
- if (numArgs == 2)
-- args[2].print(stdout);
-+ args[1].print(stdout);
- printf("\n");
- fflush(stdout);
- }
-@@ -3996,45 +4419,23 @@
- dict->lookup("Resources", &resObj);
- resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
-
- // draw it
-- doForm1(str, resDict, m, bbox);
-+ drawForm(str, resDict, m, bbox);
-
- resObj.free();
- }
-@@ -4168,6 +4598,27 @@
- out->restoreState(state);
- }
-
-+// Create a new state stack, and initialize it with a copy of the
-+// current state.
-+GfxState *Gfx::saveStateStack() {
-+ GfxState *oldState;
-+
-+ out->saveState(state);
-+ oldState = state;
-+ state = state->copy(gTrue);
-+ return oldState;
-+}
-+
-+// Switch back to the previous state stack.
-+void Gfx::restoreStateStack(GfxState *oldState) {
-+ while (state->hasSaves()) {
-+ restoreState();
-+ }
-+ delete state;
-+ state = oldState;
-+ out->restoreState(state);
-+}
-+
- void Gfx::pushResources(Dict *resDict) {
- res = new GfxResources(xref, resDict, res);
- }
-diff -ru xpdf-3.02/xpdf/GfxFont.cc xpdf-3.03/xpdf/GfxFont.cc
---- xpdf-3.02/xpdf/GfxFont.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/GfxFont.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -16,6 +16,11 @@
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
-+#include <math.h>
-+#include <limits.h>
-+#if HAVE_STD_SORT
-+#include <algorithm>
-+#endif
- #include "gmem.h"
- #include "Error.h"
- #include "Object.h"
-@@ -25,6 +30,7 @@
- #include "CharCodeToUnicode.h"
- #include "FontEncodingTables.h"
- #include "BuiltinFontTables.h"
-+#include "FoFiIdentifier.h"
- #include "FoFiType1.h"
- #include "FoFiType1C.h"
- #include "FoFiTrueType.h"
-@@ -93,15 +107,66 @@
- GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) {
- GString *nameA;
-+ Ref embFontIDA;
-+ GfxFontType typeA;
- GfxFont *font;
- Object obj1;
-
-@@ -113,53 +178,235 @@
- }
- obj1.free();
-
-- // get font type
-+ // get embedded font ID and font type
-+ typeA = getFontType(xref, fontDict, &embFontIDA);
-+
-+ // create the font object
- font = NULL;
-- fontDict->lookup("Subtype", &obj1);
-- if (obj1.isName("Type1") || obj1.isName("MMType1")) {
-- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict);
-- } else if (obj1.isName("Type1C")) {
-- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict);
-- } else if (obj1.isName("Type3")) {
-- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict);
-- } else if (obj1.isName("TrueType")) {
-- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict);
-- } else if (obj1.isName("Type0")) {
-- font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict);
-+ if (typeA < fontCIDType0) {
-+ font = new Gfx8BitFont(xref, tagA, idA, nameA, typeA, embFontIDA,
-+ fontDict);
- } else {
-- error(-1, "Unknown font type: '%s'",
-- obj1.isName() ? obj1.getName() : "???");
-- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict);
-+ font = new GfxCIDFont(xref, tagA, idA, nameA, typeA, embFontIDA,
-+ fontDict);
- }
-- obj1.free();
-
- return font;
- }
-
--GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA) {
-+GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA,
-+ GfxFontType typeA, Ref embFontIDA) {
- ok = gFalse;
- tag = new GString(tagA);
- id = idA;
- name = nameA;
-+ type = typeA;
-+ embFontID = embFontIDA;
- embFontName = NULL;
-- extFontFile = NULL;
- }
-
- GfxFont::~GfxFont() {
- delete tag;
- if (name) {
- delete name;
- }
- if (embFontName) {
- delete embFontName;
- }
-- if (extFontFile) {
-- delete extFontFile;
-+}
-+
-+// This function extracts three pieces of information:
-+// 1. the "expected" font type, i.e., the font type implied by
-+// Font.Subtype, DescendantFont.Subtype, and
-+// FontDescriptor.FontFile3.Subtype
-+// 2. the embedded font object ID
-+// 3. the actual font type - determined by examining the embedded font
-+// if there is one, otherwise equal to the expected font type
-+// If the expected and actual font types don't match, a warning
-+// message is printed. The expected font type is not used for
-+// anything else.
-+GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
-+ GfxFontType t, expectedType;
-+ FoFiIdentifierType fft;
-+ Dict *fontDict2;
-+ Object subtype, fontDesc, obj1, obj2, obj3, obj4;
-+ GBool isType0, err;
-+
-+ t = fontUnknownType;
-+ embID->num = embID->gen = -1;
-+ err = gFalse;
-+
-+ fontDict->lookup("Subtype", &subtype);
-+ expectedType = fontUnknownType;
-+ isType0 = gFalse;
-+ if (subtype.isName("Type1") || subtype.isName("MMType1")) {
-+ expectedType = fontType1;
-+ } else if (subtype.isName("Type1C")) {
-+ expectedType = fontType1C;
-+ } else if (subtype.isName("Type3")) {
-+ expectedType = fontType3;
-+ } else if (subtype.isName("TrueType")) {
-+ expectedType = fontTrueType;
-+ } else if (subtype.isName("Type0")) {
-+ isType0 = gTrue;
-+ } else {
-+ error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'",
-+ subtype.isName() ? subtype.getName() : "???");
-+ }
-+ subtype.free();
-+
-+ fontDict2 = fontDict;
-+ if (fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
-+ if (obj1.arrayGetLength() == 0) {
-+ error(errSyntaxWarning, -1, "Empty DescendantFonts array in font");
-+ obj2.initNull();
-+ } else if (obj1.arrayGet(0, &obj2)->isDict()) {
-+ if (!isType0) {
-+ error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array");
-+ }
-+ fontDict2 = obj2.getDict();
-+ fontDict2->lookup("Subtype", &subtype);
-+ if (subtype.isName("CIDFontType0")) {
-+ if (isType0) {
-+ expectedType = fontCIDType0;
-+ }
-+ } else if (subtype.isName("CIDFontType2")) {
-+ if (isType0) {
-+ expectedType = fontCIDType2;
-+ }
-+ }
-+ subtype.free();
-+ }
-+ } else {
-+ obj2.initNull();
-+ }
-+
-+ if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) {
-+ if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) {
-+ *embID = obj3.getRef();
-+ if (expectedType != fontType1) {
-+ err = gTrue;
-+ }
-+ }
-+ obj3.free();
-+ if (embID->num == -1 &&
-+ fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) {
-+ *embID = obj3.getRef();
-+ if (isType0) {
-+ expectedType = fontCIDType2;
-+ } else if (expectedType != fontTrueType) {
-+ err = gTrue;
-+ }
-+ }
-+ obj3.free();
-+ if (embID->num == -1 &&
-+ fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) {
-+ *embID = obj3.getRef();
-+ if (obj3.fetch(xref, &obj4)->isStream()) {
-+ obj4.streamGetDict()->lookup("Subtype", &subtype);
-+ if (subtype.isName("Type1")) {
-+ if (expectedType != fontType1) {
-+ err = gTrue;
-+ expectedType = isType0 ? fontCIDType0 : fontType1;
-+ }
-+ } else if (subtype.isName("Type1C")) {
-+ if (expectedType == fontType1) {
-+ expectedType = fontType1C;
-+ } else if (expectedType != fontType1C) {
-+ err = gTrue;
-+ expectedType = isType0 ? fontCIDType0C : fontType1C;
-+ }
-+ } else if (subtype.isName("TrueType")) {
-+ if (expectedType != fontTrueType) {
-+ err = gTrue;
-+ expectedType = isType0 ? fontCIDType2 : fontTrueType;
-+ }
-+ } else if (subtype.isName("CIDFontType0C")) {
-+ if (expectedType == fontCIDType0) {
-+ expectedType = fontCIDType0C;
-+ } else {
-+ err = gTrue;
-+ expectedType = isType0 ? fontCIDType0C : fontType1C;
-+ }
-+ } else if (subtype.isName("OpenType")) {
-+ if (expectedType == fontTrueType) {
-+ expectedType = fontTrueTypeOT;
-+ } else if (expectedType == fontType1) {
-+ expectedType = fontType1COT;
-+ } else if (expectedType == fontCIDType0) {
-+ expectedType = fontCIDType0COT;
-+ } else if (expectedType == fontCIDType2) {
-+ expectedType = fontCIDType2OT;
-+ } else {
-+ err = gTrue;
-+ }
-+ } else {
-+ error(errSyntaxError, -1, "Unknown font type '{0:s}'",
-+ subtype.isName() ? subtype.getName() : "???");
-+ }
-+ subtype.free();
-+ }
-+ obj4.free();
-+ }
-+ obj3.free();
-+ }
-+ fontDesc.free();
-+
-+ t = fontUnknownType;
-+ if (embID->num >= 0) {
-+ obj3.initRef(embID->num, embID->gen);
-+ obj3.fetch(xref, &obj4);
-+ if (obj4.isStream()) {
-+ obj4.streamReset();
-+ fft = FoFiIdentifier::identifyStream(&readFromStream, obj4.getStream());
-+ obj4.streamClose();
-+ switch (fft) {
-+ case fofiIdType1PFA:
-+ case fofiIdType1PFB:
-+ t = fontType1;
-+ break;
-+ case fofiIdCFF8Bit:
-+ t = isType0 ? fontCIDType0C : fontType1C;
-+ break;
-+ case fofiIdCFFCID:
-+ t = fontCIDType0C;
-+ break;
-+ case fofiIdTrueType:
-+ case fofiIdTrueTypeCollection:
-+ t = isType0 ? fontCIDType2 : fontTrueType;
-+ break;
-+ case fofiIdOpenTypeCFF8Bit:
-+ t = isType0 ? fontCIDType0COT : fontType1COT;
-+ break;
-+ case fofiIdOpenTypeCFFCID:
-+ t = fontCIDType0COT;
-+ break;
-+ default:
-+ error(errSyntaxError, -1, "Embedded font file may be invalid");
-+ break;
-+ }
-+ }
-+ obj4.free();
-+ obj3.free();
-+ }
-+
-+ if (t == fontUnknownType) {
-+ t = expectedType;
- }
-+
-+ if (t != expectedType) {
-+ err = gTrue;
-+ }
-+
-+ if (err) {
-+ error(errSyntaxWarning, -1,
-+ "Mismatch between font type and embedded font file");
-+ }
-+
-+ obj2.free();
-+ obj1.free();
-+
-+ return t;
- }
-
- void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
-@@ -170,8 +417,6 @@
- // assume Times-Roman by default (for substitution purposes)
- flags = fontSerif;
-
-- embFontID.num = -1;
-- embFontID.gen = -1;
- missingWidth = 0;
-
- if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
-@@ -189,75 +434,6 @@
- }
- obj2.free();
-
-- // look for embedded font file
-- if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) {
-- embFontID = obj2.getRef();
-- if (type != fontType1) {
-- error(-1, "Mismatch between font type and embedded font file");
-- type = fontType1;
-- }
-- }
-- obj2.free();
-- if (embFontID.num == -1 &&
-- obj1.dictLookupNF("FontFile2", &obj2)->isRef()) {
-- embFontID = obj2.getRef();
-- if (type != fontTrueType && type != fontCIDType2) {
-- error(-1, "Mismatch between font type and embedded font file");
-- type = type == fontCIDType0 ? fontCIDType2 : fontTrueType;
-- }
-- }
-- obj2.free();
-- if (embFontID.num == -1 &&
-- obj1.dictLookupNF("FontFile3", &obj2)->isRef()) {
-- if (obj2.fetch(xref, &obj3)->isStream()) {
-- obj3.streamGetDict()->lookup("Subtype", &obj4);
-- if (obj4.isName("Type1")) {
-- embFontID = obj2.getRef();
-- if (type != fontType1) {
-- error(-1, "Mismatch between font type and embedded font file");
-- type = fontType1;
-- }
-- } else if (obj4.isName("Type1C")) {
-- embFontID = obj2.getRef();
-- if (type != fontType1 && type != fontType1C) {
-- error(-1, "Mismatch between font type and embedded font file");
-- }
-- type = fontType1C;
-- } else if (obj4.isName("TrueType")) {
-- embFontID = obj2.getRef();
-- if (type != fontTrueType) {
-- error(-1, "Mismatch between font type and embedded font file");
-- type = fontTrueType;
-- }
-- } else if (obj4.isName("CIDFontType0C")) {
-- embFontID = obj2.getRef();
-- if (type != fontCIDType0) {
-- error(-1, "Mismatch between font type and embedded font file");
-- }
-- type = fontCIDType0C;
-- } else if (obj4.isName("OpenType")) {
-- embFontID = obj2.getRef();
-- if (type == fontTrueType) {
-- type = fontTrueTypeOT;
-- } else if (type == fontType1) {
-- type = fontType1COT;
-- } else if (type == fontCIDType0) {
-- type = fontCIDType0COT;
-- } else if (type == fontCIDType2) {
-- type = fontCIDType2OT;
-- } else {
-- error(-1, "Mismatch between font type and embedded font file");
-- }
-- } else {
-- error(-1, "Unknown embedded font type '%s'",
-- obj4.isName() ? obj4.getName() : "???");
-- }
-- obj4.free();
-- }
-- obj3.free();
-- }
-- obj2.free();
--
- // look for MissingWidth
- obj1.dictLookup("MissingWidth", &obj2);
- if (obj2.isNum()) {
-@@ -269,8 +445,13 @@
- obj1.dictLookup("Ascent", &obj2);
- if (obj2.isNum()) {
- t = 0.001 * obj2.getNum();
-- // some broken font descriptors set ascent and descent to 0
-- if (t != 0) {
-+ // some broken font descriptors specify a negative ascent
-+ if (t < 0) {
-+ t = -t;
-+ }
-+ // some broken font descriptors set ascent and descent to 0;
-+ // others set it to ridiculous values (e.g., 32768)
-+ if (t != 0 && t < 3) {
- ascent = t;
- }
- }
-@@ -278,14 +459,14 @@
- obj1.dictLookup("Descent", &obj2);
- if (obj2.isNum()) {
- t = 0.001 * obj2.getNum();
-+ // some broken font descriptors specify a positive descent
-+ if (t > 0) {
-+ t = -t;
-+ }
- // some broken font descriptors set ascent and descent to 0
-- if (t != 0) {
-+ if (t != 0 && t > -3) {
- descent = t;
- }
-- // some broken font descriptors specify a positive descent
-- if (descent > 0) {
-- descent = -descent;
-- }
- }
- obj2.free();
-
-@@ -330,37 +511,280 @@
- return ctu;
- }
-
--void GfxFont::findExtFontFile() {
-- static char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL };
-- static char *ttExts[] = { ".ttf", NULL };
-+GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) {
-+ GfxFontLoc *fontLoc;
-+ SysFontType sysFontType;
-+ GString *path, *base14Name, *substName;
-+ PSFontParam16 *psFont16;
-+ Object refObj, embFontObj;
-+ int substIdx, fontNum;
-+ GBool embed;
-
-- if (name) {
-- if (type == fontType1) {
-- extFontFile = globalParams->findFontFile(name, type1Exts);
-- } else if (type == fontTrueType) {
-- extFontFile = globalParams->findFontFile(name, ttExts);
-+ if (type == fontType3) {
-+ return NULL;
-+ }
-+
-+ //----- embedded font
-+ if (embFontID.num >= 0) {
-+ embed = gTrue;
-+ refObj.initRef(embFontID.num, embFontID.gen);
-+ refObj.fetch(xref, &embFontObj);
-+ if (!embFontObj.isStream()) {
-+ error(errSyntaxError, -1, "Embedded font object is wrong type");
-+ embed = gFalse;
-+ }
-+ embFontObj.free();
-+ refObj.free();
-+ if (embed) {
-+ if (ps) {
-+ switch (type) {
-+ case fontType1:
-+ case fontType1C:
-+ case fontType1COT:
-+ embed = globalParams->getPSEmbedType1();
-+ break;
-+ case fontTrueType:
-+ case fontTrueTypeOT:
-+ embed = globalParams->getPSEmbedTrueType();
-+ break;
-+ case fontCIDType0C:
-+ case fontCIDType0COT:
-+ embed = globalParams->getPSEmbedCIDPostScript();
-+ break;
-+ case fontCIDType2:
-+ case fontCIDType2OT:
-+ embed = globalParams->getPSEmbedCIDTrueType();
-+ break;
-+ default:
-+ break;
-+ }
-+ }
-+ if (embed) {
-+ fontLoc = new GfxFontLoc();
-+ fontLoc->locType = gfxFontLocEmbedded;
-+ fontLoc->fontType = type;
-+ fontLoc->embFontID = embFontID;
-+ return fontLoc;
-+ }
-+ }
-+ }
-+
-+ //----- PS passthrough
-+ if (ps && !isCIDFont() && globalParams->getPSFontPassthrough()) {
-+ fontLoc = new GfxFontLoc();
-+ fontLoc->locType = gfxFontLocResident;
-+ fontLoc->fontType = fontType1;
-+ fontLoc->path = name->copy();
-+ return fontLoc;
-+ }
-+
-+ //----- PS resident Base-14 font
-+ if (ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
-+ fontLoc = new GfxFontLoc();
-+ fontLoc->locType = gfxFontLocResident;
-+ fontLoc->fontType = fontType1;
-+ fontLoc->path = new GString(((Gfx8BitFont *)this)->base14->base14Name);
-+ return fontLoc;
-+ }
-+
-+ //----- external font file (fontFile, fontDir)
-+ if ((path = globalParams->findFontFile(name))) {
-+ if ((fontLoc = getExternalFont(path, isCIDFont()))) {
-+ return fontLoc;
-+ }
-+ }
-+
-+ //----- external font file for Base-14 font
-+ if (!ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
-+ base14Name = new GString(((Gfx8BitFont *)this)->base14->base14Name);
-+ if ((path = globalParams->findFontFile(base14Name))) {
-+ if ((fontLoc = getExternalFont(path, gFalse))) {
-+ delete base14Name;
-+ return fontLoc;
-+ }
-+ }
-+ delete base14Name;
-+ }
-+
-+ //----- system font
-+ if ((path = globalParams->findSystemFontFile(name, &sysFontType,
-+ &fontNum))) {
-+ if (isCIDFont()) {
-+ if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
-+ fontLoc = new GfxFontLoc();
-+ fontLoc->locType = gfxFontLocExternal;
-+ fontLoc->fontType = fontCIDType2;
-+ fontLoc->path = path;
-+ fontLoc->fontNum = fontNum;
-+ return fontLoc;
-+ }
-+ } else {
-+ if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
-+ fontLoc = new GfxFontLoc();
-+ fontLoc->locType = gfxFontLocExternal;
-+ fontLoc->fontType = fontTrueType;
-+ fontLoc->path = path;
-+ return fontLoc;
-+ } else if (sysFontType == sysFontPFA || sysFontType == sysFontPFB) {
-+ fontLoc = new GfxFontLoc();
-+ fontLoc->locType = gfxFontLocExternal;
-+ fontLoc->fontType = fontType1;
-+ fontLoc->path = path;
-+ fontLoc->fontNum = fontNum;
-+ return fontLoc;
-+ }
-+ }
-+ delete path;
-+ }
-+
-+ if (!isCIDFont()) {
-+
-+ //----- 8-bit PS resident font
-+ if (ps) {
-+ if ((path = globalParams->getPSResidentFont(name))) {
-+ fontLoc = new GfxFontLoc();
-+ fontLoc->locType = gfxFontLocResident;
-+ fontLoc->fontType = fontType1;
-+ fontLoc->path = path;
-+ return fontLoc;
-+ }
-+ }
-+
-+ //----- 8-bit font substitution
-+ if (flags & fontFixedWidth) {
-+ substIdx = 0;
-+ } else if (flags & fontSerif) {
-+ substIdx = 8;
-+ } else {
-+ substIdx = 4;
-+ }
-+ if (isBold()) {
-+ substIdx += 2;
-+ }
-+ if (isItalic()) {
-+ substIdx += 1;
-+ }
-+ substName = new GString(base14SubstFonts[substIdx]);
-+ if (ps) {
-+ error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'",
-+ base14SubstFonts[substIdx], name);
-+ fontLoc = new GfxFontLoc();
-+ fontLoc->locType = gfxFontLocResident;
-+ fontLoc->fontType = fontType1;
-+ fontLoc->path = substName;
-+ fontLoc->substIdx = substIdx;
-+ return fontLoc;
-+ } else {
-+ path = globalParams->findFontFile(substName);
-+ delete substName;
-+ if (path) {
-+ if ((fontLoc = getExternalFont(path, gFalse))) {
-+ error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'",
-+ base14SubstFonts[substIdx], name);
-+ fontLoc->substIdx = substIdx;
-+ return fontLoc;
-+ }
-+ }
-+ }
-+
-+ // failed to find a substitute font
-+ return NULL;
-+ }
-+
-+ //----- 16-bit PS resident font
-+ if (ps && ((psFont16 = globalParams->getPSResidentFont16(
-+ name,
-+ ((GfxCIDFont *)this)->getWMode())))) {
-+ fontLoc = new GfxFontLoc();
-+ fontLoc->locType = gfxFontLocResident;
-+ fontLoc->fontType = fontCIDType0; // this is not used
-+ fontLoc->path = psFont16->psFontName->copy();
-+ fontLoc->encoding = psFont16->encoding->copy();
-+ fontLoc->wMode = psFont16->wMode;
-+ return fontLoc;
-+ }
-+ if (ps && ((psFont16 = globalParams->getPSResidentFontCC(
-+ ((GfxCIDFont *)this)->getCollection(),
-+ ((GfxCIDFont *)this)->getWMode())))) {
-+ error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
-+ psFont16->psFontName, name);
-+ fontLoc = new GfxFontLoc();
-+ fontLoc->locType = gfxFontLocResident;
-+ fontLoc->fontType = fontCIDType0; // this is not used
-+ fontLoc->path = psFont16->psFontName->copy();
-+ fontLoc->encoding = psFont16->encoding->copy();
-+ fontLoc->wMode = psFont16->wMode;
-+ return fontLoc;
-+ }
-+
-+ //----- CID font substitution
-+ if ((path = globalParams->findCCFontFile(
-+ ((GfxCIDFont *)this)->getCollection()))) {
-+ if ((fontLoc = getExternalFont(path, gTrue))) {
-+ error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
-+ fontLoc->path, name);
-+ return fontLoc;
- }
- }
-+
-+ // failed to find a substitute font
-+ return NULL;
- }
-
--char *GfxFont::readExtFontFile(int *len) {
-- FILE *f;
-- char *buf;
-+GfxFontLoc *GfxFont::locateBase14Font(GString *base14Name) {
-+ GString *path;
-
-- if (!(f = fopen(extFontFile->getCString(), "rb"))) {
-- error(-1, "External font file '%s' vanished", extFontFile->getCString());
-+ path = globalParams->findFontFile(base14Name);
-+ if (!path) {
- return NULL;
- }
-- fseek(f, 0, SEEK_END);
-- *len = (int)ftell(f);
-- fseek(f, 0, SEEK_SET);
-- buf = (char *)gmalloc(*len);
-- if ((int)fread(buf, 1, *len, f) != *len) {
-- error(-1, "Error reading external font file '%s'",
-- extFontFile->getCString());
-+ return getExternalFont(path, gFalse);
-+}
-+
-+GfxFontLoc *GfxFont::getExternalFont(GString *path, GBool cid) {
-+ FoFiIdentifierType fft;
-+ GfxFontType fontType;
-+ GfxFontLoc *fontLoc;
-+
-+ fft = FoFiIdentifier::identifyFile(path->getCString());
-+ switch (fft) {
-+ case fofiIdType1PFA:
-+ case fofiIdType1PFB:
-+ fontType = fontType1;
-+ break;
-+ case fofiIdCFF8Bit:
-+ fontType = fontType1C;
-+ break;
-+ case fofiIdCFFCID:
-+ fontType = fontCIDType0C;
-+ break;
-+ case fofiIdTrueType:
-+ case fofiIdTrueTypeCollection:
-+ fontType = cid ? fontCIDType2 : fontTrueType;
-+ break;
-+ case fofiIdOpenTypeCFF8Bit:
-+ fontType = fontType1COT;
-+ break;
-+ case fofiIdOpenTypeCFFCID:
-+ fontType = fontCIDType0COT;
-+ break;
-+ case fofiIdUnknown:
-+ case fofiIdError:
-+ default:
-+ fontType = fontUnknownType;
-+ break;
-+ }
-+ if (fontType == fontUnknownType ||
-+ (cid ? (fontType < fontCIDType0)
-+ : (fontType >= fontCIDType0))) {
-+ delete path;
-+ return NULL;
- }
-- fclose(f);
-- return buf;
-+ fontLoc = new GfxFontLoc();
-+ fontLoc->locType = gfxFontLocExternal;
-+ fontLoc->fontType = fontType;
-+ fontLoc->path = path;
-+ return fontLoc;
- }
-
- char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
-@@ -386,6 +810,10 @@
- str->reset();
- while ((c = str->getChar()) != EOF) {
- if (i == size) {
-+ if (size > INT_MAX - 4096) {
-+ error(errSyntaxError, -1, "Embedded font file is too large");
-+ break;
-+ }
- size += 4096;
- buf = (char *)grealloc(buf, size);
- }
-@@ -405,8 +833,8 @@
- //------------------------------------------------------------------------
-
- Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
-- GfxFontType typeA, Dict *fontDict):
-- GfxFont(tagA, idA, nameA)
-+ GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
-+ GfxFont(tagA, idA, nameA, typeA, embFontIDA)
- {
- GString *name2;
- BuiltinFont *builtinFont;
-@@ -428,11 +856,11 @@
- Object obj1, obj2, obj3;
- int n, i, a, b, m;
-
-- type = typeA;
- ctu = NULL;
-
- // do font name substitution for various aliases of the Base 14 font
- // names
- base14 = NULL;
- if (name) {
- name2 = name->copy();
- i = 0;
-@@ -499,9 +927,6 @@
- fontBBox[3] = 0.001 * builtinFont->bbox[3];
- }
-
-- // look for an external font file
-- findExtFontFile();
--
- // get font matrix
- fontMat[0] = fontMat[3] = 1;
- fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
-@@ -581,54 +1007,45 @@
- baseEnc = winAnsiEncoding;
- }
-
-- // check embedded or external font file for base encoding
-+ // check embedded font file for base encoding
- // (only for Type 1 fonts - trying to get an encoding out of a
- // TrueType font is a losing proposition)
- ffT1 = NULL;
- ffT1C = NULL;
- buf = NULL;
-- if (type == fontType1 && (extFontFile || embFontID.num >= 0)) {
-- if (extFontFile) {
-- ffT1 = FoFiType1::load(extFontFile->getCString());
-- } else {
-- buf = readEmbFontFile(xref, &len);
-- ffT1 = FoFiType1::make(buf, len);
-- }
-- if (ffT1) {
-- if (ffT1->getName()) {
-- if (embFontName) {
-- delete embFontName;
-+ if (type == fontType1 && embFontID.num >= 0) {
-+ if ((buf = readEmbFontFile(xref, &len))) {
-+ if ((ffT1 = FoFiType1::make(buf, len))) {
-+ if (ffT1->getName()) {
-+ if (embFontName) {
-+ delete embFontName;
-+ }
-+ embFontName = new GString(ffT1->getName());
-+ }
-+ if (!baseEnc) {
-+ baseEnc = (const char **)ffT1->getEncoding();
-+ baseEncFromFontFile = gTrue;
- }
-- embFontName = new GString(ffT1->getName());
-- }
-- if (!baseEnc) {
-- baseEnc = (const char **)ffT1->getEncoding();
-- baseEncFromFontFile = gTrue;
- }
-+ gfree(buf);
- }
-- } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) {
-- if (extFontFile) {
-- ffT1C = FoFiType1C::load(extFontFile->getCString());
-- } else {
-- buf = readEmbFontFile(xref, &len);
-- ffT1C = FoFiType1C::make(buf, len);
-- }
-- if (ffT1C) {
-- if (ffT1C->getName()) {
-- if (embFontName) {
-- delete embFontName;
-+ } else if (type == fontType1C && embFontID.num >= 0) {
-+ if ((buf = readEmbFontFile(xref, &len))) {
-+ if ((ffT1C = FoFiType1C::make(buf, len))) {
-+ if (ffT1C->getName()) {
-+ if (embFontName) {
-+ delete embFontName;
-+ }
-+ embFontName = new GString(ffT1C->getName());
-+ }
-+ if (!baseEnc) {
-+ baseEnc = (const char **)ffT1C->getEncoding();
-+ baseEncFromFontFile = gTrue;
- }
-- embFontName = new GString(ffT1C->getName());
-- }
-- if (!baseEnc) {
-- baseEnc = (const char **)ffT1C->getEncoding();
-- baseEncFromFontFile = gTrue;
- }
-+ gfree(buf);
- }
- }
-- if (buf) {
-- gfree(buf);
-- }
-
- // get default base encoding
- if (!baseEnc) {
-@@ -644,7 +1061,7 @@
-
- // copy the base encoding
- for (i = 0; i < 256; ++i) {
-- enc[i] = baseEnc[i];
-+ enc[i] = (char *)baseEnc[i];
- if ((encFree[i] = baseEncFromFontFile) && enc[i]) {
- enc[i] = copyString(baseEnc[i]);
- }
-@@ -654,11 +1071,10 @@
- // T1C->T1 conversion (since the 'seac' operator depends on having
- // the accents in the encoding), so we fill in any gaps from
- // StandardEncoding
-- if (type == fontType1C && (extFontFile || embFontID.num >= 0) &&
-- baseEncFromFontFile) {
-+ if (type == fontType1C && embFontID.num >= 0 && baseEncFromFontFile) {
- for (i = 0; i < 256; ++i) {
- if (!enc[i] && standardEncoding[i]) {
- enc[i] = (char *)standardEncoding[i];
- encFree[i] = gFalse;
- }
- }
-@@ -734,14 +1151,21 @@
- }
-
- // pass 2: try to fill in the missing chars, looking for names of
-- // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B'
-- // are any letters, 'xx' is two hex digits, and 'nn' is 2-4
-- // decimal digits
-+ // any of the following forms:
-+ // - 'xx'
-+ // - 'Axx'
-+ // - 'nn'
-+ // - 'Ann'
-+ // - 'ABnn'
-+ // - 'unixxxx' (possibly followed by garbage - some Arabic files
-+ // use 'uni0628.medi', etc.)
-+ // where 'A' and 'B' are any letters, 'xx' is two hex digits, 'xxxx'
-+ // is four hex digits, and 'nn' is 2-4 decimal digits
- if (missing && globalParams->getMapNumericCharNames()) {
- for (code = 0; code < 256; ++code) {
- if ((charName = enc[code]) && !toUnicode[code] &&
- strcmp(charName, ".notdef")) {
- n = strlen(charName);
- code2 = -1;
- if (hex && n == 3 && isalpha(charName[0]) &&
- isxdigit(charName[1]) && isxdigit(charName[2])) {
-@@ -758,8 +1182,13 @@
- } else if (n >= 4 && n <= 6 &&
- isdigit(charName[2]) && isdigit(charName[3])) {
- code2 = atoi(charName+2);
-+ } else if (n >= 7 && charName[0] == 'u' && charName[1] == 'n' &&
-+ charName[2] == 'i' &&
-+ isxdigit(charName[3]) && isxdigit(charName[4]) &&
-+ isxdigit(charName[5]) && isxdigit(charName[6])) {
-+ sscanf(charName + 3, "%x", &code2);
- }
-- if (code2 >= 0 && code2 <= 0xff) {
-+ if (code2 >= 0 && code2 <= 0xffff) {
- toUnicode[code] = (Unicode)code2;
- }
- }
-@@ -835,7 +1264,7 @@
- obj1.arrayGet(code - firstChar, &obj2);
- if (obj2.isNum()) {
- widths[code] = obj2.getNum() * mul;
-- if (widths[code] != widths[firstChar]) {
-+ if (fabs(widths[code] - widths[firstChar]) > 0.00001) {
- flags &= ~fontFixedWidth;
- }
- }
-@@ -945,9 +1374,10 @@
- // TrueType font has a Macintosh Roman cmap, use it, and
- // reverse map the char names through MacRomanEncoding to
- // get char codes.
-- // 1b. If the TrueType font has a Microsoft Unicode cmap or a
-- // non-Microsoft Unicode cmap, use it, and use the Unicode
-- // indexes, not the char codes.
-+ // 1b. If the PDF font is not symbolic or the PDF font is not
-+ // embedded, and the TrueType font has a Microsoft Unicode
-+ // cmap or a non-Microsoft Unicode cmap, use it, and use the
-+ // Unicode indexes, not the char codes.
- // 1c. If the PDF font is symbolic and the TrueType font has a
- // Microsoft Symbol cmap, use it, and use char codes
- // directly (possibly with an offset of 0xf000).
-@@ -983,7 +1413,8 @@
- if (usesMacRomanEnc && macRomanCmap >= 0) {
- cmap = macRomanCmap;
- useMacRoman = gTrue;
-- } else if (unicodeCmap >= 0) {
-+ } else if ((!(flags & fontSymbolic) || embFontID.num < 0) &&
-+ unicodeCmap >= 0) {
- cmap = unicodeCmap;
- useUnicode = gTrue;
- } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) {
-@@ -1010,6 +1441,8 @@
- if ((code = globalParams->getMacRomanCharCode(charName))) {
- map[i] = ff->mapCodeToGID(cmap, code);
- }
-+ } else {
-+ map[i] = -1;
- }
- }
-
-@@ -1020,6 +1453,8 @@
- (u = globalParams->mapNameToUnicode(charName))) ||
- (n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
- map[i] = ff->mapCodeToGID(cmap, u);
-+ } else {
-+ map[i] = -1;
- }
- }
-
-@@ -1035,8 +1470,8 @@
-
- // try the TrueType 'post' table to handle any unmapped characters
- for (i = 0; i < 256; ++i) {
-- if (!map[i] && (charName = enc[i])) {
-+ if (map[i] <= 0 && (charName = enc[i])) {
- map[i] = ff->mapNameToGID(charName);
- }
- }
-
-@@ -1077,12 +1530,11 @@
- GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
-- Dict *fontDict):
-- GfxFont(tagA, idA, nameA)
-+ GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
-+ GfxFont(tagA, idA, nameA, typeA, embFontIDA)
- {
- Dict *desFontDict;
-- GString *collection, *cMapName;
- Object desFontDictObj;
- Object obj1, obj2, obj3, obj4, obj5, obj6;
- CharCodeToUnicode *utu;
-@@ -1091,8 +1545,10 @@
- ascent = 0.95;
- descent = -0.35;
- fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
-+ collection = NULL;
- cMap = NULL;
- ctu = NULL;
-+ ctuUsesCharCode = gTrue;
- widths.defWidth = 1.0;
- widths.defHeight = -1.0;
- widths.defVY = 0.880;
-@@ -1104,52 +1560,38 @@
- cidToGIDLen = 0;
-
- // get the descendant font
-- if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
-- error(-1, "Missing DescendantFonts entry in Type 0 font");
-+ if (!fontDict->lookup("DescendantFonts", &obj1)->isArray() ||
-+ obj1.arrayGetLength() == 0) {
-+ error(errSyntaxError, -1,
-+ "Missing or empty DescendantFonts entry in Type 0 font");
- obj1.free();
-+
- goto err1;
- }
- if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) {
-- error(-1, "Bad descendant font in Type 0 font");
-- goto err3;
-+ error(errSyntaxError, -1, "Bad descendant font in Type 0 font");
-+ goto err2;
- }
- obj1.free();
- desFontDict = desFontDictObj.getDict();
-
-- // font type
-- if (!desFontDict->lookup("Subtype", &obj1)) {
-- error(-1, "Missing Subtype entry in Type 0 descendant font");
-- goto err3;
-- }
-- if (obj1.isName("CIDFontType0")) {
-- type = fontCIDType0;
-- } else if (obj1.isName("CIDFontType2")) {
-- type = fontCIDType2;
-- } else {
-- error(-1, "Unknown Type 0 descendant font type '%s'",
-- obj1.isName() ? obj1.getName() : "???");
-- goto err3;
-- }
-- obj1.free();
--
- // get info from font descriptor
- readFontDescriptor(xref, desFontDict);
-
-- // look for an external font file
-- findExtFontFile();
--
- //----- encoding info -----
-
- // char collection
- if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) {
-- error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font");
-- goto err3;
-+ error(errSyntaxError, -1,
-+ "Missing CIDSystemInfo dictionary in Type 0 descendant font");
-+ goto err2;
- }
- obj1.dictLookup("Registry", &obj2);
- obj1.dictLookup("Ordering", &obj3);
- if (!obj2.isString() || !obj3.isString()) {
-- error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
-- goto err4;
-+ error(errSyntaxError, -1,
-+ "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
-+ goto err3;
- }
- collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
- obj3.free();
-@@ -1158,19 +1600,18 @@
-
- // look for a ToUnicode CMap
- if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) {
-+ ctuUsesCharCode = gFalse;
-
-- // the "Adobe-Identity" and "Adobe-UCS" collections don't have
-- // cidToUnicode files
-- if (collection->cmp("Adobe-Identity") &&
-- collection->cmp("Adobe-UCS")) {
--
-- // look for a user-supplied .cidToUnicode file
-- if (!(ctu = globalParams->getCIDToUnicode(collection))) {
-- error(-1, "Unknown character collection '%s'",
-- collection->getCString());
-- // fall-through, assuming the Identity mapping -- this appears
-- // to match Adobe's behavior
-- }
-+ // use an identity mapping for the "Adobe-Identity" and
-+ // "Adobe-UCS" collections
-+ if (!collection->cmp("Adobe-Identity") ||
-+ !collection->cmp("Adobe-UCS")) {
-+ ctu = CharCodeToUnicode::makeIdentityMapping();
-+
-+ // look for a user-supplied .cidToUnicode file
-+ } else if (!(ctu = globalParams->getCIDToUnicode(collection))) {
-+ error(errSyntaxError, -1,
-+ "Unknown character collection '{0:t}'", collection);
- }
- }
-
-@@ -1193,43 +1634,35 @@
- }
-
- // encoding (i.e., CMap)
-- //~ need to handle a CMap stream here
-- //~ also need to deal with the UseCMap entry in the stream dict
-- if (!fontDict->lookup("Encoding", &obj1)->isName()) {
-- error(-1, "Missing or invalid Encoding entry in Type 0 font");
-- delete collection;
-- goto err3;
-+ if (fontDict->lookup("Encoding", &obj1)->isNull()) {
-+ error(errSyntaxError, -1, "Missing Encoding entry in Type 0 font");
-+ goto err2;
- }
-- cMapName = new GString(obj1.getName());
-- obj1.free();
-- if (!(cMap = globalParams->getCMap(collection, cMapName))) {
-- error(-1, "Unknown CMap '%s' for character collection '%s'",
-- cMapName->getCString(), collection->getCString());
-- delete collection;
-- delete cMapName;
-+ if (!(cMap = CMap::parse(NULL, collection, &obj1))) {
- goto err2;
- }
-- delete collection;
-- delete cMapName;
-+ obj1.free();
-
-- // CIDToGIDMap (for embedded TrueType fonts)
-- if (type == fontCIDType2) {
-+ // CIDToGIDMap
-+ // (the PDF spec only allows these for TrueType fonts, but Acrobat
-+ // apparently also allows them for OpenType CFF fonts)
-+ if (type == fontCIDType2 || type == fontCIDType0COT) {
- desFontDict->lookup("CIDToGIDMap", &obj1);
- if (obj1.isStream()) {
- cidToGIDLen = 0;
- i = 64;
-@@ -1387,17 +1830,19 @@
- ok = gTrue;
- return;
-
-- err4:
-+ err3:
- obj3.free();
- obj2.free();
-- err3:
-- obj1.free();
- err2:
-+ obj1.free();
- desFontDictObj.free();
- err1:;
- }
-
- GfxCIDFont::~GfxCIDFont() {
-+ if (collection) {
-+ delete collection;
-+ }
- if (cMap) {
- cMap->decRefCnt();
- }
-@@ -1425,12 +1871,16 @@
- return 1;
- }
-
- *code = (CharCode)(cid = cMap->getCID(s, len, &c, &n));
- if (ctu) {
-- *uLen = ctu->mapToUnicode(cid, u, uSize);
-+ *uLen = ctu->mapToUnicode(ctuUsesCharCode ? c : cid, u, uSize);
- } else {
- *uLen = 0;
- }
-+ if (!*uLen && uSize >= 1 && globalParams->getMapUnknownCharNames()) {
-+ u[0] = *code;
-+ *uLen = 1;
-+ }
-
- // horizontal
- if (cMap->getWMode() == 0) {
-diff -ru xpdf-3.02/xpdf/GfxFont.h xpdf-3.03/xpdf/GfxFont.h
---- xpdf-3.02/xpdf/GfxFont.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/GfxFont.h 2011-08-15 23:08:53.000000000 +0200
-@@ -91,7 +127,8 @@
- // Build a GfxFont object.
- static GfxFont *makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict);
-
-- GfxFont(char *tagA, Ref idA, GString *nameA);
-+ GfxFont(char *tagA, Ref idA, GString *nameA,
-+ GfxFontType typeA, Ref embFontIDA);
-
- virtual ~GfxFont();
-
-@@ -126,10 +160,6 @@
- // NULL if there is no embedded font.
- GString *getEmbeddedFontName() { return embFontName; }
-
-- // Get the name of the external font file. Returns NULL if there
-- // is no external font file.
-- GString *getExtFontFile() { return extFontFile; }
--
- // Get font descriptor flags.
- int getFlags() { return flags; }
- GBool isFixedWidth() { return flags & fontFixedWidth; }
-@@ -151,8 +181,14 @@
- // Return the writing mode (0=horizontal, 1=vertical).
- virtual int getWMode() { return 0; }
-
-- // Read an external or embedded font file into a buffer.
-- char *readExtFontFile(int *len);
-+ // Locate the font file for this font. If <ps> is true, includes PS
-+ // printer-resident fonts. Returns NULL on failure.
-+ GfxFontLoc *locateFont(XRef *xref, GBool ps);
-+
-+ // Locate a Base-14 font file for a specified font name.
-+ static GfxFontLoc *locateBase14Font(GString *base14Name);
-+
-+ // Read an embedded font file into a buffer.
- char *readEmbFontFile(XRef *xref, int *len);
-
- // Get the next char from a string <s> of <len> bytes, returning the
-@@ -167,22 +203,21 @@
-
- protected:
-
-+ static GfxFontType getFontType(XRef *xref, Dict *fontDict, Ref *embID);
- void readFontDescriptor(XRef *xref, Dict *fontDict);
- CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits,
- CharCodeToUnicode *ctu);
-- void findExtFontFile();
-+ static GfxFontLoc *getExternalFont(GString *path, GBool cid);
-
- GString *tag; // PDF font tag
- Ref id; // reference (used as unique ID)
- GString *name; // font name
- GfxFontType type; // type of font
- int flags; // font descriptor flags
- GString *embFontName; // name of embedded font
- Ref embFontID; // ref to embedded font file stream
-- GString *extFontFile; // external font file name
-- double fontMat[6]; // font matrix (Type 3 only)
-- double fontBBox[4]; // font bounding box (Type 3 only)
-+ double fontMat[6]; // font matrix
-+ double fontBBox[4]; // font bounding box
- double missingWidth; // "default" width
- double ascent; // max height above baseline
- double descent; // max depth below baseline
-@@ -197,7 +232,7 @@
- public:
-
- Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
-- GfxFontType typeA, Dict *fontDict);
-+ GfxFontType typeA, Ref embFontIDA, Dict *fontDict);
-
- virtual ~Gfx8BitFont();
-
-@@ -247,6 +283,8 @@
- double widths[256]; // character widths
- Object charProcs; // Type 3 CharProcs dictionary
- Object resources; // Type 3 Resources dictionary
-+
-+ friend class GfxFont;
- };
-
- //------------------------------------------------------------------------
-@@ -257,7 +295,7 @@
- public:
-
- GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
-- Dict *fontDict);
-+ GfxFontType typeA, Ref embFontIDA, Dict *fontDict);
-
- virtual ~GfxCIDFont();
-
-@@ -278,15 +316,18 @@
-
- private:
-
-+ GString *collection; // collection name
- CMap *cMap; // char code --> CID
-- CharCodeToUnicode *ctu; // CID --> Unicode
-+ CharCodeToUnicode *ctu; // CID/char code --> Unicode
-+ GBool ctuUsesCharCode; // true: ctu maps char code to Unicode;
-+ // false: ctu maps CID to Unicode
- GfxFontCIDWidths widths; // character widths
-diff -ru xpdf-3.02/xpdf/Gfx.h xpdf-3.03/xpdf/Gfx.h
---- xpdf-3.02/xpdf/Gfx.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/Gfx.h 2011-08-15 23:08:53.000000000 +0200
-@@ -18,6 +18,8 @@
- #include "gtypes.h"
-
- class GString;
-+class GList;
- class PDFDoc;
- class XRef;
- class Array;
- class Stream;
-@@ -141,8 +169,16 @@
- // Get the current graphics state object.
- GfxState *getState() { return state; }
-
-+ void drawForm(Object *str, Dict *resDict, double *matrix, double *bbox,
-+ GBool transpGroup = gFalse, GBool softMask = gFalse,
-+ GfxColorSpace *blendingColorSpace = NULL,
-+ GBool isolated = gFalse, GBool knockout = gFalse,
-+ GBool alpha = gFalse, Function *transferFunc = NULL,
-+ GfxColor *backdropColor = NULL);
-+
- private:
-
- PDFDoc *doc;
- XRef *xref; // the xref table for this PDF file
- OutputDev *out; // output device
- GBool subPage; // is this a sub-page object?
-@@ -157,6 +193,12 @@
- double baseMatrix[6]; // default matrix for most recent
- // page/form/pattern
- int formDepth;
-+ double textClipBBox[4]; // text clipping bounding box
-+ GBool textClipBBoxEmpty; // true if textClipBBox has not been
-+ // initialized yet
-+ GBool ocState; // true if drawing is enabled, false if
-+ // disabled
-+ GList *markedContentStack; // BMC/BDC/EMC stack [GfxMarkedContent]
-
- Parser *parser; // parser for page content stream(s)
-
-@@ -224,10 +266,13 @@
- void opCloseEOFillStroke(Object args[], int numArgs);
- void doPatternFill(GBool eoFill);
- void doPatternStroke();
-+ void doPatternText();
-+ void doPatternImageMask(Object *ref, Stream *str, int width, int height,
-+ GBool invert, GBool inlineImg);
- void doTilingPatternFill(GfxTilingPattern *tPat,
-- GBool stroke, GBool eoFill);
-+ GBool stroke, GBool eoFill, GBool text);
- void doShadingPatternFill(GfxShadingPattern *sPat,
-- GBool stroke, GBool eoFill);
-+ GBool stroke, GBool eoFill, GBool text);
- void opShFill(Object args[], int numArgs);
- void doFunctionShFill(GfxFunctionShading *shading);
- void doFunctionShFill1(GfxFunctionShading *shading,
-@@ -274,17 +319,12 @@
- void opMoveSetShowText(Object args[], int numArgs);
- void opShowSpaceText(Object args[], int numArgs);
- void doShowText(GString *s);
-+ void doIncCharCount(GString *s);
-
- // XObject operators
- void opXObject(Object args[], int numArgs);
- void doImage(Object *ref, Stream *str, GBool inlineImg);
- void doForm(Object *str);
-- void doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
-- GBool transpGroup = gFalse, GBool softMask = gFalse,
-- GfxColorSpace *blendingColorSpace = NULL,
-- GBool isolated = gFalse, GBool knockout = gFalse,
-- GBool alpha = gFalse, Function *transferFunc = NULL,
-- GfxColor *backdropColor = NULL);
-
- // in-line image operators
- void opBeginImage(Object args[], int numArgs);
-@@ -305,6 +345,8 @@
- void opEndMarkedContent(Object args[], int numArgs);
- void opMarkPoint(Object args[], int numArgs);
-
-+ GfxState *saveStateStack();
-+ void restoreStateStack(GfxState *oldState);
- void pushResources(Dict *resDict);
- void popResources();
- };
-diff -ru xpdf-3.02/xpdf/GfxState.cc xpdf-3.03/xpdf/GfxState.cc
---- xpdf-3.02/xpdf/GfxState.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/GfxState.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -819,26 +854,27 @@
- obj1.free();
- arr->get(1, &obj1);
- if (!obj1.isStream()) {
- error(errSyntaxError, -1, "Bad ICCBased color space (stream)");
- obj1.free();
- return NULL;
- }
- dict = obj1.streamGetDict();
- if (!dict->lookup("N", &obj2)->isInt()) {
- error(errSyntaxError, -1, "Bad ICCBased color space (N)");
- obj2.free();
- obj1.free();
- return NULL;
- }
- nCompsA = obj2.getInt();
- obj2.free();
-- if (nCompsA > gfxColorMaxComps) {
-- error(-1, "ICCBased color space with too many (%d > %d) components",
-- nCompsA, gfxColorMaxComps);
-- nCompsA = gfxColorMaxComps;
-+ if (nCompsA > 4) {
-+ error(errSyntaxError, -1,
-+ "ICCBased color space with too many ({0:d} > 4) components",
-+ nCompsA);
-+ nCompsA = 4;
- }
- if (dict->lookup("Alternate", &obj2)->isNull() ||
-@@ -986,8 +1025,9 @@
- for (i = 0; i <= indexHighA; ++i) {
- for (j = 0; j < n; ++j) {
- if ((x = obj1.streamGetChar()) == EOF) {
-- error(-1, "Bad Indexed color space (lookup table stream too short)");
-- goto err3;
-+ error(errSyntaxError, -1,
-+ "Bad Indexed color space (lookup table stream too short)");
-+ cs->indexHigh = indexHighA = i - 1;
- }
- cs->lookup[i*n + j] = (Guchar)x;
- }
-@@ -995,8 +1035,9 @@
- obj1.streamClose();
- } else if (obj1.isString()) {
- if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
-- error(-1, "Bad Indexed color space (lookup table string too short)");
-- goto err3;
-+ error(errSyntaxError, -1,
-+ "Bad Indexed color space (lookup table string too short)");
-+ cs->indexHigh = indexHighA = obj1.getString()->getLength() / n - 1;
- }
- s = obj1.getString()->getCString();
- for (i = 0; i <= indexHighA; ++i) {
-@@ -1254,14 +1354,7 @@
- goto err4;
- }
- obj1.free();
- cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
-- cs->nonMarking = gTrue;
-- for (i = 0; i < nCompsA; ++i) {
-- cs->names[i] = namesA[i];
-- if (namesA[i]->cmp("None")) {
-- cs->nonMarking = gFalse;
-- }
-- }
- return cs;
-
- err4:
-@@ -3187,7 +3299,7 @@
- GfxIndexedColorSpace *indexedCS;
- GfxSeparationColorSpace *sepCS;
- int maxPixel, indexHigh;
-- Guchar *lookup2;
-+ Guchar *indexedLookup;
- Function *sepFunc;
- Object obj;
- double x[gfxColorMaxComps];
-@@ -3204,6 +3316,7 @@
- // initialize
- for (k = 0; k < gfxColorMaxComps; ++k) {
- lookup[k] = NULL;
-+ lookup2[k] = NULL;
- }
-
- // get decode map
-@@ -3236,10 +3353,18 @@
- // Construct a lookup table -- this stores pre-computed decoded
- // values for each component, i.e., the result of applying the
- // decode mapping to each possible image pixel component value.
-- //
-+ for (k = 0; k < nComps; ++k) {
-+ lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
-+ sizeof(GfxColorComp));
-+ for (i = 0; i <= maxPixel; ++i) {
-+ lookup[k][i] = dblToCol(decodeLow[k] +
-+ (i * decodeRange[k]) / maxPixel);
-+ }
-+ }
-+
- // Optimization: for Indexed and Separation color spaces (which have
-- // only one component), we store color values in the lookup table
-- // rather than component values.
-+ // only one component), we pre-compute a second lookup table with
-+ // color values
- colorSpace2 = NULL;
- nComps2 = 0;
- if (colorSpace->getMode() == csIndexed) {
-@@ -3250,20 +3375,22 @@
- colorSpace2 = indexedCS->getBase();
- indexHigh = indexedCS->getIndexHigh();
- nComps2 = colorSpace2->getNComps();
-- lookup2 = indexedCS->getLookup();
-+ indexedLookup = indexedCS->getLookup();
- colorSpace2->getDefaultRanges(x, y, indexHigh);
- for (k = 0; k < nComps2; ++k) {
-- lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
-- sizeof(GfxColorComp));
-- for (i = 0; i <= maxPixel; ++i) {
-- j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
-- if (j < 0) {
-- j = 0;
-- } else if (j > indexHigh) {
-- j = indexHigh;
-- }
-- lookup[k][i] =
-- dblToCol(x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]);
-+ lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
-+ sizeof(GfxColorComp));
-+ }
-+ for (i = 0; i <= maxPixel; ++i) {
-+ j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
-+ if (j < 0) {
-+ j = 0;
-+ } else if (j > indexHigh) {
-+ j = indexHigh;
-+ }
-+ for (k = 0; k < nComps2; ++k) {
-+ lookup2[k][i] =
-+ dblToCol(x[k] + (indexedLookup[j*nComps2 + k] / 255.0) * y[k]);
- }
- }
- } else if (colorSpace->getMode() == csSeparation) {
-@@ -3272,21 +3399,14 @@
- nComps2 = colorSpace2->getNComps();
- sepFunc = sepCS->getFunc();
- for (k = 0; k < nComps2; ++k) {
-- lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
-- sizeof(GfxColorComp));
-- for (i = 0; i <= maxPixel; ++i) {
-- x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
-- sepFunc->transform(x, y);
-- lookup[k][i] = dblToCol(y[k]);
-- }
-+ lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
-+ sizeof(GfxColorComp));
- }
-- } else {
-- for (k = 0; k < nComps; ++k) {
-- lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
-- sizeof(GfxColorComp));
-- for (i = 0; i <= maxPixel; ++i) {
-- lookup[k][i] = dblToCol(decodeLow[k] +
-- (i * decodeRange[k]) / maxPixel);
-+ for (i = 0; i <= maxPixel; ++i) {
-+ x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
-+ sepFunc->transform(x, y);
-+ for (k = 0; k < nComps2; ++k) {
-+ lookup2[k][i] = dblToCol(y[k]);
- }
- }
- }
-@@ -3309,24 +3429,24 @@
- colorSpace2 = NULL;
- for (k = 0; k < gfxColorMaxComps; ++k) {
- lookup[k] = NULL;
-+ lookup2[k] = NULL;
- }
- n = 1 << bits;
-+ for (k = 0; k < nComps; ++k) {
-+ lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
-+ memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
-+ }
- if (colorSpace->getMode() == csIndexed) {
- colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
- for (k = 0; k < nComps2; ++k) {
-- lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
-- memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
-+ lookup2[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
-+ memcpy(lookup2[k], colorMap->lookup2[k], n * sizeof(GfxColorComp));
- }
- } else if (colorSpace->getMode() == csSeparation) {
- colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
- for (k = 0; k < nComps2; ++k) {
-- lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
-- memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
-- }
-- } else {
-- for (k = 0; k < nComps; ++k) {
-- lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
-- memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
-+ lookup2[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
-+ memcpy(lookup2[k], colorMap->lookup2[k], n * sizeof(GfxColorComp));
- }
- }
- for (i = 0; i < nComps; ++i) {
-@@ -3342,6 +3462,7 @@
- delete colorSpace;
- for (i = 0; i < gfxColorMaxComps; ++i) {
- gfree(lookup[i]);
-+ gfree(lookup2[i]);
- }
- }
-
-@@ -3351,7 +3472,7 @@
-
- if (colorSpace2) {
- for (i = 0; i < nComps2; ++i) {
-- color.c[i] = lookup[i][x[0]];
-+ color.c[i] = lookup2[i][x[0]];
- }
- colorSpace2->getGray(&color, gray);
- } else {
-@@ -3368,7 +3489,7 @@
-
- if (colorSpace2) {
- for (i = 0; i < nComps2; ++i) {
-- color.c[i] = lookup[i][x[0]];
-+ color.c[i] = lookup2[i][x[0]];
- }
- colorSpace2->getRGB(&color, rgb);
- } else {
-@@ -3385,7 +3506,7 @@
-
- if (colorSpace2) {
- for (i = 0; i < nComps2; ++i) {
-- color.c[i] = lookup[i][x[0]];
-+ color.c[i] = lookup2[i][x[0]];
- }
- colorSpace2->getCMYK(&color, cmyk);
- } else {
-@@ -3405,6 +3527,88 @@
- }
- }
-
-+void GfxImageColorMap::getGrayByteLine(Guchar *in, Guchar *out, int n) {
-+ GfxColor color;
-+ GfxGray gray;
-+ int i, j;
-+
-+ if (colorSpace2) {
-+ for (j = 0; j < n; ++j) {
-+ for (i = 0; i < nComps2; ++i) {
-+ color.c[i] = lookup2[i][in[j]];
-+ }
-+ colorSpace2->getGray(&color, &gray);
-+ out[j] = colToByte(gray);
-+ }
-+ } else {
-+ for (j = 0; j < n; ++j) {
-+ for (i = 0; i < nComps; ++i) {
-+ color.c[i] = lookup[i][in[j * nComps + i]];
-+ }
-+ colorSpace->getGray(&color, &gray);
-+ out[j] = colToByte(gray);
-+ }
-+ }
-+}
-+
-+void GfxImageColorMap::getRGBByteLine(Guchar *in, Guchar *out, int n) {
-+ GfxColor color;
-+ GfxRGB rgb;
-+ int i, j;
-+
-+ if (colorSpace2) {
-+ for (j = 0; j < n; ++j) {
-+ for (i = 0; i < nComps2; ++i) {
-+ color.c[i] = lookup2[i][in[j]];
-+ }
-+ colorSpace2->getRGB(&color, &rgb);
-+ out[j*3] = colToByte(rgb.r);
-+ out[j*3 + 1] = colToByte(rgb.g);
-+ out[j*3 + 2] = colToByte(rgb.b);
-+ }
-+ } else {
-+ for (j = 0; j < n; ++j) {
-+ for (i = 0; i < nComps; ++i) {
-+ color.c[i] = lookup[i][in[j * nComps + i]];
-+ }
-+ colorSpace->getRGB(&color, &rgb);
-+ out[j*3] = colToByte(rgb.r);
-+ out[j*3 + 1] = colToByte(rgb.g);
-+ out[j*3 + 2] = colToByte(rgb.b);
-+ }
-+ }
-+}
-+
-+void GfxImageColorMap::getCMYKByteLine(Guchar *in, Guchar *out, int n) {
-+ GfxColor color;
-+ GfxCMYK cmyk;
-+ int i, j;
-+
-+ if (colorSpace2) {
-+ for (j = 0; j < n; ++j) {
-+ for (i = 0; i < nComps2; ++i) {
-+ color.c[i] = lookup2[i][in[j]];
-+ }
-+ colorSpace2->getCMYK(&color, &cmyk);
-+ out[j*4] = colToByte(cmyk.c);
-+ out[j*4 + 1] = colToByte(cmyk.m);
-+ out[j*4 + 2] = colToByte(cmyk.y);
-+ out[j*4 + 3] = colToByte(cmyk.k);
-+ }
-+ } else {
-+ for (j = 0; j < n; ++j) {
-+ for (i = 0; i < nComps; ++i) {
-+ color.c[i] = lookup[i][in[j * nComps + i]];
-+ }
-+ colorSpace->getCMYK(&color, &cmyk);
-+ out[j*4] = colToByte(cmyk.c);
-+ out[j*4 + 1] = colToByte(cmyk.m);
-+ out[j*4 + 2] = colToByte(cmyk.y);
-+ out[j*4 + 3] = colToByte(cmyk.k);
-+ }
-+ }
-+}
-+
- //------------------------------------------------------------------------
- // GfxSubpath and GfxPath
- //------------------------------------------------------------------------
-@@ -3526,13 +3730,18 @@
- }
-
- void GfxPath::lineTo(double x, double y) {
-- if (justMoved) {
-+ if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
- if (n >= size) {
- size *= 2;
- subpaths = (GfxSubpath **)
- greallocn(subpaths, size, sizeof(GfxSubpath *));
- }
-- subpaths[n] = new GfxSubpath(firstX, firstY);
-+ if (justMoved) {
-+ subpaths[n] = new GfxSubpath(firstX, firstY);
-+ } else {
-+ subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
-+ subpaths[n-1]->getLastY());
-+ }
- ++n;
- justMoved = gFalse;
- }
-@@ -3541,13 +3750,18 @@
-
- void GfxPath::curveTo(double x1, double y1, double x2, double y2,
- double x3, double y3) {
-- if (justMoved) {
-+ if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
- if (n >= size) {
- size *= 2;
- subpaths = (GfxSubpath **)
- greallocn(subpaths, size, sizeof(GfxSubpath *));
- }
-- subpaths[n] = new GfxSubpath(firstX, firstY);
-+ if (justMoved) {
-+ subpaths[n] = new GfxSubpath(firstX, firstY);
-+ } else {
-+ subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
-+ subpaths[n-1]->getLastY());
-+ }
- ++n;
- justMoved = gFalse;
- }
-@@ -3658,6 +3872,7 @@
- strokeOpacity = 1;
- fillOverprint = gFalse;
- strokeOverprint = gFalse;
-+ overprintMode = 0;
- transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL;
-
- lineWidth = 1;
-@@ -3719,13 +3934,10 @@
- // this gets set to NULL by restore()
- delete path;
- }
-- if (saved) {
-- delete saved;
-- }
- }
-
- // Used for copy();
--GfxState::GfxState(GfxState *state) {
-+GfxState::GfxState(GfxState *state, GBool copyPath) {
- int i;
-
- memcpy(this, state, sizeof(GfxState));
-@@ -3750,6 +3962,9 @@
- lineDash = (double *)gmallocn(lineDashLength, sizeof(double));
- memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
- }
-+ if (copyPath) {
-+ path = state->path->copy();
-+ }
- saved = NULL;
- }
-
-@@ -4056,6 +4271,60 @@
- }
- }
-
-+void GfxState::clipToRect(double xMin, double yMin, double xMax, double yMax) {
-+ double x, y, xMin1, yMin1, xMax1, yMax1;
-+
-+ transform(xMin, yMin, &x, &y);
-+ xMin1 = xMax1 = x;
-+ yMin1 = yMax1 = y;
-+ transform(xMax, yMin, &x, &y);
-+ if (x < xMin1) {
-+ xMin1 = x;
-+ } else if (x > xMax1) {
-+ xMax1 = x;
-+ }
-+ if (y < yMin1) {
-+ yMin1 = y;
-+ } else if (y > yMax1) {
-+ yMax1 = y;
-+ }
-+ transform(xMax, yMax, &x, &y);
-+ if (x < xMin1) {
-+ xMin1 = x;
-+ } else if (x > xMax1) {
-+ xMax1 = x;
-+ }
-+ if (y < yMin1) {
-+ yMin1 = y;
-+ } else if (y > yMax1) {
-+ yMax1 = y;
-+ }
-+ transform(xMin, yMax, &x, &y);
-+ if (x < xMin1) {
-+ xMin1 = x;
-+ } else if (x > xMax1) {
-+ xMax1 = x;
-+ }
-+ if (y < yMin1) {
-+ yMin1 = y;
-+ } else if (y > yMax1) {
-+ yMax1 = y;
-+ }
-+
-+ if (xMin1 > clipXMin) {
-+ clipXMin = xMin1;
-+ }
-+ if (yMin1 > clipYMin) {
-+ clipYMin = yMin1;
-+ }
-+ if (xMax1 < clipXMax) {
-+ clipXMax = xMax1;
-+ }
-+ if (yMax1 < clipYMax) {
-+ clipYMax = yMax1;
-+ }
-+}
-+
- void GfxState::textShift(double tx, double ty) {
- double dx, dy;
-
-diff -ru xpdf-3.02/xpdf/GfxState.h xpdf-3.03/xpdf/GfxState.h
---- xpdf-3.02/xpdf/GfxState.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/GfxState.h 2011-08-15 23:08:53.000000000 +0200
-@@ -878,6 +894,11 @@
- void getCMYK(Guchar *x, GfxCMYK *cmyk);
- void getColor(Guchar *x, GfxColor *color);
-
-+ // Convert a line of <n> pixels to 8-bit colors.
-+ void getGrayByteLine(Guchar *in, Guchar *out, int n);
-+ void getRGBByteLine(Guchar *in, Guchar *out, int n);
-+ void getCMYKByteLine(Guchar *in, Guchar *out, int n);
-+
- private:
-
- GfxImageColorMap(GfxImageColorMap *colorMap);
-@@ -889,6 +910,8 @@
- int nComps2; // number of components in colorSpace2
- GfxColorComp * // lookup table
- lookup[gfxColorMaxComps];
-+ GfxColorComp * // optimized case lookup table
-+ lookup2[gfxColorMaxComps];
- double // minimum values for each component
- decodeLow[gfxColorMaxComps];
- double // max - min value for each component
-@@ -1023,7 +1046,8 @@
- ~GfxState();
-
- // Copy.
-- GfxState *copy() { return new GfxState(this); }
-+ GfxState *copy(GBool copyPath = gFalse)
-+ { return new GfxState(this, copyPath); }
-
- // Accessors.
- double getHDPI() { return hDPI; }
-@@ -1059,6 +1083,7 @@
- double getStrokeOpacity() { return strokeOpacity; }
- GBool getFillOverprint() { return fillOverprint; }
- GBool getStrokeOverprint() { return strokeOverprint; }
-+ int getOverprintMode() { return overprintMode; }
- Function **getTransfer() { return transfer; }
- double getLineWidth() { return lineWidth; }
- void getLineDash(double **dash, int *length, double *start)
-@@ -1127,6 +1152,7 @@
- void setStrokeOpacity(double opac) { strokeOpacity = opac; }
- void setFillOverprint(GBool op) { fillOverprint = op; }
- void setStrokeOverprint(GBool op) { strokeOverprint = op; }
-+ void setOverprintMode(int opm) { overprintMode = opm; }
- void setTransfer(Function **funcs);
- void setLineWidth(double width) { lineWidth = width; }
- void setLineDash(double *dash, int length, double start);
-@@ -1169,6 +1195,7 @@
- // Update clip region.
- void clip();
- void clipToStrokePath();
-+ void clipToRect(double xMin, double yMin, double xMax, double yMax);
-
- // Text position.
- void textSetPos(double tx, double ty) { lineX = tx; lineY = ty; }
-@@ -1204,6 +1231,7 @@
- double strokeOpacity; // stroke opacity
- GBool fillOverprint; // fill overprint
- GBool strokeOverprint; // stroke overprint
-+ int overprintMode; // overprint mode ("OPM")
- Function *transfer[4]; // transfer function (entries may be: all
- // NULL = identity; last three NULL =
- // single function; all four non-NULL =
-@@ -1238,7 +1266,7 @@
-
- GfxState *saved; // next GfxState on stack
-
-- GfxState(GfxState *state);
-+ GfxState(GfxState *state, GBool copyPath);
- };
-
- #endif
-diff -ru xpdf-3.02/xpdf/GlobalParams.cc xpdf-3.03/xpdf/GlobalParams.cc
---- xpdf-3.02/xpdf/GlobalParams.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/GlobalParams.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -124,215 +124,138 @@
- GlobalParams *globalParams = NULL;
-
- //------------------------------------------------------------------------
--// DisplayFontParam
-+// PSFontParam16
- //------------------------------------------------------------------------
-
--DisplayFontParam::DisplayFontParam(GString *nameA,
-- DisplayFontParamKind kindA) {
-+PSFontParam16::PSFontParam16(GString *nameA, int wModeA,
-+ GString *psFontNameA, GString *encodingA) {
- name = nameA;
-- kind = kindA;
-- switch (kind) {
-- case displayFontT1:
-- t1.fileName = NULL;
-- break;
-- case displayFontTT:
-- tt.fileName = NULL;
-- break;
-- }
-+ wMode = wModeA;
-+ psFontName = psFontNameA;
-+ encoding = encodingA;
- }
-
--DisplayFontParam::~DisplayFontParam() {
-+PSFontParam16::~PSFontParam16() {
- delete name;
-- switch (kind) {
-- case displayFontT1:
-- if (t1.fileName) {
-- delete t1.fileName;
-- }
-- break;
-- case displayFontTT:
-- if (tt.fileName) {
-- delete tt.fileName;
-- }
-- break;
-- }
-+ delete psFontName;
-+ delete encoding;
- }
-
--#ifdef WIN32
--
- //------------------------------------------------------------------------
--// WinFontInfo
-+// SysFontInfo
- //------------------------------------------------------------------------
-
--class WinFontInfo: public DisplayFontParam {
-+class SysFontInfo {
- public:
-
-- GBool bold, italic;
-+ GString *name;
-+ GBool bold;
-+ GBool italic;
-+ GString *path;
-+ SysFontType type;
-+ int fontNum; // for TrueType collections
-
-- static WinFontInfo *make(GString *nameA, GBool boldA, GBool italicA,
-- HKEY regKey, char *winFontDir);
-- WinFontInfo(GString *nameA, GBool boldA, GBool italicA,
-- GString *fileNameA);
-- virtual ~WinFontInfo();
-- GBool equals(WinFontInfo *fi);
-+ SysFontInfo(GString *nameA, GBool boldA, GBool italicA,
-+ GString *pathA, SysFontType typeA, int fontNumA);
-+ ~SysFontInfo();
-+ GBool match(SysFontInfo *fi);
-+ GBool match(GString *nameA, GBool boldA, GBool italicA);
- };
-
--WinFontInfo *WinFontInfo::make(GString *nameA, GBool boldA, GBool italicA,
-- HKEY regKey, char *winFontDir) {
-- GString *regName;
-- GString *fileNameA;
-- char buf[MAX_PATH];
-- DWORD n;
-- char c;
-- int i;
--
-- //----- find the font file
-- fileNameA = NULL;
-- regName = nameA->copy();
-- if (boldA) {
-- regName->append(" Bold");
-- }
-- if (italicA) {
-- regName->append(" Italic");
-- }
-- regName->append(" (TrueType)");
-- n = sizeof(buf);
-- if (RegQueryValueEx(regKey, regName->getCString(), NULL, NULL,
-- (LPBYTE)buf, &n) == ERROR_SUCCESS) {
-- fileNameA = new GString(winFontDir);
-- fileNameA->append('\\')->append(buf);
-- }
-- delete regName;
-- if (!fileNameA) {
-- delete nameA;
-- return NULL;
-- }
--
-- //----- normalize the font name
-- i = 0;
-- while (i < nameA->getLength()) {
-- c = nameA->getChar(i);
-- if (c == ' ' || c == ',' || c == '-') {
-- nameA->del(i);
-- } else {
-- ++i;
-- }
-- }
--
-- return new WinFontInfo(nameA, boldA, italicA, fileNameA);
--}
--
--WinFontInfo::WinFontInfo(GString *nameA, GBool boldA, GBool italicA,
-- GString *fileNameA):
-- DisplayFontParam(nameA, displayFontTT)
--{
-+SysFontInfo::SysFontInfo(GString *nameA, GBool boldA, GBool italicA,
-+ GString *pathA, SysFontType typeA, int fontNumA) {
-+ name = nameA;
- bold = boldA;
- italic = italicA;
-- tt.fileName = fileNameA;
-+ path = pathA;
-+ type = typeA;
-+ fontNum = fontNumA;
-+}
-+
-+SysFontInfo::~SysFontInfo() {
-+ delete name;
-+ delete path;
- }
-
--WinFontInfo::~WinFontInfo() {
-+GBool SysFontInfo::match(SysFontInfo *fi) {
-+ return !strcasecmp(name->getCString(), fi->name->getCString()) &&
-+ bold == fi->bold && italic == fi->italic;
- }
-
--GBool WinFontInfo::equals(WinFontInfo *fi) {
-- return !name->cmp(fi->name) && bold == fi->bold && italic == fi->italic;
-+GBool SysFontInfo::match(GString *nameA, GBool boldA, GBool italicA) {
-+ return !strcasecmp(name->getCString(), nameA->getCString()) &&
-+ bold == boldA && italic == italicA;
- }
-
- //------------------------------------------------------------------------
--// WinFontList
-+// SysFontList
- //------------------------------------------------------------------------
-
--class WinFontList {
-+class SysFontList {
- public:
-
-- WinFontList(char *winFontDirA);
-- ~WinFontList();
-- WinFontInfo *find(GString *font);
-+ SysFontList();
-+ ~SysFontList();
-+ SysFontInfo *find(GString *name);
-+
-+#ifdef WIN32
-+ void scanWindowsFonts(char *winFontDir);
-+#endif
-
- private:
-
-- void add(WinFontInfo *fi);
-- static int CALLBACK enumFunc1(CONST LOGFONT *font,
-- CONST TEXTMETRIC *metrics,
-- DWORD type, LPARAM data);
-- static int CALLBACK enumFunc2(CONST LOGFONT *font,
-- CONST TEXTMETRIC *metrics,
-- DWORD type, LPARAM data);
--
-- GList *fonts; // [WinFontInfo]
-- HDC dc; // (only used during enumeration)
-- HKEY regKey; // (only used during enumeration)
-- char *winFontDir; // (only used during enumeration)
--};
-+#ifdef WIN32
-+ SysFontInfo *makeWindowsFont(char *name, int fontNum,
-+ char *path);
-+#endif
-
--WinFontList::WinFontList(char *winFontDirA) {
-- OSVERSIONINFO version;
-- char *path;
-+ GList *fonts; // [SysFontInfo]
-+};
-
-+SysFontList::SysFontList() {
- fonts = new GList();
-- dc = GetDC(NULL);
-- winFontDir = winFontDirA;
-- version.dwOSVersionInfoSize = sizeof(version);
-- GetVersionEx(&version);
-- if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-- path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
-- } else {
-- path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
-- }
-- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0,
-- KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
-- &regKey) == ERROR_SUCCESS) {
-- EnumFonts(dc, NULL, &WinFontList::enumFunc1, (LPARAM)this);
-- RegCloseKey(regKey);
-- }
-- ReleaseDC(NULL, dc);
- }
-
--WinFontList::~WinFontList() {
-- deleteGList(fonts, WinFontInfo);
-+SysFontList::~SysFontList() {
-+ deleteGList(fonts, SysFontInfo);
- }
-
--void WinFontList::add(WinFontInfo *fi) {
-- int i;
--
-- for (i = 0; i < fonts->getLength(); ++i) {
-- if (((WinFontInfo *)fonts->get(i))->equals(fi)) {
-- delete fi;
-- return;
-- }
-- }
-- fonts->append(fi);
--}
--
--WinFontInfo *WinFontList::find(GString *font) {
-- GString *name;
-+SysFontInfo *SysFontList::find(GString *name) {
-+ GString *name2;
- GBool bold, italic;
-- WinFontInfo *fi;
-+ SysFontInfo *fi;
- char c;
- int n, i;
-
-- name = font->copy();
-+ name2 = name->copy();
-
- // remove space, comma, dash chars
- i = 0;
-- while (i < name->getLength()) {
-- c = name->getChar(i);
-+ while (i < name2->getLength()) {
-+ c = name2->getChar(i);
- if (c == ' ' || c == ',' || c == '-') {
-- name->del(i);
-+ name2->del(i);
- } else {
- ++i;
- }
- }
-- n = name->getLength();
-+ n = name2->getLength();
-
- // remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.)
-- if (!strcmp(name->getCString() + n - 2, "MT")) {
-- name->del(n - 2, 2);
-+ if (n > 2 && !strcmp(name2->getCString() + n - 2, "MT")) {
-+ name2->del(n - 2, 2);
- n -= 2;
- }
-
-+ // look for "Regular"
-+ if (n > 7 && !strcmp(name2->getCString() + n - 7, "Regular")) {
-+ name2->del(n - 7, 7);
-+ n -= 7;
-+ }
-+
- // look for "Italic"
-- if (!strcmp(name->getCString() + n - 6, "Italic")) {
-- name->del(n - 6, 6);
-+ if (n > 6 && !strcmp(name2->getCString() + n - 6, "Italic")) {
-+ name2->del(n - 6, 6);
- italic = gTrue;
- n -= 6;
- } else {
-@@ -340,8 +263,8 @@
- }
-
- // look for "Bold"
-- if (!strcmp(name->getCString() + n - 4, "Bold")) {
-- name->del(n - 4, 4);
-+ if (n > 4 && !strcmp(name2->getCString() + n - 4, "Bold")) {
-+ name2->del(n - 4, 4);
- bold = gTrue;
- n -= 4;
- } else {
-@@ -349,84 +272,183 @@
- }
-
- // remove trailing "MT" (FooMT-Bold, etc.)
-- if (!strcmp(name->getCString() + n - 2, "MT")) {
-- name->del(n - 2, 2);
-+ if (n > 2 && !strcmp(name2->getCString() + n - 2, "MT")) {
-+ name2->del(n - 2, 2);
- n -= 2;
- }
-
- // remove trailing "PS"
-- if (!strcmp(name->getCString() + n - 2, "PS")) {
-- name->del(n - 2, 2);
-+ if (n > 2 && !strcmp(name2->getCString() + n - 2, "PS")) {
-+ name2->del(n - 2, 2);
- n -= 2;
- }
-
-+ // remove trailing "IdentityH"
-+ if (n > 9 && !strcmp(name2->getCString() + n - 9, "IdentityH")) {
-+ name2->del(n - 9, 9);
-+ n -= 9;
-+ }
-+
- // search for the font
- fi = NULL;
- for (i = 0; i < fonts->getLength(); ++i) {
-- fi = (WinFontInfo *)fonts->get(i);
-- if (!fi->name->cmp(name) && fi->bold == bold && fi->italic == italic) {
-+ fi = (SysFontInfo *)fonts->get(i);
-+ if (fi->match(name2, bold, italic)) {
- break;
- }
- fi = NULL;
- }
-+ if (!fi && bold) {
-+ // try ignoring the bold flag
-+ for (i = 0; i < fonts->getLength(); ++i) {
-+ fi = (SysFontInfo *)fonts->get(i);
-+ if (fi->match(name2, gFalse, italic)) {
-+ break;
-+ }
-+ fi = NULL;
-+ }
-+ }
-+ if (!fi && (bold || italic)) {
-+ // try ignoring the bold and italic flags
-+ for (i = 0; i < fonts->getLength(); ++i) {
-+ fi = (SysFontInfo *)fonts->get(i);
-+ if (fi->match(name2, gFalse, gFalse)) {
-+ break;
-+ }
-+ fi = NULL;
-+ }
-+ }
-
-- delete name;
-+ delete name2;
- return fi;
- }
-
--int CALLBACK WinFontList::enumFunc1(CONST LOGFONT *font,
-- CONST TEXTMETRIC *metrics,
-- DWORD type, LPARAM data) {
-- WinFontList *fl = (WinFontList *)data;
--
-- EnumFonts(fl->dc, font->lfFaceName, &WinFontList::enumFunc2, (LPARAM)fl);
-- return 1;
--}
--
--int CALLBACK WinFontList::enumFunc2(CONST LOGFONT *font,
-- CONST TEXTMETRIC *metrics,
-- DWORD type, LPARAM data) {
-- WinFontList *fl = (WinFontList *)data;
-- WinFontInfo *fi;
--
-- if (type & TRUETYPE_FONTTYPE) {
-- if ((fi = WinFontInfo::make(new GString(font->lfFaceName),
-- font->lfWeight >= 600,
-- font->lfItalic ? gTrue : gFalse,
-- fl->regKey, fl->winFontDir))) {
-- fl->add(fi);
-+#ifdef WIN32
-+void SysFontList::scanWindowsFonts(char *winFontDir) {
-+ OSVERSIONINFO version;
-+ char *path;
-+ DWORD idx, valNameLen, dataLen, type;
-+ HKEY regKey;
-+ char valName[1024], data[1024];
-+ int n, fontNum;
-+ char *p0, *p1;
-+ GString *fontPath;
-+
-+ version.dwOSVersionInfoSize = sizeof(version);
-+ GetVersionEx(&version);
-+ if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-+ path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
-+ } else {
-+ path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
-+ }
-+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0,
-+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
-+ &regKey) == ERROR_SUCCESS) {
-+ idx = 0;
-+ while (1) {
-+ valNameLen = sizeof(valName) - 1;
-+ dataLen = sizeof(data) - 1;
-+ if (RegEnumValue(regKey, idx, valName, &valNameLen, NULL,
-+ &type, (LPBYTE)data, &dataLen) != ERROR_SUCCESS) {
-+ break;
-+ }
-+ if (type == REG_SZ &&
-+ valNameLen > 0 && valNameLen < sizeof(valName) &&
-+ dataLen > 0 && dataLen < sizeof(data)) {
-+ valName[valNameLen] = '\0';
-+ data[dataLen] = '\0';
-+ n = strlen(data);
-+ if (!strcasecmp(data + n - 4, ".ttf") ||
-+ !strcasecmp(data + n - 4, ".ttc")) {
-+ fontPath = new GString(data);
-+ if (!(dataLen >= 3 && data[1] == ':' && data[2] == '\\')) {
-+ fontPath->insert(0, '\\');
-+ fontPath->insert(0, winFontDir);
-+ }
-+ p0 = valName;
-+ fontNum = 0;
-+ while (*p0) {
-+ p1 = strstr(p0, " & ");
-+ if (p1) {
-+ *p1 = '\0';
-+ p1 = p1 + 3;
-+ } else {
-+ p1 = p0 + strlen(p0);
-+ }
-+ fonts->append(makeWindowsFont(p0, fontNum,
-+ fontPath->getCString()));
-+ p0 = p1;
-+ ++fontNum;
-+ }
-+ delete fontPath;
-+ }
-+ }
-+ ++idx;
- }
-+ RegCloseKey(regKey);
- }
-- return 1;
- }
-
--#endif // WIN32
-+SysFontInfo *SysFontList::makeWindowsFont(char *name, int fontNum,
-+ char *path) {
-+ int n;
-+ GBool bold, italic;
-+ GString *s;
-+ char c;
-+ int i;
-+ SysFontType type;
-
--//------------------------------------------------------------------------
--// PSFontParam
--//------------------------------------------------------------------------
-+ n = strlen(name);
-+ bold = italic = gFalse;
-
--PSFontParam::PSFontParam(GString *pdfFontNameA, int wModeA,
-- GString *psFontNameA, GString *encodingA) {
-- pdfFontName = pdfFontNameA;
-- wMode = wModeA;
-- psFontName = psFontNameA;
-- encoding = encodingA;
--}
-+ // remove trailing ' (TrueType)'
-+ if (n > 11 && !strncmp(name + n - 11, " (TrueType)", 11)) {
-+ n -= 11;
-+ }
-
--PSFontParam::~PSFontParam() {
-- delete pdfFontName;
-- delete psFontName;
-- if (encoding) {
-- delete encoding;
-+ // remove trailing ' Italic'
-+ if (n > 7 && !strncmp(name + n - 7, " Italic", 7)) {
-+ n -= 7;
-+ italic = gTrue;
-+ }
-+
-+ // remove trailing ' Bold'
-+ if (n > 5 && !strncmp(name + n - 5, " Bold", 5)) {
-+ n -= 5;
-+ bold = gTrue;
- }
-+
-+ // remove trailing ' Regular'
-+ if (n > 5 && !strncmp(name + n - 8, " Regular", 8)) {
-+ n -= 8;
-+ }
-+
-+ //----- normalize the font name
-+ s = new GString(name, n);
-+ i = 0;
-+ while (i < s->getLength()) {
-+ c = s->getChar(i);
-+ if (c == ' ' || c == ',' || c == '-') {
-+ s->del(i);
-+ } else {
-+ ++i;
-+ }
-+ }
-+
-+ if (!strcasecmp(path + strlen(path) - 4, ".ttc")) {
-+ type = sysFontTTC;
-+ } else {
-+ type = sysFontTTF;
-+ }
-+ return new SysFontInfo(s, bold, italic, new GString(path), type, fontNum);
- }
-+#endif
-
- //------------------------------------------------------------------------
- // KeyBinding
- //------------------------------------------------------------------------
-
--KeyBinding::KeyBinding(int codeA, int modsA, int contextA, char *cmd0) {
-+KeyBinding::KeyBinding(int codeA, int modsA, int contextA, const char *cmd0) {
- code = codeA;
- mods = modsA;
- context = contextA;
-@@ -637,9 +657,10 @@
- unicodeMaps = new GHash(gTrue);
- cMapDirs = new GHash(gTrue);
- toUnicodeDirs = new GList();
-- displayFonts = new GHash();
-- displayCIDFonts = new GHash();
-- displayNamedCIDFonts = new GHash();
-+ fontFiles = new GHash(gTrue);
-+ fontDirs = new GList();
-+ ccFontFiles = new GHash(gTrue);
-+ sysFonts = new SysFontList();
- #if HAVE_PAPER_H
- char *paperName;
- const struct paper *paperType;
-@@ -668,16 +689,21 @@
- psDuplex = gFalse;
- psLevel = psLevel2;
- psFile = NULL;
-- psFonts = new GHash();
-- psNamedFonts16 = new GList();
-- psFonts16 = new GList();
-+ psResidentFonts = new GHash(gTrue);
-+ psResidentFonts16 = new GList();
-+ psResidentFontsCC = new GList();
- psEmbedType1 = gTrue;
- psEmbedTrueType = gTrue;
- psEmbedCIDPostScript = gTrue;
- psEmbedCIDTrueType = gTrue;
-+ psFontPassthrough = gFalse;
- psPreload = gFalse;
- psOPI = gFalse;
- psASCIIHex = gFalse;
-+ psUncompressPreloadedImages = gFalse;
-+ psRasterResolution = 300;
-+ psRasterMono = gFalse;
-+ psAlwaysRasterize = gFalse;
- textEncoding = new GString("Latin1");
- #if defined(WIN32)
- textEOL = eolDOS;
-@@ -688,13 +714,14 @@
- #endif
- textPageBreaks = gTrue;
- textKeepTinyChars = gFalse;
-- fontDirs = new GList();
- initialZoom = new GString("125");
- continuousView = gFalse;
- enableT1lib = gTrue;
- enableFreeType = gTrue;
-+ disableFreeTypeHinting = gFalse;
- antialias = gTrue;
- vectorAntialias = gTrue;
-+ antialiasPrinting = gFalse;
- strokeAdjust = gTrue;
- screenType = screenUnset;
- screenSize = -1;
-@@ -702,6 +729,10 @@
- screenGamma = 1.0;
- screenBlackThreshold = 0.0;
- screenWhiteThreshold = 1.0;
-+ minLineWidth = 0.0;
- overprintPreview = gFalse;
- urlCommand = NULL;
- movieCommand = NULL;
- mapNumericCharNames = gTrue;
-@@ -716,10 +747,6 @@
- unicodeMapCache = new UnicodeMapCache();
- cMapCache = new CMapCache();
-
--#ifdef WIN32
-- winFontList = NULL;
--#endif
--
- #ifdef ENABLE_PLUGINS
- plugins = new GList();
- securityHandlers = new GList();
-@@ -764,7 +791,7 @@
- }
- }
- if (!f) {
--#if defined(WIN32) && !defined(__CYGWIN32__)
-+#ifdef WIN32
- char buf[512];
- i = GetModuleFileName(NULL, buf, sizeof(buf));
- if (i <= 0 || i >= sizeof(buf)) {
-@@ -1762,23 +1833,21 @@
- deleteGHash(residentUnicodeMaps, UnicodeMap);
- deleteGHash(unicodeMaps, GString);
- deleteGList(toUnicodeDirs, GString);
-- deleteGHash(displayFonts, DisplayFontParam);
-- deleteGHash(displayCIDFonts, DisplayFontParam);
-- deleteGHash(displayNamedCIDFonts, DisplayFontParam);
--#ifdef WIN32
-- if (winFontList) {
-- delete winFontList;
-- }
--#endif
-+ deleteGHash(fontFiles, GString);
-+ deleteGList(fontDirs, GString);
-+ deleteGHash(ccFontFiles, GString);
-+ delete sysFonts;
- if (psFile) {
- delete psFile;
- }
-- deleteGHash(psFonts, PSFontParam);
-- deleteGList(psNamedFonts16, PSFontParam);
-- deleteGList(psFonts16, PSFontParam);
-+ deleteGHash(psResidentFonts, GString);
-+ deleteGList(psResidentFonts16, PSFontParam16);
-+ deleteGList(psResidentFontsCC, PSFontParam16);
- delete textEncoding;
-- deleteGList(fontDirs, GString);
- delete initialZoom;
-@@ -1829,8 +1898,6 @@
- char winFontDir[MAX_PATH];
- #endif
- FILE *f;
-- DisplayFontParamKind kind;
-- DisplayFontParam *dfp;
- int i, j;
-
- #ifdef WIN32
-@@ -1850,16 +1917,13 @@
- }
- #endif
- for (i = 0; displayFontTab[i].name; ++i) {
-- fontName = new GString(displayFontTab[i].name);
-- if (getDisplayFont(fontName)) {
-- delete fontName;
-+ if (fontFiles->lookup(displayFontTab[i].name)) {
- continue;
- }
-+ fontName = new GString(displayFontTab[i].name);
- fileName = NULL;
-- kind = displayFontT1; // make gcc happy
- if (dir) {
- fileName = appendToPath(new GString(dir), displayFontTab[i].t1FileName);
-- kind = displayFontT1;
- if ((f = fopen(fileName->getCString(), "rb"))) {
- fclose(f);
- } else {
-@@ -1871,7 +1935,6 @@
- if (!fileName && winFontDir[0] && displayFontTab[i].ttFileName) {
- fileName = appendToPath(new GString(winFontDir),
- displayFontTab[i].ttFileName);
-- kind = displayFontTT;
- if ((f = fopen(fileName->getCString(), "rb"))) {
- fclose(f);
- } else {
-@@ -1886,7 +1949,6 @@
- for (j = 0; !fileName && displayFontDirs[j]; ++j) {
- fileName = appendToPath(new GString(displayFontDirs[j]),
- displayFontTab[i].ttFileName);
-- kind = displayFontTT;
- if ((f = fopen(fileName->getCString(), "rb"))) {
- fclose(f);
- } else {
-@@ -1895,11 +1957,10 @@
- }
- }
- }
--#else
-+#else // WIN32
- for (j = 0; !fileName && displayFontDirs[j]; ++j) {
- fileName = appendToPath(new GString(displayFontDirs[j]),
- displayFontTab[i].t1FileName);
-- kind = displayFontT1;
- if ((f = fopen(fileName->getCString(), "rb"))) {
- fclose(f);
- } else {
-@@ -1907,20 +1968,19 @@
- fileName = NULL;
- }
- }
--#endif
-+#endif // WIN32
- if (!fileName) {
-- error(-1, "No display font for '%s'", displayFontTab[i].name);
-+ error(errConfig, -1, "No display font for '{0:s}'",
-+ displayFontTab[i].name);
- delete fontName;
- continue;
- }
-- dfp = new DisplayFontParam(fontName, kind);
-- dfp->t1.fileName = fileName;
-- globalParams->addDisplayFont(dfp);
-+ addFontFile(fontName, fileName);
- }
-
- #ifdef WIN32
- if (winFontDir[0]) {
-- winFontList = new WinFontList(winFontDir);
-+ sysFonts->scanWindowsFonts(winFontDir);
- }
- #endif
- }
-@@ -2020,31 +2080,72 @@
- return NULL;
- }
-
--DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) {
-- DisplayFontParam *dfp;
-+GString *GlobalParams::findFontFile(GString *fontName) {
-+ static const char *exts[] = { ".pfa", ".pfb", ".ttf", ".ttc" };
-+ GString *path, *dir;
-+#ifdef WIN32
-+ GString *fontNameU;
-+#endif
-+ const char *ext;
-+ FILE *f;
-+ int i, j;
-
- lockGlobalParams;
-- dfp = (DisplayFontParam *)displayFonts->lookup(fontName);
--#ifdef WIN32
-- if (!dfp && winFontList) {
-- dfp = winFontList->find(fontName);
-+ if ((path = (GString *)fontFiles->lookup(fontName))) {
-+ path = path->copy();
-+ unlockGlobalParams;
-+ return path;
- }
-+ for (i = 0; i < fontDirs->getLength(); ++i) {
-+ dir = (GString *)fontDirs->get(i);
-+ for (j = 0; j < (int)(sizeof(exts) / sizeof(exts[0])); ++j) {
-+ ext = exts[j];
-+#ifdef WIN32
-+ fontNameU = fileNameToUTF8(fontName->getCString());
-+ path = appendToPath(dir->copy(), fontNameU->getCString());
-+ delete fontNameU;
-+#else
-+ path = appendToPath(dir->copy(), fontName->getCString());
- #endif
-+ path->append(ext);
-+ if ((f = openFile(path->getCString(), "rb"))) {
-+ fclose(f);
-+ unlockGlobalParams;
-+ return path;
-+ }
-+ delete path;
-+ }
-+ }
-+ unlockGlobalParams;
-+ return NULL;
-+}
-+
-+GString *GlobalParams::findSystemFontFile(GString *fontName,
-+ SysFontType *type,
-+ int *fontNum) {
-+ SysFontInfo *fi;
-+ GString *path;
-+
-+ path = NULL;
-+ lockGlobalParams;
-+ if ((fi = sysFonts->find(fontName))) {
-+ path = fi->path->copy();
-+ *type = fi->type;
-+ *fontNum = fi->fontNum;
-+ }
- unlockGlobalParams;
-- return dfp;
-+ return path;
- }
-
--DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *fontName,
-- GString *collection) {
-- DisplayFontParam *dfp;
-+GString *GlobalParams::findCCFontFile(GString *collection) {
-+ GString *path;
-
- lockGlobalParams;
-- if (!fontName ||
-- !(dfp = (DisplayFontParam *)displayNamedCIDFonts->lookup(fontName))) {
-- dfp = (DisplayFontParam *)displayCIDFonts->lookup(collection);
-+ if ((path = (GString *)ccFontFiles->lookup(collection))) {
-+ path = path->copy();
- }
- unlockGlobalParams;
-- return dfp;
-+ return path;
- }
-
- GString *GlobalParams::getPSFile() {
-@@ -2137,41 +2238,62 @@
- return level;
- }
-
--PSFontParam *GlobalParams::getPSFont(GString *fontName) {
-- PSFontParam *p;
-+GString *GlobalParams::getPSResidentFont(GString *fontName) {
-+ GString *psName;
-
- lockGlobalParams;
-- p = (PSFontParam *)psFonts->lookup(fontName);
-+ psName = (GString *)psResidentFonts->lookup(fontName);
- unlockGlobalParams;
-- return p;
-+ return psName;
- }
-
--PSFontParam *GlobalParams::getPSFont16(GString *fontName,
-- GString *collection, int wMode) {
-- PSFontParam *p;
-+GList *GlobalParams::getPSResidentFonts() {
-+ GList *names;
-+ GHashIter *iter;
-+ GString *name;
-+ GString *psName;
-+
-+ names = new GList();
-+ lockGlobalParams;
-+ psResidentFonts->startIter(&iter);
-+ while (psResidentFonts->getNext(&iter, &name, (void **)&psName)) {
-+ names->append(psName->copy());
-+ }
-+ unlockGlobalParams;
-+ return names;
-+}
-+
-+PSFontParam16 *GlobalParams::getPSResidentFont16(GString *fontName,
-+ int wMode) {
-+ PSFontParam16 *p;
- int i;
-
- lockGlobalParams;
- p = NULL;
-- if (fontName) {
-- for (i = 0; i < psNamedFonts16->getLength(); ++i) {
-- p = (PSFontParam *)psNamedFonts16->get(i);
-- if (!p->pdfFontName->cmp(fontName) &&
-- p->wMode == wMode) {
-- break;
-- }
-- p = NULL;
-+ for (i = 0; i < psResidentFonts16->getLength(); ++i) {
-+ p = (PSFontParam16 *)psResidentFonts16->get(i);
-+ if (!(p->name->cmp(fontName)) && p->wMode == wMode) {
-+ break;
- }
-+ p = NULL;
- }
-- if (!p && collection) {
-- for (i = 0; i < psFonts16->getLength(); ++i) {
-- p = (PSFontParam *)psFonts16->get(i);
-- if (!p->pdfFontName->cmp(collection) &&
-- p->wMode == wMode) {
-- break;
-- }
-- p = NULL;
-+ unlockGlobalParams;
-+ return p;
-+}
-+
-+PSFontParam16 *GlobalParams::getPSResidentFontCC(GString *collection,
-+ int wMode) {
-+ PSFontParam16 *p;
-+ int i;
-+
-+ lockGlobalParams;
-+ p = NULL;
-+ for (i = 0; i < psResidentFontsCC->getLength(); ++i) {
-+ p = (PSFontParam16 *)psResidentFontsCC->get(i);
-+ if (!(p->name->cmp(collection)) && p->wMode == wMode) {
-+ break;
- }
-+ p = NULL;
- }
- unlockGlobalParams;
- return p;
-@@ -2213,6 +2335,15 @@
- return e;
- }
-
-+GBool GlobalParams::getPSFontPassthrough() {
-+ GBool e;
-+
-+ lockGlobalParams;
-+ e = psFontPassthrough;
-+ unlockGlobalParams;
-+ return e;
-+}
-+
- GBool GlobalParams::getPSPreload() {
- GBool preload;
-
-@@ -2240,6 +2371,42 @@
- return ah;
- }
-
-+GBool GlobalParams::getPSUncompressPreloadedImages() {
-+ GBool ah;
-+
-+ lockGlobalParams;
-+ ah = psUncompressPreloadedImages;
-+ unlockGlobalParams;
-+ return ah;
-+}
-+
-+double GlobalParams::getPSRasterResolution() {
-+ double res;
-+
-+ lockGlobalParams;
-+ res = psRasterResolution;
-+ unlockGlobalParams;
-+ return res;
-+}
-+
-+GBool GlobalParams::getPSRasterMono() {
-+ GBool mono;
-+
-+ lockGlobalParams;
-+ mono = psRasterMono;
-+ unlockGlobalParams;
-+ return mono;
-+}
-+
-+GBool GlobalParams::getPSAlwaysRasterize() {
-+ GBool rast;
-+
-+ lockGlobalParams;
-+ rast = psAlwaysRasterize;
-+ unlockGlobalParams;
-+ return rast;
-+}
-+
- GString *GlobalParams::getTextEncodingName() {
- GString *s;
-
-@@ -2276,30 +2443,6 @@
- return tiny;
- }
-
--GString *GlobalParams::findFontFile(GString *fontName, char **exts) {
-- GString *dir, *fileName;
-- char **ext;
-- FILE *f;
-- int i;
--
-- lockGlobalParams;
-- for (i = 0; i < fontDirs->getLength(); ++i) {
-- dir = (GString *)fontDirs->get(i);
-- for (ext = exts; *ext; ++ext) {
-- fileName = appendToPath(dir->copy(), fontName->getCString());
-- fileName->append(*ext);
-- if ((f = fopen(fileName->getCString(), "rb"))) {
-- fclose(f);
-- unlockGlobalParams;
-- return fileName;
-- }
-- delete fileName;
-- }
-- }
-- unlockGlobalParams;
-- return NULL;
--}
--
- GString *GlobalParams::getInitialZoom() {
- GString *s;
-
-@@ -2355,6 +2507,15 @@
- return f;
- }
-
-+GBool GlobalParams::getAntialiasPrinting() {
-+ GBool f;
-+
-+ lockGlobalParams;
-+ f = antialiasPrinting;
-+ unlockGlobalParams;
-+ return f;
-+}
-+
- GBool GlobalParams::getStrokeAdjust() {
- GBool f;
-
-@@ -2418,6 +2579,24 @@
- return thresh;
- }
-
-+double GlobalParams::getMinLineWidth() {
-+ double w;
-+
-+ lockGlobalParams;
-+ w = minLineWidth;
-+ unlockGlobalParams;
-+ return w;
-+}
-+
- GBool GlobalParams::getMapNumericCharNames() {
- GBool map;
-
-@@ -2552,14 +2731,9 @@
- // functions to set parameters
- //------------------------------------------------------------------------
-
--void GlobalParams::addDisplayFont(DisplayFontParam *param) {
-- DisplayFontParam *old;
--
-+void GlobalParams::addFontFile(GString *fontName, GString *path) {
- lockGlobalParams;
-- if ((old = (DisplayFontParam *)displayFonts->remove(param->name))) {
-- delete old;
-- }
-- displayFonts->add(param->name, param);
-+ fontFiles->add(fontName, path);
- unlockGlobalParams;
- }
-
-@@ -2684,6 +2858,12 @@
- unlockGlobalParams;
- }
-
-+void GlobalParams::setPSFontPassthrough(GBool passthrough) {
-+ lockGlobalParams;
-+ psFontPassthrough = passthrough;
-+ unlockGlobalParams;
-+}
-+
- void GlobalParams::setPSPreload(GBool preload) {
- lockGlobalParams;
- psPreload = preload;
-diff -ru xpdf-3.02/xpdf/GlobalParams.h xpdf-3.03/xpdf/GlobalParams.h
---- xpdf-3.02/xpdf/GlobalParams.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/GlobalParams.h 2011-08-15 23:08:53.000000000 +0200
-@@ -35,9 +35,7 @@
- class CMapCache;
- struct XpdfSecurityHandler;
- class GlobalParams;
--#ifdef WIN32
--class WinFontList;
--#endif
-+class SysFontList;
-
- //------------------------------------------------------------------------
-
-@@ -46,51 +44,27 @@
-
- //------------------------------------------------------------------------
-
--enum DisplayFontParamKind {
-- displayFontT1,
-- displayFontTT
--};
--
--struct DisplayFontParamT1 {
-- GString *fileName;
--};
--
--struct DisplayFontParamTT {
-- GString *fileName;
--};
--
--class DisplayFontParam {
--public:
--
-- GString *name; // font name for 8-bit fonts and named
-- // CID fonts; collection name for
-- // generic CID fonts
-- DisplayFontParamKind kind;
-- union {
-- DisplayFontParamT1 t1;
-- DisplayFontParamTT tt;
-- };
--
-- DisplayFontParam(GString *nameA, DisplayFontParamKind kindA);
-- virtual ~DisplayFontParam();
-+enum SysFontType {
-+ sysFontPFA,
-+ sysFontPFB,
-+ sysFontTTF,
-+ sysFontTTC
- };
-
- //------------------------------------------------------------------------
-
--class PSFontParam {
-+class PSFontParam16 {
- public:
-
-- GString *pdfFontName; // PDF font name for 8-bit fonts and
-- // named 16-bit fonts; char collection
-- // name for generic 16-bit fonts
-- int wMode; // writing mode (0=horiz, 1=vert) for
-- // 16-bit fonts
-+ GString *name; // PDF font name for psResidentFont16;
-+ // char collection name for psResidentFontCC
-+ int wMode; // writing mode (0=horiz, 1=vert)
- GString *psFontName; // PostScript font name
-- GString *encoding; // encoding, for 16-bit fonts only
-+ GString *encoding; // encoding
-
-- PSFontParam(GString *pdfFontNameA, int wModeA,
-- GString *psFontNameA, GString *encodingA);
-- ~PSFontParam();
-+ PSFontParam16(GString *nameA, int wModeA,
-+ GString *psFontNameA, GString *encodingA);
-+ ~PSFontParam16();
- };
-
- //------------------------------------------------------------------------
-@@ -212,9 +191,11 @@
- UnicodeMap *getResidentUnicodeMap(GString *encodingName);
- FILE *getUnicodeMapFile(GString *encodingName);
- FILE *findCMapFile(GString *collection, GString *cMapName);
- FILE *findToUnicodeFile(GString *name);
-- DisplayFontParam *getDisplayFont(GString *fontName);
-- DisplayFontParam *getDisplayCIDFont(GString *fontName, GString *collection);
-+ GString *findFontFile(GString *fontName);
-+ GString *findSystemFontFile(GString *fontName, SysFontType *type,
-+ int *fontNum);
-+ GString *findCCFontFile(GString *collection);
- GString *getPSFile();
- int getPSPaperWidth();
- int getPSPaperHeight();
-@@ -225,26 +206,34 @@
- GBool getPSShrinkLarger();
- GBool getPSCenter();
- PSLevel getPSLevel();
-- PSFontParam *getPSFont(GString *fontName);
-- PSFontParam *getPSFont16(GString *fontName, GString *collection, int wMode);
-+ GString *getPSResidentFont(GString *fontName);
-+ GList *getPSResidentFonts();
-+ PSFontParam16 *getPSResidentFont16(GString *fontName, int wMode);
-+ PSFontParam16 *getPSResidentFontCC(GString *collection, int wMode);
- GBool getPSEmbedType1();
- GBool getPSEmbedTrueType();
- GBool getPSEmbedCIDPostScript();
- GBool getPSEmbedCIDTrueType();
-+ GBool getPSFontPassthrough();
- GBool getPSPreload();
- GBool getPSOPI();
- GBool getPSASCIIHex();
-+ GBool getPSUncompressPreloadedImages();
-+ double getPSRasterResolution();
-+ GBool getPSRasterMono();
-+ GBool getPSAlwaysRasterize();
- GString *getTextEncodingName();
- EndOfLineKind getTextEOL();
- GBool getTextPageBreaks();
- GBool getTextKeepTinyChars();
-- GString *findFontFile(GString *fontName, char **exts);
- GString *getInitialZoom();
- GBool getContinuousView();
- GBool getEnableT1lib();
- GBool getEnableFreeType();
- GBool getAntialias();
- GBool getVectorAntialias();
-+ GBool getAntialiasPrinting();
- GBool getStrokeAdjust();
- ScreenType getScreenType();
- int getScreenSize();
-@@ -252,6 +241,10 @@
- double getScreenGamma();
- double getScreenBlackThreshold();
- double getScreenWhiteThreshold();
-+ double getMinLineWidth();
-+ GBool getDrawAnnotations();
- GBool getOverprintPreview() { return overprintPreview; }
- GString *getURLCommand() { return urlCommand; }
- GString *getMovieCommand() { return movieCommand; }
- GBool getMapNumericCharNames();
-@@ -268,7 +261,7 @@
-
- //----- functions to set parameters
-
-- void addDisplayFont(DisplayFontParam *param);
-+ void addFontFile(GString *fontName, GString *path);
- void setPSFile(char *file);
- GBool setPSPaperSize(char *size);
- void setPSPaperWidth(int width);
-@@ -284,6 +277,7 @@
- void setPSEmbedTrueType(GBool embed);
- void setPSEmbedCIDPostScript(GBool embed);
- void setPSEmbedCIDTrueType(GBool embed);
-+ void setPSFontPassthrough(GBool passthrough);
- void setPSPreload(GBool preload);
- void setPSOPI(GBool opi);
- void setPSASCIIHex(GBool hex);
-@@ -380,15 +374,12 @@
- GHash *cMapDirs; // list of CMap dirs, indexed by collection
- // name [GList[GString]]
- GList *toUnicodeDirs; // list of ToUnicode CMap dirs [GString]
-- GHash *displayFonts; // display font info, indexed by font name
-- // [DisplayFontParam]
--#ifdef WIN32
-- WinFontList *winFontList; // system TrueType fonts
--#endif
-- GHash *displayCIDFonts; // display CID font info, indexed by
-- // collection [DisplayFontParam]
-- GHash *displayNamedCIDFonts; // display CID font info, indexed by
-- // font name [DisplayFontParam]
-+ GHash *fontFiles; // font files: font name mapped to path
-+ // [GString]
-+ GList *fontDirs; // list of font dirs [GString]
-+ GHash *ccFontFiles; // character collection font files:
-+ // collection name mapped to path [GString]
-+ SysFontList *sysFonts; // system fonts
- GString *psFile; // PostScript file or command (for xpdf)
- int psPaperWidth; // paper size, in PostScript points, for
- int psPaperHeight; // PostScript output
-@@ -402,31 +393,44 @@
- GBool psCenter; // center pages on the paper
- GBool psDuplex; // enable duplexing in PostScript?
- PSLevel psLevel; // PostScript level to generate
-- GHash *psFonts; // PostScript font info, indexed by PDF
-- // font name [PSFontParam]
-- GList *psNamedFonts16; // named 16-bit fonts [PSFontParam]
-- GList *psFonts16; // generic 16-bit fonts [PSFontParam]
-+ GHash *psResidentFonts; // 8-bit fonts resident in printer:
-+ // PDF font name mapped to PS font name
-+ // [GString]
-+ GList *psResidentFonts16; // 16-bit fonts resident in printer:
-+ // PDF font name mapped to font info
-+ // [PSFontParam16]
-+ GList *psResidentFontsCC; // 16-bit character collection fonts
-+ // resident in printer: collection name
-+ // mapped to font info [PSFontParam16]
- GBool psEmbedType1; // embed Type 1 fonts?
- GBool psEmbedTrueType; // embed TrueType fonts?
- GBool psEmbedCIDPostScript; // embed CID PostScript fonts?
- GBool psEmbedCIDTrueType; // embed CID TrueType fonts?
-+ GBool psFontPassthrough; // pass all fonts through as-is?
- GBool psPreload; // preload PostScript images and forms into
- // memory
- GBool psOPI; // generate PostScript OPI comments?
- GBool psASCIIHex; // use ASCIIHex instead of ASCII85?
-+ GBool psUncompressPreloadedImages; // uncompress all preloaded images
-+ double psRasterResolution; // PostScript rasterization resolution (dpi)
-+ GBool psRasterMono; // true to do PostScript rasterization
-+ // in monochrome (gray); false to do it
-+ // in color (RGB/CMYK)
-+ GBool psAlwaysRasterize; // force PostScript rasterization
- GString *textEncoding; // encoding (unicodeMap) to use for text
- // output
- EndOfLineKind textEOL; // type of EOL marker to use for text
- // output
- GBool textPageBreaks; // insert end-of-page markers?
- GBool textKeepTinyChars; // keep all characters in text output
-- GList *fontDirs; // list of font dirs [GString]
- GString *initialZoom; // initial zoom level
- GBool continuousView; // continuous view mode
- GBool enableT1lib; // t1lib enable flag
- GBool enableFreeType; // FreeType enable flag
- GBool antialias; // font anti-aliasing enable flag
- GBool vectorAntialias; // vector anti-aliasing enable flag
-+ GBool antialiasPrinting; // allow anti-aliasing when printing
- GBool strokeAdjust; // stroke adjustment enable flag
- ScreenType screenType; // halftone screen type
- int screenSize; // screen matrix size
-@@ -434,6 +438,10 @@
- double screenGamma; // screen gamma correction
- double screenBlackThreshold; // screen black clamping threshold
- double screenWhiteThreshold; // screen white clamping threshold
-+ double minLineWidth; // minimum line width
- GBool overprintPreview; // enable overprint preview
- GString *urlCommand; // command executed for URL links
- GString *movieCommand; // command executed for movie annotations
- GBool mapNumericCharNames; // map numeric char names (from font subsets)?
-Només a xpdf-3.03/xpdf: OptionalContent.cc
-Només a xpdf-3.03/xpdf: OptionalContent.h
-diff -ru xpdf-3.02/xpdf/OutputDev.cc xpdf-3.03/xpdf/OutputDev.cc
---- xpdf-3.02/xpdf/OutputDev.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/OutputDev.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -65,6 +65,7 @@
- updateStrokeOpacity(state);
- updateFillOverprint(state);
- updateStrokeOverprint(state);
-+ updateOverprintMode(state);
- updateTransfer(state);
- updateFont(state);
- }
-@@ -89,6 +90,13 @@
- }
- }
-
-+void OutputDev::setSoftMaskFromImageMask(GfxState *state,
-+ Object *ref, Stream *str,
-+ int width, int height, GBool invert,
-+ GBool inlineImg) {
-+ drawImageMask(state, ref, str, width, height, invert, inlineImg);
-+}
-+
- void OutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
- int width, int height, GfxImageColorMap *colorMap,
- int *maskColors, GBool inlineImg) {
-diff -ru xpdf-3.02/xpdf/OutputDev.h xpdf-3.03/xpdf/OutputDev.h
---- xpdf-3.02/xpdf/OutputDev.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/OutputDev.h 2011-08-15 23:08:53.000000000 +0200
-@@ -19,6 +19,7 @@
- #include "CharTypes.h"
-
- class GString;
-+class Gfx;
- class GfxState;
- struct GfxColor;
- class GfxColorSpace;
-@@ -76,6 +77,11 @@
- // Does this device need non-text content?
- virtual GBool needNonText() { return gTrue; }
-
-+ // Does this device require incCharCount to be called for text on
-+ // non-shown layers?
-+ virtual GBool needCharCount() { return gFalse; }
-+
-+
- //----- initialization and control
-
- // Set default transform matrix.
-@@ -135,6 +141,7 @@
- virtual void updateStrokeOpacity(GfxState *state) {}
- virtual void updateFillOverprint(GfxState *state) {}
- virtual void updateStrokeOverprint(GfxState *state) {}
-+ virtual void updateOverprintMode(GfxState *state) {}
- virtual void updateTransfer(GfxState *state) {}
-
- //----- update text state
-@@ -147,12 +154,14 @@
- virtual void updateHorizScaling(GfxState *state) {}
- virtual void updateTextPos(GfxState *state) {}
- virtual void updateTextShift(GfxState *state, double shift) {}
-+ virtual void saveTextPos(GfxState *state) {}
-+ virtual void restoreTextPos(GfxState *state) {}
-
- //----- path painting
- virtual void stroke(GfxState *state) {}
- virtual void fill(GfxState *state) {}
- virtual void eoFill(GfxState *state) {}
-- virtual void tilingPatternFill(GfxState *state, Object *str,
-+ virtual void tilingPatternFill(GfxState *state, Gfx *gfx, Object *str,
- int paintType, Dict *resDict,
- double *mat, double *bbox,
- int x0, int y0, int x1, int y1,
-@@ -185,11 +194,18 @@
- CharCode code, Unicode *u, int uLen);
- virtual void endType3Char(GfxState *state) {}
- virtual void endTextObject(GfxState *state) {}
-+ virtual void incCharCount(int nChars) {}
-
- //----- image drawing
- virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
- int width, int height, GBool invert,
- GBool inlineImg);
-+ virtual void setSoftMaskFromImageMask(GfxState *state,
-+ Object *ref, Stream *str,
-+ int width, int height, GBool invert,
-+ GBool inlineImg);
- virtual void drawImage(GfxState *state, Object *ref, Stream *str,
- int width, int height, GfxImageColorMap *colorMap,
- int *maskColors, GBool inlineImg);
-@@ -234,11 +250,10 @@
- virtual void clearSoftMask(GfxState *state) {}
-
- //----- links
- virtual void processLink(Link *link) {}
-
- #if 1 //~tmp: turn off anti-aliasing temporarily
-- virtual GBool getVectorAntialias() { return gFalse; }
-- virtual void setVectorAntialias(GBool vaa) {}
-+ virtual void setInShading(GBool sh) {}
- #endif
-
- private:
-diff -ru xpdf-3.02/xpdf/PDFDoc.cc xpdf-3.03/xpdf/PDFDoc.cc
---- xpdf-3.02/xpdf/PDFDoc.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/PDFDoc.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -36,6 +36,7 @@
- #ifndef DISABLE_OUTLINE
- #include "Outline.h"
- #endif
-+#include "OptionalContent.h"
- #include "PDFDoc.h"
-
- //------------------------------------------------------------------------
-@@ -174,6 +199,7 @@
- #ifndef DISABLE_OUTLINE
- outline = NULL;
- #endif
-+ optContent = NULL;
- ok = setup(ownerPassword, userPassword);
- }
-
-@@ -183,38 +209,71 @@
- // check header
- checkHeader();
-
-+ // read the xref and catalog
-+ if (!PDFDoc::setup2(ownerPassword, userPassword, gFalse)) {
-+ if (errCode == errDamaged || errCode == errBadCatalog) {
-+ // try repairing the xref table
-+ error(errSyntaxWarning, -1,
-+ "PDF file is damaged - attempting to reconstruct xref table...");
-+ if (!PDFDoc::setup2(ownerPassword, userPassword, gTrue)) {
-+ return gFalse;
-+ }
-+ } else {
-+ return gFalse;
-+ }
-+ }
-+
-+#ifndef DISABLE_OUTLINE
-+ // read outline
-+ outline = new Outline(catalog->getOutline(), xref);
-+#endif
-+
-+ // read the optional content info
-+ optContent = new OptionalContent(this);
-+
-+ // done
-+ return gTrue;
-+}
-+
-+GBool PDFDoc::setup2(GString *ownerPassword, GString *userPassword,
-+ GBool repairXRef) {
- // read xref table
-- xref = new XRef(str);
-+ xref = new XRef(str, repairXRef);
- if (!xref->isOk()) {
-- error(-1, "Couldn't read xref table");
-+ error(errSyntaxError, -1, "Couldn't read xref table");
- errCode = xref->getErrorCode();
-+ delete xref;
-+ xref = NULL;
- return gFalse;
- }
-
- // check for encryption
- if (!checkEncryption(ownerPassword, userPassword)) {
- errCode = errEncrypted;
-+ delete xref;
-+ xref = NULL;
- return gFalse;
- }
-
- // read catalog
- catalog = new Catalog(this);
- if (!catalog->isOk()) {
-- error(-1, "Couldn't read page catalog");
-+ error(errSyntaxError, -1, "Couldn't read page catalog");
- errCode = errBadCatalog;
-+ delete catalog;
-+ catalog = NULL;
-+ delete xref;
-+ xref = NULL;
- return gFalse;
- }
-
--#ifndef DISABLE_OUTLINE
-- // read outline
-- outline = new Outline(catalog->getOutline(), xref);
--#endif
--
-- // done
- return gTrue;
- }
-
- PDFDoc::~PDFDoc() {
-+ if (optContent) {
-+ delete optContent;
-+ }
- #ifndef DISABLE_OUTLINE
- if (outline) {
- delete outline;
-@@ -280,7 +345,10 @@
- xref->getTrailerDict()->dictLookup("Encrypt", &encrypt);
- if ((encrypted = encrypt.isDict())) {
- if ((secHdlr = SecurityHandler::make(this, &encrypt))) {
-- if (secHdlr->checkEncryption(ownerPassword, userPassword)) {
-+ if (secHdlr->isUnencrypted()) {
-+ // no encryption
-+ ret = gTrue;
-+ } else if (secHdlr->checkEncryption(ownerPassword, userPassword)) {
- // authorization succeeded
- xref->setEncryption(secHdlr->getPermissionFlags(),
- secHdlr->getOwnerPasswordOk(),
-@@ -315,7 +383,7 @@
- printf("***** page %d *****\n", page);
- }
- catalog->getPage(page)->display(out, hDPI, vDPI,
-- rotate, useMediaBox, crop, printing, catalog,
-+ rotate, useMediaBox, crop, printing,
- abortCheckCbk, abortCheckCbkData);
- }
-
-@@ -329,6 +397,7 @@
- for (page = firstPage; page <= lastPage; ++page) {
- displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing,
- abortCheckCbk, abortCheckCbkData);
-+ catalog->doneWithPage(page);
- }
- }
-
-diff -ru xpdf-3.02/xpdf/PDFDoc.h xpdf-3.03/xpdf/PDFDoc.h
---- xpdf-3.02/xpdf/PDFDoc.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/PDFDoc.h 2011-08-15 23:08:53.000000000 +0200
-@@ -27,6 +27,8 @@
- class LinkAction;
- class LinkDest;
- class Outline;
-+class OptionalContent;
-
- //------------------------------------------------------------------------
- // PDFDoc
-@@ -128,6 +133,9 @@
- Outline *getOutline() { return outline; }
- #endif
-
-+ // Return the OptionalContent object.
-+ OptionalContent *getOptionalContent() { return optContent; }
-+
- // Is the file encrypted?
- GBool isEncrypted() { return xref->isEncrypted(); }
-
-@@ -154,27 +162,44 @@
- private:
-
- GBool setup(GString *ownerPassword, GString *userPassword);
-+ GBool setup2(GString *ownerPassword, GString *userPassword,
-+ GBool repairXRef);
- void checkHeader();
- GBool checkEncryption(GString *ownerPassword, GString *userPassword);
-
- GString *fileName;
- #ifdef WIN32
- wchar_t *fileNameU;
- #endif
- FILE *file;
- BaseStream *str;
- void *guiData;
- double pdfVersion;
- XRef *xref;
- Catalog *catalog;
- #ifndef DISABLE_OUTLINE
- Outline *outline;
- #endif
--
-+ OptionalContent *optContent;
-
- GBool ok;
- int errCode;
-diff -ru xpdf-3.02/xpdf/pdftotext.cc xpdf-3.03/xpdf/pdftotext.cc
---- xpdf-3.02/xpdf/pdftotext.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/pdftotext.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -35,7 +35,8 @@
-
- static int firstPage = 1;
- static int lastPage = 0;
- static GBool physLayout = gFalse;
-+static double fixedPitch = 0;
- static GBool rawOrder = gFalse;
- static GBool htmlMeta = gFalse;
- static char textEncName[128] = "";
-@@ -55,6 +58,8 @@
- "last page to convert"},
- {"-layout", argFlag, &physLayout, 0,
- "maintain original physical layout"},
-+ {"-fixed", argFP, &fixedPitch, 0,
-+ "assume fixed-pitch (or tabular) text"},
- {"-raw", argFlag, &rawOrder, 0,
- "keep strings in content stream order"},
- {"-htmlmeta", argFlag, &htmlMeta, 0,
-@@ -112,6 +117,9 @@
- goto err0;
- }
- fileName = new GString(argv[1]);
-+ if (fixedPitch) {
-+ physLayout = gTrue;
-+ }
-
- // read config file
- globalParams = new GlobalParams(cfgFileName);
-@@ -232,7 +241,7 @@
-
- // write text file
- textOut = new TextOutputDev(textFileName->getCString(),
-- physLayout, rawOrder, htmlMeta);
-+ physLayout, fixedPitch, rawOrder, htmlMeta);
- if (textOut->isOk()) {
- doc->displayPages(textOut, firstPage, lastPage, 72, 72, 0,
- gFalse, gTrue, gFalse);
-diff -ru xpdf-3.02/xpdf/PreScanOutputDev.cc xpdf-3.03/xpdf/PreScanOutputDev.cc
---- xpdf-3.02/xpdf/PreScanOutputDev.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/PreScanOutputDev.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -14,6 +14,8 @@
-
- #include <math.h>
- #include "GlobalParams.h"
-+#include "Page.h"
-+#include "Gfx.h"
- #include "GfxFont.h"
- #include "Link.h"
- #include "PreScanOutputDev.h"
-@@ -58,6 +60,62 @@
- state->getFillOpacity(), state->getBlendMode());
- }
-
-+void PreScanOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx,
-+ Object *str,
-+ int paintType, Dict *resDict,
-+ double *mat, double *bbox,
-+ int x0, int y0, int x1, int y1,
-+ double xStep, double yStep) {
-+ if (paintType == 1) {
-+ gfx->drawForm(str, resDict, mat, bbox);
-+ } else {
-+ check(state->getFillColorSpace(), state->getFillColor(),
-+ state->getFillOpacity(), state->getBlendMode());
-+ }
-+}
-+
-+GBool PreScanOutputDev::functionShadedFill(GfxState *state,
-+ GfxFunctionShading *shading) {
-+ if (shading->getColorSpace()->getMode() != csDeviceGray &&
-+ shading->getColorSpace()->getMode() != csCalGray) {
-+ gray = gFalse;
-+ }
-+ mono = gFalse;
-+ if (state->getFillOpacity() != 1 ||
-+ state->getBlendMode() != gfxBlendNormal) {
-+ transparency = gTrue;
-+ }
-+ return gTrue;
-+}
-+
-+GBool PreScanOutputDev::axialShadedFill(GfxState *state,
-+ GfxAxialShading *shading) {
-+ if (shading->getColorSpace()->getMode() != csDeviceGray &&
-+ shading->getColorSpace()->getMode() != csCalGray) {
-+ gray = gFalse;
-+ }
-+ mono = gFalse;
-+ if (state->getFillOpacity() != 1 ||
-+ state->getBlendMode() != gfxBlendNormal) {
-+ transparency = gTrue;
-+ }
-+ return gTrue;
-+}
-+
-+GBool PreScanOutputDev::radialShadedFill(GfxState *state,
-+ GfxRadialShading *shading) {
-+ if (shading->getColorSpace()->getMode() != csDeviceGray &&
-+ shading->getColorSpace()->getMode() != csCalGray) {
-+ gray = gFalse;
-+ }
-+ mono = gFalse;
-+ if (state->getFillOpacity() != 1 ||
-+ state->getBlendMode() != gfxBlendNormal) {
-+ transparency = gTrue;
-+ }
-+ return gTrue;
-+}
-+
- void PreScanOutputDev::clip(GfxState *state) {
- //~ check for a rectangle "near" the edge of the page;
- //~ else set gdi to false
-@@ -71,8 +129,6 @@
- int render;
- GfxFont *font;
- double m11, m12, m21, m22;
-- Ref embRef;
-- DisplayFontParam *dfp;
- GBool simpleTTF;
-
- render = state->getRender();
-@@ -87,18 +143,14 @@
-
- font = state->getFont();
- state->getFontTransMat(&m11, &m12, &m21, &m22);
-+ //~ this should check for external fonts that are non-TrueType
- simpleTTF = fabs(m11 + m22) < 0.01 &&
- m11 > 0 &&
- fabs(m12) < 0.01 &&
- fabs(m21) < 0.01 &&
- fabs(state->getHorizScaling() - 1) < 0.001 &&
- (font->getType() == fontTrueType ||
-- font->getType() == fontTrueTypeOT) &&
-- (font->getEmbeddedFontID(&embRef) ||
-- font->getExtFontFile() ||
-- (font->getName() &&
-- (dfp = globalParams->getDisplayFont(font->getName())) &&
-- dfp->kind == displayFontTT));
-+ font->getType() == fontTrueTypeOT);
- if (simpleTTF) {
- //~ need to create a FoFiTrueType object, and check for a Unicode cmap
- }
-@@ -127,6 +179,9 @@
-
- check(state->getFillColorSpace(), state->getFillColor(),
- state->getFillOpacity(), state->getBlendMode());
-+ if (state->getFillColorSpace()->getMode() == csPattern) {
-+ patternImgMask = gTrue;
-+ }
- gdi = gFalse;
-
- if (inlineImg) {
-@@ -149,12 +204,17 @@
- if (colorSpace->getMode() == csIndexed) {
- colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
- }
-- if (colorSpace->getMode() != csDeviceGray &&
-- colorSpace->getMode() != csCalGray) {
-+ if (colorSpace->getMode() == csDeviceGray ||
-+ colorSpace->getMode() == csCalGray) {
-+ if (colorMap->getBits() > 1) {
-+ mono = gFalse;
-+ }
-+ } else {
- gray = gFalse;
-+ mono = gFalse;
- }
-- mono = gFalse;
-- if (state->getBlendMode() != gfxBlendNormal) {
-+ if (state->getFillOpacity() != 1 ||
-+ state->getBlendMode() != gfxBlendNormal) {
- transparency = gTrue;
- }
- gdi = gFalse;
-@@ -182,12 +242,17 @@
- if (colorSpace->getMode() == csIndexed) {
- colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
- }
-- if (colorSpace->getMode() != csDeviceGray &&
-- colorSpace->getMode() != csCalGray) {
-+ if (colorSpace->getMode() == csDeviceGray ||
-+ colorSpace->getMode() == csCalGray) {
-+ if (colorMap->getBits() > 1) {
-+ mono = gFalse;
-+ }
-+ } else {
- gray = gFalse;
-+ mono = gFalse;
- }
-- mono = gFalse;
-- if (state->getBlendMode() != gfxBlendNormal) {
-+ if (state->getFillOpacity() != 1 ||
-+ state->getBlendMode() != gfxBlendNormal) {
- transparency = gTrue;
- }
- gdi = gFalse;
-@@ -253,5 +318,6 @@
- mono = gTrue;
- gray = gTrue;
- transparency = gFalse;
-+ patternImgMask = gFalse;
- gdi = gTrue;
- }
-diff -ru xpdf-3.02/xpdf/PreScanOutputDev.h xpdf-3.03/xpdf/PreScanOutputDev.h
---- xpdf-3.02/xpdf/PreScanOutputDev.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/PreScanOutputDev.h 2011-08-15 23:08:53.000000000 +0200
-@@ -41,6 +41,16 @@
- // Does this device use drawChar() or drawString()?
- virtual GBool useDrawChar() { return gTrue; }
-
-+ // Does this device use tilingPatternFill()? If this returns false,
-+ // tiling pattern fills will be reduced to a series of other drawing
-+ // operations.
-+ virtual GBool useTilingPatternFill() { return gTrue; }
-+
-+ // Does this device use functionShadedFill(), axialShadedFill(), and
-+ // radialShadedFill()? If this returns false, these shaded fills
-+ // will be reduced to a series of other drawing operations.
-+ virtual GBool useShadedFills() { return gTrue; }
-+
- // Does this device use beginType3Char/endType3Char? Otherwise,
- // text in Type 3 fonts will be drawn with drawChar/drawString.
- virtual GBool interpretType3Chars() { return gTrue; }
-@@ -57,6 +67,15 @@
- virtual void stroke(GfxState *state);
- virtual void fill(GfxState *state);
- virtual void eoFill(GfxState *state);
-+ virtual void tilingPatternFill(GfxState *state, Gfx *gfx, Object *str,
-+ int paintType, Dict *resDict,
-+ double *mat, double *bbox,
-+ int x0, int y0, int x1, int y1,
-+ double xStep, double yStep);
-+ virtual GBool functionShadedFill(GfxState *state,
-+ GfxFunctionShading *shading);
-+ virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading);
-+ virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading);
-
- //----- path clipping
- virtual void clip(GfxState *state);
-@@ -110,6 +129,11 @@
- GBool usesTransparency() { return transparency; }
-
- // Returns true if the operations performed since the last call to
-+ // clearStats() included any image mask fills with a pattern color
-+ // space.
-+ GBool usesPatternImageMask() { return patternImgMask; }
-+
-+ // Returns true if the operations performed since the last call to
- // clearStats() are all rasterizable by GDI calls in GDIOutputDev.
- GBool isAllGDI() { return gdi; }
-
-@@ -124,6 +148,7 @@
- GBool mono;
- GBool gray;
- GBool transparency;
-+ GBool patternImgMask;
- GBool gdi;
- };
-
-diff -ru xpdf-3.02/xpdf/PSOutputDev.cc xpdf-3.03/xpdf/PSOutputDev.cc
---- xpdf-3.02/xpdf/PSOutputDev.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/PSOutputDev.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -19,6 +19,7 @@
- #include <math.h>
- #include "GString.h"
- #include "GList.h"
-+#include "GHash.h"
- #include "config.h"
- #include "GlobalParams.h"
- #include "Object.h"
-@@ -34,8 +35,10 @@
- #include "Page.h"
- #include "Stream.h"
- #include "Annot.h"
-+#include "PDFDoc.h"
- #include "XRef.h"
- #include "PreScanOutputDev.h"
-+#include "CharCodeToUnicode.h"
- #if HAVE_SPLASH
- # include "Splash.h"
- # include "SplashBitmap.h"
-@@ -55,8 +58,8 @@
-
- //------------------------------------------------------------------------
-
--// Resolution at which pages with transparency will be rasterized.
--#define splashDPI 300
-+// Max size of a slice when rasterizing pages, in pixels.
-+#define rasterizationSliceSize 20000000
-
- //------------------------------------------------------------------------
- // PostScript prolog and setup
-@@ -82,16 +85,24 @@
- " } for",
- "~123sn",
- "/pdfSetup {",
-- " 3 1 roll 2 array astore",
- " /setpagedevice where {",
-- " pop 3 dict begin",
-+ " pop 2 dict begin",
-+ " /Policies 1 dict dup begin /PageSize 6 def end def",
-+ " { /Duplex true def } if",
-+ " currentdict end setpagedevice",
-+ " } {",
-+ " pop",
-+ " } ifelse",
-+ "} def",
-+ "/pdfSetupPaper {",
-+ " 2 array astore",
-+ " /setpagedevice where {",
-+ " pop 2 dict begin",
- " /PageSize exch def",
- " /ImagingBBox null def",
-- " /Policies 1 dict dup begin /PageSize 3 def end def",
-- " { /Duplex true def } if",
- " currentdict end setpagedevice",
- " } {",
-- " pop pop",
-+ " pop",
- " } ifelse",
- "} def",
- "~1sn",
-@@ -377,82 +388,82 @@
- "/Td { pdfTextMat transform moveto } def",
- "/Tm { /pdfTextMat exch def } def",
- "% text string operators",
-+ "/xyshow where {",
-+ " pop",
-+ " /xyshow2 {",
-+ " dup length array",
-+ " 0 2 2 index length 1 sub {",
-+ " 2 index 1 index 2 copy get 3 1 roll 1 add get",
-+ " pdfTextMat dtransform",
-+ " 4 2 roll 2 copy 6 5 roll put 1 add 3 1 roll dup 4 2 roll put",
-+ " } for",
-+ " exch pop",
-+ " xyshow",
-+ " } def",
-+ "}{",
-+ " /xyshow2 {",
-+ " currentfont /FontType get 0 eq {",
-+ " 0 2 3 index length 1 sub {",
-+ " currentpoint 4 index 3 index 2 getinterval show moveto",
-+ " 2 copy get 2 index 3 2 roll 1 add get",
-+ " pdfTextMat dtransform rmoveto",
-+ " } for",
-+ " } {",
-+ " 0 1 3 index length 1 sub {",
-+ " currentpoint 4 index 3 index 1 getinterval show moveto",
-+ " 2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get",
-+ " pdfTextMat dtransform rmoveto",
-+ " } for",
-+ " } ifelse",
-+ " pop pop",
-+ " } def",
-+ "} ifelse",
- "/cshow where {",
- " pop",
-- " /cshow2 {",
-- " dup {",
-- " pop pop",
-- " 1 string dup 0 3 index put 3 index exec",
-+ " /xycp {", // xycharpath
-+ " 0 3 2 roll",
-+ " {",
-+ " pop pop currentpoint 3 2 roll",
-+ " 1 string dup 0 4 3 roll put false charpath moveto",
-+ " 2 copy get 2 index 2 index 1 add get",
-+ " pdfTextMat dtransform rmoveto",
-+ " 2 add",
- " } exch cshow",
- " pop pop",
- " } def",
- "}{",
-- " /cshow2 {",
-+ " /xycp {", // xycharpath
- " currentfont /FontType get 0 eq {",
-- " 0 2 2 index length 1 sub {",
-- " 2 copy get exch 1 add 2 index exch get",
-- " 2 copy exch 256 mul add",
-- " 2 string dup 0 6 5 roll put dup 1 5 4 roll put",
-- " 3 index exec",
-+ " 0 2 3 index length 1 sub {",
-+ " currentpoint 4 index 3 index 2 getinterval false charpath moveto",
-+ " 2 copy get 2 index 3 2 roll 1 add get",
-+ " pdfTextMat dtransform rmoveto",
- " } for",
- " } {",
-- " dup {",
-- " 1 string dup 0 3 index put 3 index exec",
-- " } forall",
-+ " 0 1 3 index length 1 sub {",
-+ " currentpoint 4 index 3 index 1 getinterval false charpath moveto",
-+ " 2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get",
-+ " pdfTextMat dtransform rmoveto",
-+ " } for",
- " } ifelse",
- " pop pop",
- " } def",
- "} ifelse",
-- "/awcp {", // awidthcharpath
-- " exch {",
-- " false charpath",
-- " 5 index 5 index rmoveto",
-- " 6 index eq { 7 index 7 index rmoveto } if",
-- " } exch cshow2",
-- " 6 {pop} repeat",
-- "} def",
- "/Tj {",
- " fCol", // because stringwidth has to draw Type 3 chars
-- " 1 index stringwidth pdfTextMat idtransform pop",
-- " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
-- " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
-- " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
-- " pdfTextMat dtransform",
-- " 6 5 roll Tj1",
-- "} def",
-- "/Tj16 {",
-- " fCol", // because stringwidth has to draw Type 3 chars
-- " 2 index stringwidth pdfTextMat idtransform pop",
-- " sub exch div",
-- " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
-- " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
-- " pdfTextMat dtransform",
-- " 6 5 roll Tj1",
-- "} def",
-- "/Tj16V {",
-- " fCol", // because stringwidth has to draw Type 3 chars
-- " 2 index stringwidth pdfTextMat idtransform exch pop",
-- " sub exch div",
-- " 0 pdfWordSpacing pdfTextMat dtransform 32",
-- " 4 3 roll pdfCharSpacing add 0 exch",
-- " pdfTextMat dtransform",
-- " 6 5 roll Tj1",
-- "} def",
-- "/Tj1 {",
- " 0 pdfTextRise pdfTextMat dtransform rmoveto",
-- " currentpoint 8 2 roll",
-+ " currentpoint 4 2 roll",
- " pdfTextRender 1 and 0 eq {",
-- " 6 copy awidthshow",
-+ " 2 copy xyshow2",
- " } if",
- " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
-- " 7 index 7 index moveto",
-- " 6 copy",
-+ " 3 index 3 index moveto",
-+ " 2 copy",
- " currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
-- " false awcp currentpoint stroke moveto",
-+ " xycp currentpoint stroke moveto",
- " } if",
- " pdfTextRender 4 and 0 ne {",
-- " 8 6 roll moveto",
-- " false awcp",
-+ " 4 2 roll moveto xycp",
- " /pdfTextClipPath [ pdfTextClipPath aload pop",
- " {/moveto cvx}",
- " {/lineto cvx}",
-@@ -461,13 +472,13 @@
- " pathforall ] def",
- " currentpoint newpath moveto",
- " } {",
-- " 8 {pop} repeat",
-+ " pop pop pop pop",
- " } ifelse",
- " 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
- "} def",
-- "/TJm { pdfFontSize 0.001 mul mul neg 0",
-+ "/TJm { 0.001 mul pdfFontSize mul pdfHorizScaling mul neg 0",
- " pdfTextMat dtransform rmoveto } def",
-- "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
-+ "/TJmV { 0.001 mul pdfFontSize mul neg 0 exch",
- " pdfTextMat dtransform rmoveto } def",
- "/Tclip { pdfTextClipPath cvx exec clip newpath",
- " /pdfTextClipPath [] def } def",
-@@ -495,19 +506,52 @@
- " fCol /pdfImBuf1 4 index 7 add 8 idiv string def",
- " { currentfile pdfImBuf1 readhexstring pop } imagemask",
- "} def",
-+ "/pdfImStr {",
-+ " 2 copy exch length lt {",
-+ " 2 copy get exch 1 add exch",
-+ " } {",
-+ " ()",
-+ " } ifelse",
-+ "} def",
- "/pdfImM1a {",
-- " { 2 copy get exch 1 add exch } imagemask",
-+ " { pdfImStr } imagemask",
- " pop pop",
- "} def",
- "~23sn",
-- "% Level 2 image operators",
-+ "% Level 2/3 image operators",
- "/pdfImBuf 100 string def",
-- "/pdfIm {",
-- " image",
-+ "/pdfImStr {",
-+ " 2 copy exch length lt {",
-+ " 2 copy get exch 1 add exch",
-+ " } {",
-+ " ()",
-+ " } ifelse",
-+ "} def",
-+ "/skipEOD {",
- " { currentfile pdfImBuf readline",
- " not { pop exit } if",
- " (%-EOD-) eq { exit } if } loop",
- "} def",
-+ "/pdfIm { image skipEOD } def",
-+ "~3sn",
-+ "/pdfMask {",
-+ " /ReusableStreamDecode filter",
-+ " skipEOD",
-+ " /maskStream exch def",
-+ "} def",
-+ "/pdfMaskEnd { maskStream closefile } def",
-+ "/pdfMaskInit {",
-+ " /maskArray exch def",
-+ " /maskIdx 0 def",
-+ "} def",
-+ "/pdfMaskSrc {",
-+ " maskIdx maskArray length lt {",
-+ " maskArray maskIdx get",
-+ " /maskIdx maskIdx 1 add def",
-+ " } {",
-+ " ()",
-+ " } ifelse",
-+ "} def",
- "~23s",
- "/pdfImSep {",
- " findcmykcustomcolor exch",
-@@ -523,17 +567,10 @@
- " 255 exch sub put",
- " } for }",
- " 6 5 roll customcolorimage",
-- " { currentfile pdfImBuf readline",
-- " not { pop exit } if",
-- " (%-EOD-) eq { exit } if } loop",
-+ " skipEOD",
- "} def",
- "~23sn",
-- "/pdfImM {",
-- " fCol imagemask",
-- " { currentfile pdfImBuf readline",
-- " not { pop exit } if",
-- " (%-EOD-) eq { exit } if } loop",
-- "} def",
-+ "/pdfImM { fCol imagemask skipEOD } def",
- "/pr { 2 index 2 index 3 2 roll putinterval 4 add } def",
- "/pdfImClip {",
- " gsave",
-@@ -607,7 +644,7 @@
- " func n array astore",
- "} def",
- "/axialSH {",
-- " dup 0 eq {",
-+ " dup 2 lt {",
- " true",
- " } {",
- " dup 8 eq {",
-@@ -753,25 +790,12 @@
- double mWidth; // width of 'm' character
- };
-
--static char *psFonts[] = {
-- "Courier",
-- "Courier-Bold",
-- "Courier-Oblique",
-- "Courier-BoldOblique",
-- "Helvetica",
-- "Helvetica-Bold",
-- "Helvetica-Oblique",
-- "Helvetica-BoldOblique",
-- "Symbol",
-- "Times-Roman",
-- "Times-Bold",
-- "Times-Italic",
-- "Times-BoldItalic",
-- "ZapfDingbats",
-- NULL
--};
--
--static PSSubstFont psSubstFonts[] = {
-+// NB: must be in same order as base14SubstFonts in GfxFont.cc
-+static PSSubstFont psBase14SubstFonts[14] = {
-+ {"Courier", 0.600},
-+ {"Courier-Oblique", 0.600},
-+ {"Courier-Bold", 0.600},
-+ {"Courier-BoldOblique", 0.600},
- {"Helvetica", 0.833},
- {"Helvetica-Oblique", 0.833},
- {"Helvetica-Bold", 0.889},
-@@ -780,22 +804,28 @@
- {"Times-Italic", 0.722},
- {"Times-Bold", 0.833},
- {"Times-BoldItalic", 0.778},
-- {"Courier", 0.600},
-- {"Courier-Oblique", 0.600},
-- {"Courier-Bold", 0.600},
-- {"Courier-BoldOblique", 0.600}
-+ // the last two are never used for substitution
-+ {"Symbol", 0},
-+ {"ZapfDingbats", 0}
-+};
-+
-+// Mapping from Type 1/1C font file to PS font name.
-+struct PST1FontName {
-+ Ref fontFileID;
-+ GString *psName; // PostScript font name used for this
-+ // embedded font file
- };
-
- // Encoding info for substitute 16-bit font
- struct PSFont16Enc {
- Ref fontID;
-- GString *enc;
-+ GString *enc; // NULL means font wasn't correctly substituted
- };
-
- //------------------------------------------------------------------------
-@@ -845,6 +875,13 @@
- };
-
- //------------------------------------------------------------------------
-+
-+struct PSOutPaperSize {
-+ PSOutPaperSize(int wA, int hA) { w = wA; h = hA; }
-+ int w, h;
-+};
-+
-+//------------------------------------------------------------------------
- // DeviceNRecoder
- //------------------------------------------------------------------------
-
-@@ -897,6 +934,9 @@
- if (imgStr) {
- delete imgStr;
- }
-+ if (str->isEncoder()) {
-+ delete str;
-+ }
- }
-
- void DeviceNRecoder::reset() {
-@@ -942,10 +982,12 @@
- fwrite(data, 1, len, (FILE *)stream);
- }
-
- PSOutputDev::PSOutputDev(char *fileName, PDFDoc *docA,
- int firstPage, int lastPage, PSOutMode modeA,
- int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
-- GBool manualCtrlA) {
-+ GBool manualCtrlA,
-+ PSOutCustomCodeCbk customCodeCbkA,
-+ void *customCodeCbkDataA) {
- FILE *f;
- PSFileType fileTypeA;
-
-@@ -953,15 +995,18 @@
- underlayCbkData = NULL;
- overlayCbk = NULL;
- overlayCbkData = NULL;
-+ customCodeCbk = customCodeCbkA;
-+ customCodeCbkData = customCodeCbkDataA;
-
- fontIDs = NULL;
-- fontFileIDs = NULL;
-- fontFileNames = NULL;
-+ fontNames = new GHash(gTrue);
-+ t1FontNames = NULL;
- font8Info = NULL;
- font16Enc = NULL;
- imgIDs = NULL;
- formIDs = NULL;
- xobjStack = NULL;
-+ paperSizes = NULL;
- embFontList = NULL;
- customColors = NULL;
- haveTextClip = gFalse;
-@@ -978,71 +1023,82 @@
- signal(SIGPIPE, (SignalFunc)SIG_IGN);
- #endif
- if (!(f = popen(fileName + 1, "w"))) {
- error(errIO, -1, "Couldn't run print command '{0:s}'", fileName);
- ok = gFalse;
- return;
- }
- #else
- error(errIO, -1, "Print commands are not supported ('{0:s}')", fileName);
- ok = gFalse;
- return;
- #endif
- } else {
- fileTypeA = psFile;
- if (!(f = fopen(fileName, "w"))) {
- error(errIO, -1, "Couldn't open PostScript file '{0:s}'", fileName);
- ok = gFalse;
- return;
- }
- }
-
- init(outputToFile, f, fileTypeA,
-- xrefA, catalog, firstPage, lastPage, modeA,
-+ docA, firstPage, lastPage, modeA,
- imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
- }
-
- PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
- PDFDoc *docA,
- int firstPage, int lastPage, PSOutMode modeA,
- int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
-- GBool manualCtrlA) {
-+ GBool manualCtrlA,
-+ PSOutCustomCodeCbk customCodeCbkA,
-+ void *customCodeCbkDataA) {
- underlayCbk = NULL;
- underlayCbkData = NULL;
- overlayCbk = NULL;
- overlayCbkData = NULL;
-+ customCodeCbk = customCodeCbkA;
-+ customCodeCbkData = customCodeCbkDataA;
-
- fontIDs = NULL;
-- fontFileIDs = NULL;
-- fontFileNames = NULL;
-+ fontNames = new GHash(gTrue);
-+ t1FontNames = NULL;
- font8Info = NULL;
- font16Enc = NULL;
- imgIDs = NULL;
- formIDs = NULL;
- xobjStack = NULL;
-+ paperSizes = NULL;
- embFontList = NULL;
- customColors = NULL;
- haveTextClip = gFalse;
- t3String = NULL;
-
- init(outputFuncA, outputStreamA, psGeneric,
- docA, firstPage, lastPage, modeA,
- imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
- }
-
- void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
- PSFileType fileTypeA, PDFDoc *docA,
- int firstPage, int lastPage, PSOutMode modeA,
- int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
- GBool manualCtrlA) {
- Catalog *catalog;
- Page *page;
- PDFRectangle *box;
-+ PSOutPaperSize *size;
-+ GList *names;
-+ int pg, w, h, i;
-
- // initialize
- ok = gTrue;
- outputFunc = outputFuncA;
- outputStream = outputStreamA;
- fileType = fileTypeA;
- doc = docA;
- xref = doc->getXRef();
- catalog = doc->getCatalog();
- level = globalParams->getPSLevel();
- mode = modeA;
- paperWidth = globalParams->getPSPaperWidth();
-@@ -1055,18 +1111,34 @@
- globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY);
- }
- if (paperWidth < 0 || paperHeight < 0) {
-- // this check is needed in case the document has zero pages
-- if (firstPage > 0 && firstPage <= catalog->getNumPages()) {
-- page = catalog->getPage(firstPage);
-- paperWidth = (int)ceil(page->getMediaWidth());
-- paperHeight = (int)ceil(page->getMediaHeight());
-- } else {
-- paperWidth = 1;
-- paperHeight = 1;
-- }
-- imgLLX = imgLLY = 0;
-- imgURX = paperWidth;
-- imgURY = paperHeight;
-+ paperMatch = gTrue;
-+ paperSizes = new GList();
-+ paperWidth = paperHeight = 1; // in case the document has zero pages
-+ for (pg = (firstPage >= 1) ? firstPage : 1;
-+ pg <= lastPage && pg <= catalog->getNumPages();
-+ ++pg) {
-+ page = catalog->getPage(pg);
-+ w = (int)ceil(page->getMediaWidth());
-+ h = (int)ceil(page->getMediaHeight());
-+ for (i = 0; i < paperSizes->getLength(); ++i) {
-+ size = (PSOutPaperSize *)paperSizes->get(i);
-+ if (size->w == w && size->h == h) {
-+ break;
-+ }
-+ }
-+ if (i == paperSizes->getLength()) {
-+ paperSizes->append(new PSOutPaperSize(w, h));
-+ }
-+ if (w > paperWidth) {
-+ paperWidth = w;
-+ }
-+ if (h > paperHeight) {
-+ paperHeight = h;
-+ }
-+ }
-+ // NB: img{LLX,LLY,URX,URY} will be set by startPage()
-+ } else {
-+ paperMatch = gFalse;
- }
- preload = globalParams->getPSPreload();
- manualCtrl = manualCtrlA;
-@@ -1088,17 +1160,21 @@
- clipLLX0 = clipLLY0 = 0;
- clipURX0 = clipURY0 = -1;
-
-- // initialize fontIDs, fontFileIDs, and fontFileNames lists
-+ // initialize fontIDs and fontNames lists
- fontIDSize = 64;
- fontIDLen = 0;
- fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref));
-- fontFileIDSize = 64;
-- fontFileIDLen = 0;
-- fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref));
-- fontFileNameSize = 64;
-- fontFileNameLen = 0;
-- fontFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *));
-- nextTrueTypeNum = 0;
-+ for (i = 0; i < 14; ++i) {
-+ fontNames->add(new GString(psBase14SubstFonts[i].psName), 1);
-+ }
-+ names = globalParams->getPSResidentFonts();
-+ for (i = 0; i < names->getLength(); ++i) {
-+ fontNames->add((GString *)names->get(i), 1);
-+ }
-+ delete names;
-+ t1FontNameSize = 64;
-+ t1FontNameLen = 0;
-+ t1FontNames = (PST1FontName *)gmallocn(t1FontNameSize, sizeof(PST1FontName));
- font8InfoLen = 0;
- font8InfoSize = 0;
- font16EncLen = 0;
-@@ -1173,20 +1249,21 @@
- }
- #endif
- }
-+ if (paperSizes) {
-+ deleteGList(paperSizes, PSOutPaperSize);
-+ }
- if (embFontList) {
- delete embFontList;
- }
- if (fontIDs) {
- gfree(fontIDs);
- }
-- if (fontFileIDs) {
-- gfree(fontFileIDs);
-- }
-- if (fontFileNames) {
-- for (i = 0; i < fontFileNameLen; ++i) {
-- delete fontFileNames[i];
-+ delete fontNames;
-+ if (t1FontNames) {
-+ for (i = 0; i < t1FontNameLen; ++i) {
-+ delete t1FontNames[i].psName;
- }
-- gfree(fontFileNames);
-+ gfree(t1FontNames);
- }
- if (font8Info) {
- for (i = 0; i < font8InfoLen; ++i) {
-@@ -1196,7 +1273,9 @@
- }
- if (font16Enc) {
- for (i = 0; i < font16EncLen; ++i) {
-- delete font16Enc[i].enc;
-+ if (font16Enc[i].enc) {
-+ delete font16Enc[i].enc;
-+ }
- }
- gfree(font16Enc);
- }
-@@ -1216,7 +1295,9 @@
- PDFRectangle *mediaBox, PDFRectangle *cropBox,
- int pageRotate) {
- Object info, obj1;
-+ PSOutPaperSize *size;
- double x1, y1, x2, y2;
-+ int i;
-
- switch (mode) {
- case psModePS:
-@@ -1230,7 +1311,7 @@
- break;
- }
-
-- writePSFmt("% Produced by xpdf/pdftops {0:s}\n", xpdfVersion);
-+ writePSFmt("%XpdfVersion: {0:s}\n", xpdfVersion);
- xref->getDocInfo(&info);
- if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) {
- writePS("%%Creator: ");
-@@ -1254,14 +1335,24 @@
-
- switch (mode) {
- case psModePS:
-- writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n",
-- paperWidth, paperHeight);
-+ if (paperMatch) {
-+ for (i = 0; i < paperSizes->getLength(); ++i) {
-+ size = (PSOutPaperSize *)paperSizes->get(i);
-+ writePSFmt("%%{0:s} {1:d}x{2:d} {1:d} {2:d} 0 () ()\n",
-+ i==0 ? "DocumentMedia:" : "+", size->w, size->h);
-+ }
-+ } else {
-+ writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n",
-+ paperWidth, paperHeight);
-+ }
- writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight);
- writePSFmt("%%Pages: {0:d}\n", lastPage - firstPage + 1);
- writePS("%%EndComments\n");
-- writePS("%%BeginDefaults\n");
-- writePS("%%PageMedia: plain\n");
-- writePS("%%EndDefaults\n");
-+ if (!paperMatch) {
-+ writePS("%%BeginDefaults\n");
-+ writePS("%%PageMedia: plain\n");
-+ writePS("%%EndDefaults\n");
-+ }
- break;
- case psModeEPS:
- epsX1 = cropBox->x1;
-@@ -1343,7 +1434,9 @@
- Page *page;
- Dict *resDict;
- Annots *annots;
-- Object obj1, obj2;
-+ Object *acroForm;
-+ Object obj1, obj2, obj3;
-+ GString *s;
- int pg, i;
-
- if (mode == psModeForm) {
-@@ -1371,11 +1464,31 @@
- }
- delete annots;
- }
-+ if ((acroForm = catalog->getAcroForm()) && acroForm->isDict()) {
-+ if (acroForm->dictLookup("DR", &obj1)->isDict()) {
-+ setupResources(obj1.getDict());
-+ }
-+ obj1.free();
-+ if (acroForm->dictLookup("Fields", &obj1)->isArray()) {
-+ for (i = 0; i < obj1.arrayGetLength(); ++i) {
-+ if (obj1.arrayGet(i, &obj2)->isDict()) {
-+ if (obj2.dictLookup("DR", &obj3)->isDict()) {
-+ setupResources(obj3.getDict());
-+ }
-+ obj3.free();
-+ }
-+ obj2.free();
-+ }
-+ }
-+ obj1.free();
-+ }
- if (mode != psModeForm) {
- if (mode != psModeEPS && !manualCtrl) {
-- writePSFmt("{0:d} {1:d} {2:s} pdfSetup\n",
-- paperWidth, paperHeight,
-+ writePSFmt("{0:s} pdfSetup\n",
- globalParams->getPSDuplex() ? "true" : "false");
-+ if (!paperMatch) {
-+ writePSFmt("{0:d} {1:d} pdfSetupPaper\n", paperWidth, paperHeight);
-+ }
- }
- #if OPI_SUPPORT
- if (globalParams->getPSOPI()) {
-@@ -1383,6 +1496,13 @@
- }
- #endif
- }
-+ if (customCodeCbk) {
-+ if ((s = (*customCodeCbk)(this, psOutCustomDocSetup, 0,
-+ customCodeCbkData))) {
-+ writePS(s->getCString());
-+ delete s;
-+ }
-+ }
- }
-
- void PSOutputDev::writePageTrailer() {
-@@ -1558,18 +1681,15 @@
- }
-
- void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
-- Ref fontFileID;
-- GString *name;
-- PSFontParam *fontParam;
-+ GfxFontLoc *fontLoc;
- GString *psName;
-- char buf[16];
- GBool subst;
-+ char buf[16];
- UnicodeMap *uMap;
- char *charName;
- double xs, ys;
- int code;
- double w1, w2;
-- double *fm;
- int i, j;
-
- // check if font is already set up
-@@ -1587,119 +1707,120 @@
- }
- fontIDs[fontIDLen++] = *font->getID();
-
-+ psName = NULL;
- xs = ys = 1;
- subst = gFalse;
-
-- // check for resident 8-bit font
-- if (font->getName() &&
-- (fontParam = globalParams->getPSFont(font->getName()))) {
-- psName = new GString(fontParam->psFontName->getCString());
--
-- // check for embedded Type 1 font
-- } else if (globalParams->getPSEmbedType1() &&
-- font->getType() == fontType1 &&
-- font->getEmbeddedFontID(&fontFileID)) {
-- psName = filterPSName(font->getEmbeddedFontName());
-- setupEmbeddedType1Font(&fontFileID, psName);
--
-- // check for embedded Type 1C font
-- } else if (globalParams->getPSEmbedType1() &&
-- font->getType() == fontType1C &&
-- font->getEmbeddedFontID(&fontFileID)) {
-- // use the PDF font name because the embedded font name might
-- // not include the subset prefix
-- psName = filterPSName(font->getOrigName());
-- setupEmbeddedType1CFont(font, &fontFileID, psName);
--
-- // check for embedded OpenType - Type 1C font
-- } else if (globalParams->getPSEmbedType1() &&
-- font->getType() == fontType1COT &&
-- font->getEmbeddedFontID(&fontFileID)) {
-- // use the PDF font name because the embedded font name might
-- // not include the subset prefix
-- psName = filterPSName(font->getOrigName());
-- setupEmbeddedOpenTypeT1CFont(font, &fontFileID, psName);
--
-- // check for external Type 1 font file
-- } else if (globalParams->getPSEmbedType1() &&
-- font->getType() == fontType1 &&
-- font->getExtFontFile()) {
-- // this assumes that the PS font name matches the PDF font name
-- psName = font->getName()->copy();
-- setupExternalType1Font(font->getExtFontFile(), psName);
--
-- // check for embedded TrueType font
-- } else if (globalParams->getPSEmbedTrueType() &&
-- (font->getType() == fontTrueType ||
-- font->getType() == fontTrueTypeOT) &&
-- font->getEmbeddedFontID(&fontFileID)) {
-- psName = filterPSName(font->getEmbeddedFontName());
-- setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
--
-- // check for external TrueType font file
-- } else if (globalParams->getPSEmbedTrueType() &&
-- font->getType() == fontTrueType &&
-- font->getExtFontFile()) {
-- psName = filterPSName(font->getName());
-- setupExternalTrueTypeFont(font, psName);
--
-- // check for embedded CID PostScript font
-- } else if (globalParams->getPSEmbedCIDPostScript() &&
-- font->getType() == fontCIDType0C &&
-- font->getEmbeddedFontID(&fontFileID)) {
-- psName = filterPSName(font->getEmbeddedFontName());
-- setupEmbeddedCIDType0Font(font, &fontFileID, psName);
--
-- // check for embedded CID TrueType font
-- } else if (globalParams->getPSEmbedCIDTrueType() &&
-- (font->getType() == fontCIDType2 ||
-- font->getType() == fontCIDType2OT) &&
-- font->getEmbeddedFontID(&fontFileID)) {
-- psName = filterPSName(font->getEmbeddedFontName());
-- //~ should check to see if font actually uses vertical mode
-- setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue);
--
-- // check for embedded OpenType - CID CFF font
-- } else if (globalParams->getPSEmbedCIDPostScript() &&
-- font->getType() == fontCIDType0COT &&
-- font->getEmbeddedFontID(&fontFileID)) {
-- psName = filterPSName(font->getEmbeddedFontName());
-- setupEmbeddedOpenTypeCFFFont(font, &fontFileID, psName);
--
-- // check for Type 3 font
-- } else if (font->getType() == fontType3) {
-+ if (font->getType() == fontType3) {
- psName = GString::format("T3_{0:d}_{1:d}",
- font->getID()->num, font->getID()->gen);
- setupType3Font(font, psName, parentResDict);
--
-- // do 8-bit font substitution
-- } else if (!font->isCIDFont()) {
-- subst = gTrue;
-- name = font->getName();
-- psName = NULL;
-- if (name) {
-- for (i = 0; psFonts[i]; ++i) {
-- if (name->cmp(psFonts[i]) == 0) {
-- psName = new GString(psFonts[i]);
-- break;
-+ } else {
-+ fontLoc = font->locateFont(xref, gTrue);
-+ switch (fontLoc->locType) {
-+ case gfxFontLocEmbedded:
-+ switch (fontLoc->fontType) {
-+ case fontType1:
-+ // this assumes that the PS font name matches the PDF font name
-+ psName = font->getEmbeddedFontName()->copy();
-+ setupEmbeddedType1Font(&fontLoc->embFontID, psName);
-+ break;
-+ case fontType1C:
-+ psName = makePSFontName(font, &fontLoc->embFontID);
-+ setupEmbeddedType1CFont(font, &fontLoc->embFontID, psName);
-+ break;
-+ case fontType1COT:
-+ psName = makePSFontName(font, &fontLoc->embFontID);
-+ setupEmbeddedOpenTypeT1CFont(font, &fontLoc->embFontID, psName);
-+ break;
-+ case fontTrueType:
-+ case fontTrueTypeOT:
-+ psName = makePSFontName(font, font->getID());
-+ setupEmbeddedTrueTypeFont(font, &fontLoc->embFontID, psName);
-+ break;
-+ case fontCIDType0C:
-+ psName = makePSFontName(font, &fontLoc->embFontID);
-+ setupEmbeddedCIDType0Font(font, &fontLoc->embFontID, psName);
-+ break;
-+ case fontCIDType2:
-+ case fontCIDType2OT:
-+ psName = makePSFontName(font, font->getID());
-+ //~ should check to see if font actually uses vertical mode
-+ setupEmbeddedCIDTrueTypeFont(font, &fontLoc->embFontID, psName, gTrue);
-+ break;
-+ case fontCIDType0COT:
-+ psName = makePSFontName(font, &fontLoc->embFontID);
-+ setupEmbeddedOpenTypeCFFFont(font, &fontLoc->embFontID, psName);
-+ break;
-+ default:
-+ break;
-+ }
-+ break;
-+ case gfxFontLocExternal:
-+ //~ add cases for external 16-bit fonts
-+ switch (fontLoc->fontType) {
-+ case fontType1:
-+ if (font->getName()) {
-+ // this assumes that the PS font name matches the PDF font name
-+ psName = font->getName()->copy();
-+ } else {
-+ //~ this won't work -- the PS font name won't match
-+ psName = makePSFontName(font, font->getID());
- }
-+ setupExternalType1Font(fontLoc->path, psName);
-+ break;
-+ case fontTrueType:
-+ case fontTrueTypeOT:
-+ psName = makePSFontName(font, font->getID());
-+ setupExternalTrueTypeFont(font, fontLoc->path, psName);
-+ break;
-+ case fontCIDType2:
-+ case fontCIDType2OT:
-+ psName = makePSFontName(font, font->getID());
-+ //~ should check to see if font actually uses vertical mode
-+ setupExternalCIDTrueTypeFont(font, fontLoc->path, psName, gTrue);
-+ break;
-+ default:
-+ break;
- }
-+ break;
-+ case gfxFontLocResident:
-+ psName = fontLoc->path->copy();
-+ break;
- }
-+
- if (!psName) {
-- if (font->isFixedWidth()) {
-- i = 8;
-- } else if (font->isSerif()) {
-- i = 4;
-+ if (font->isCIDFont()) {
-+ error(errSyntaxError, -1,
-+ "Couldn't find a font to substitute for '{0:s}' ('{1:s}' character collection)",
-+ font->getName() ? font->getName()->getCString()
-+ : "(unnamed)",
-+ ((GfxCIDFont *)font)->getCollection()
-+ ? ((GfxCIDFont *)font)->getCollection()->getCString()
-+ : "(unknown)");
-+ if (font16EncLen >= font16EncSize) {
-+ font16EncSize += 16;
-+ font16Enc = (PSFont16Enc *)greallocn(font16Enc,
-+ font16EncSize,
-+ sizeof(PSFont16Enc));
-+ }
-+ font16Enc[font16EncLen].fontID = *font->getID();
-+ font16Enc[font16EncLen].enc = NULL;
-+ ++font16EncLen;
- } else {
-- i = 0;
-- }
-- if (font->isBold()) {
-- i += 2;
-- }
-- if (font->isItalic()) {
-- i += 1;
-+ error(errSyntaxError, -1,
-+ "Couldn't find a font to substitute for '{0:s}'",
-+ font->getName() ? font->getName()->getCString()
-+ : "(unnamed)");
- }
-- psName = new GString(psSubstFonts[i].psName);
-+ delete fontLoc;
-+ return;
-+ }
-+
-+ // scale substituted 8-bit fonts
-+ if (fontLoc->locType == gfxFontLocResident &&
-+ fontLoc->substIdx >= 0) {
-+ subst = gTrue;
- for (code = 0; code < 256; ++code) {
- if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
- charName[0] == 'm' && charName[1] == '\0') {
-@@ -1711,56 +1832,37 @@
- } else {
- w1 = 0;
- }
-- w2 = psSubstFonts[i].mWidth;
-+ w2 = psBase14SubstFonts[fontLoc->substIdx].mWidth;
- xs = w1 / w2;
- if (xs < 0.1) {
- xs = 1;
- }
-- if (font->getType() == fontType3) {
-- // This is a hack which makes it possible to substitute for some
-- // Type 3 fonts. The problem is that it's impossible to know what
-- // the base coordinate system used in the font is without actually
-- // rendering the font.
-- ys = xs;
-- fm = font->getFontMatrix();
-- if (fm[0] != 0) {
-- ys *= fm[3] / fm[0];
-- }
-- } else {
-- ys = 1;
-- }
- }
-
-- // do 16-bit font substitution
-- } else if ((fontParam = globalParams->
-- getPSFont16(font->getName(),
-- ((GfxCIDFont *)font)->getCollection(),
-- font->getWMode()))) {
-- subst = gTrue;
-- psName = fontParam->psFontName->copy();
-- if (font16EncLen >= font16EncSize) {
-- font16EncSize += 16;
-- font16Enc = (PSFont16Enc *)greallocn(font16Enc,
-- font16EncSize, sizeof(PSFont16Enc));
-- }
-- font16Enc[font16EncLen].fontID = *font->getID();
-- font16Enc[font16EncLen].enc = fontParam->encoding->copy();
-- if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) {
-- uMap->decRefCnt();
-+ // handle encodings for substituted CID fonts
-+ if (fontLoc->locType == gfxFontLocResident &&
-+ fontLoc->fontType >= fontCIDType0) {
-+ subst = gTrue;
-+ if (font16EncLen >= font16EncSize) {
-+ font16EncSize += 16;
-+ font16Enc = (PSFont16Enc *)greallocn(font16Enc,
-+ font16EncSize,
-+ sizeof(PSFont16Enc));
-+ }
-+ font16Enc[font16EncLen].fontID = *font->getID();
-+ if ((uMap = globalParams->getUnicodeMap(fontLoc->encoding))) {
-+ font16Enc[font16EncLen].enc = fontLoc->encoding->copy();
-+ uMap->decRefCnt();
-+ } else {
-+ error(errSyntaxError, -1,
-+ "Couldn't find Unicode map for 16-bit font encoding '{0:t}'",
-+ fontLoc->encoding);
-+ font16Enc[font16EncLen].enc = NULL;
-+ }
- ++font16EncLen;
-- } else {
-- error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
-- font16Enc[font16EncLen].enc->getCString());
- }
-
-- // give up - can't do anything with this font
-- } else {
-- error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
-- font->getName() ? font->getName()->getCString() : "(unnamed)",
-- ((GfxCIDFont *)font)->getCollection()
-- ? ((GfxCIDFont *)font)->getCollection()->getCString()
-- : "(unknown)");
-- return;
-+ delete fontLoc;
- }
-
- // generate PostScript code to set up the font
-@@ -1787,11 +1889,6 @@
- charName = buf;
- } else {
- charName = ((Gfx8BitFont *)font)->getCharName(i+j);
-- // this is a kludge for broken PDF files that encode char 32
-- // as .notdef
-- if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
-- charName = "space";
-- }
- }
- writePS("/");
- writePSName(charName ? charName : (char *)".notdef");
-@@ -1821,36 +1918,30 @@
- int i;
-
- // check if font is already embedded
-- for (i = 0; i < fontFileIDLen; ++i) {
-- if (fontFileIDs[i].num == id->num &&
-- fontFileIDs[i].gen == id->gen)
-- return;
-- }
--
-- // add entry to fontFileIDs list
-- if (fontFileIDLen >= fontFileIDSize) {
-- fontFileIDSize += 64;
-- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
-+ if (fontNames->lookupInt(psName)) {
-+ return;
- }
-- fontFileIDs[fontFileIDLen++] = *id;
-+ fontNames->add(psName->copy(), 1);
-
- // get the font stream and info
- refObj.initRef(id->num, id->gen);
- refObj.fetch(xref, &strObj);
- refObj.free();
- if (!strObj.isStream()) {
- error(errSyntaxError, -1, "Embedded font file object is not a stream");
- goto err1;
- }
- if (!(dict = strObj.streamGetDict())) {
- error(errSyntaxError, -1,
- "Embedded font stream is missing its dictionary");
- goto err1;
- }
- dict->lookup("Length1", &obj1);
- dict->lookup("Length2", &obj2);
- dict->lookup("Length3", &obj3);
- if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
- error(errSyntaxError, -1,
- "Missing length fields in embedded font stream dictionary");
- obj1.free();
- obj2.free();
- obj3.free();
-@@ -1947,22 +2039,12 @@
- void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) {
- FILE *fontFile;
- int c;
-- int i;
-
- // check if font is already embedded
-- for (i = 0; i < fontFileNameLen; ++i) {
-- if (!fontFileNames[i]->cmp(fileName)) {
-- return;
-- }
-- }
--
-- // add entry to fontFileNames list
-- if (fontFileNameLen >= fontFileNameSize) {
-- fontFileNameSize += 64;
-- fontFileNames = (GString **)greallocn(fontFileNames,
-- fontFileNameSize, sizeof(GString *));
-+ if (fontNames->lookupInt(psName)) {
-+ return;
- }
-- fontFileNames[fontFileNameLen++] = fileName->copy();
-+ fontNames->add(psName->copy(), 1);
-
- // beginning comment
- writePSFmt("%%BeginResource: font {0:t}\n", psName);
-@@ -1992,18 +2074,22 @@
- int i;
-
- // check if font is already embedded
-- for (i = 0; i < fontFileIDLen; ++i) {
-- if (fontFileIDs[i].num == id->num &&
-- fontFileIDs[i].gen == id->gen)
-+ for (i = 0; i < t1FontNameLen; ++i) {
-+ if (t1FontNames[i].fontFileID.num == id->num &&
-+ t1FontNames[i].fontFileID.gen == id->gen) {
-+ psName->clear();
-+ psName->insert(0, t1FontNames[i].psName);
- return;
-+ }
- }
--
-- // add entry to fontFileIDs list
-- if (fontFileIDLen >= fontFileIDSize) {
-- fontFileIDSize += 64;
-- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
-- }
-- fontFileIDs[fontFileIDLen++] = *id;
-+ if (t1FontNameLen == t1FontNameSize) {
-+ t1FontNameSize *= 2;
-+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
-+ sizeof(PST1FontName));
-+ }
-+ t1FontNames[t1FontNameLen].fontFileID = *id;
-+ t1FontNames[t1FontNameLen].psName = psName->copy();
-+ ++t1FontNameLen;
-
- // beginning comment
- writePSFmt("%%BeginResource: font {0:t}\n", psName);
-@@ -2012,13 +2098,14 @@
- embFontList->append("\n");
-
- // convert it to a Type 1 font
-- fontBuf = font->readEmbFontFile(xref, &fontLen);
-- if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
-- ffT1C->convertToType1(psName->getCString(), NULL, gTrue,
-- outputFunc, outputStream);
-- delete ffT1C;
-+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
-+ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
-+ ffT1C->convertToType1(psName->getCString(), NULL, gTrue,
-+ outputFunc, outputStream);
-+ delete ffT1C;
-+ }
-+ gfree(fontBuf);
- }
-- gfree(fontBuf);
-
- // ending comment
- writePS("%%EndResource\n");
-@@ -2032,18 +2119,22 @@
- int i;
-
- // check if font is already embedded
-- for (i = 0; i < fontFileIDLen; ++i) {
-- if (fontFileIDs[i].num == id->num &&
-- fontFileIDs[i].gen == id->gen)
-+ for (i = 0; i < t1FontNameLen; ++i) {
-+ if (t1FontNames[i].fontFileID.num == id->num &&
-+ t1FontNames[i].fontFileID.gen == id->gen) {
-+ psName->clear();
-+ psName->insert(0, t1FontNames[i].psName);
- return;
-+ }
- }
--
-- // add entry to fontFileIDs list
-- if (fontFileIDLen >= fontFileIDSize) {
-- fontFileIDSize += 64;
-- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
-- }
-- fontFileIDs[fontFileIDLen++] = *id;
-+ if (t1FontNameLen == t1FontNameSize) {
-+ t1FontNameSize *= 2;
-+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
-+ sizeof(PST1FontName));
-+ }
-+ t1FontNames[t1FontNameLen].fontFileID = *id;
-+ t1FontNames[t1FontNameLen].psName = psName->copy();
-+ ++t1FontNameLen;
-
- // beginning comment
- writePSFmt("%%BeginResource: font {0:t}\n", psName);
-@@ -2052,15 +2143,16 @@
- embFontList->append("\n");
-
- // convert it to a Type 1 font
-- fontBuf = font->readEmbFontFile(xref, &fontLen);
-- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-- if (ffTT->isOpenTypeCFF()) {
-- ffTT->convertToType1(psName->getCString(), NULL, gTrue,
-- outputFunc, outputStream);
-+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
-+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-+ if (ffTT->isOpenTypeCFF()) {
-+ ffTT->convertToType1(psName->getCString(), NULL, gTrue,
-+ outputFunc, outputStream);
-+ }
-+ delete ffTT;
- }
-- delete ffTT;
-+ gfree(fontBuf);
- }
-- gfree(fontBuf);
-
- // ending comment
- writePS("%%EndResource\n");
-@@ -2071,26 +2163,7 @@
- char *fontBuf;
- int fontLen;
- FoFiTrueType *ffTT;
- int *codeToGID;
-- int i;
--
-- // check if font is already embedded
-- for (i = 0; i < fontFileIDLen; ++i) {
-- if (fontFileIDs[i].num == id->num &&
-- fontFileIDs[i].gen == id->gen) {
-- psName->appendf("_{0:d}", nextTrueTypeNum++);
-- break;
-- }
-- }
--
-- // add entry to fontFileIDs list
-- if (i == fontFileIDLen) {
-- if (fontFileIDLen >= fontFileIDSize) {
-- fontFileIDSize += 64;
-- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
-- }
-- fontFileIDs[fontFileIDLen++] = *id;
-- }
-
- // beginning comment
- writePSFmt("%%BeginResource: font {0:t}\n", psName);
-@@ -2099,60 +2172,38 @@
- embFontList->append("\n");
-
- // convert it to a Type 42 font
-- fontBuf = font->readEmbFontFile(xref, &fontLen);
-- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-- codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
-- ffTT->convertToType42(psName->getCString(),
-- ((Gfx8BitFont *)font)->getHasEncoding()
-- ? ((Gfx8BitFont *)font)->getEncoding()
-- : (char **)NULL,
-- codeToGID, outputFunc, outputStream);
-- if (codeToGID) {
-- if (font8InfoLen >= font8InfoSize) {
-- font8InfoSize += 16;
-- font8Info = (PSFont8Info *)greallocn(font8Info,
-- font8InfoSize,
-- sizeof(PSFont8Info));
-+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
-+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-+ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
-+ ffTT->convertToType42(psName->getCString(),
-+ ((Gfx8BitFont *)font)->getHasEncoding()
-+ ? ((Gfx8BitFont *)font)->getEncoding()
-+ : (char **)NULL,
-+ codeToGID, outputFunc, outputStream);
-+ if (codeToGID) {
-+ if (font8InfoLen >= font8InfoSize) {
-+ font8InfoSize += 16;
-+ font8Info = (PSFont8Info *)greallocn(font8Info,
-+ font8InfoSize,
-+ sizeof(PSFont8Info));
-+ }
-+ font8Info[font8InfoLen].fontID = *font->getID();
-+ font8Info[font8InfoLen].codeToGID = codeToGID;
-+ ++font8InfoLen;
- }
-- font8Info[font8InfoLen].fontID = *font->getID();
-- font8Info[font8InfoLen].codeToGID = codeToGID;
-- ++font8InfoLen;
-+ delete ffTT;
- }
-- delete ffTT;
-+ gfree(fontBuf);
- }
-- gfree(fontBuf);
-
- // ending comment
- writePS("%%EndResource\n");
- }
-
--void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) {
-- GString *fileName;
-- char *fontBuf;
-- int fontLen;
-+void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *fileName,
-+ GString *psName) {
- FoFiTrueType *ffTT;
- int *codeToGID;
-- int i;
--
-- // check if font is already embedded
-- fileName = font->getExtFontFile();
-- for (i = 0; i < fontFileNameLen; ++i) {
-- if (!fontFileNames[i]->cmp(fileName)) {
-- psName->appendf("_{0:d}", nextTrueTypeNum++);
-- break;
-- }
-- }
--
-- // add entry to fontFileNames list
-- if (i == fontFileNameLen) {
-- if (fontFileNameLen >= fontFileNameSize) {
-- fontFileNameSize += 64;
-- fontFileNames =
-- (GString **)greallocn(fontFileNames,
-- fontFileNameSize, sizeof(GString *));
-- }
-- fontFileNames[fontFileNameLen++] = fileName->copy();
-- }
-
- // beginning comment
- writePSFmt("%%BeginResource: font {0:t}\n", psName);
-@@ -2161,8 +2212,7 @@
- embFontList->append("\n");
-
- // convert it to a Type 42 font
-- fontBuf = font->readExtFontFile(&fontLen);
-- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-+ if ((ffTT = FoFiTrueType::load(fileName->getCString()))) {
- codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
- ffTT->convertToType42(psName->getCString(),
- ((Gfx8BitFont *)font)->getHasEncoding()
-@@ -2182,7 +2232,6 @@
- }
- delete ffTT;
- }
-- gfree(fontBuf);
-
- // ending comment
- writePS("%%EndResource\n");
-@@ -2196,18 +2245,22 @@
- int i;
-
- // check if font is already embedded
-- for (i = 0; i < fontFileIDLen; ++i) {
-- if (fontFileIDs[i].num == id->num &&
-- fontFileIDs[i].gen == id->gen)
-+ for (i = 0; i < t1FontNameLen; ++i) {
-+ if (t1FontNames[i].fontFileID.num == id->num &&
-+ t1FontNames[i].fontFileID.gen == id->gen) {
-+ psName->clear();
-+ psName->insert(0, t1FontNames[i].psName);
- return;
-+ }
- }
--
-- // add entry to fontFileIDs list
-- if (fontFileIDLen >= fontFileIDSize) {
-- fontFileIDSize += 64;
-- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
-- }
-- fontFileIDs[fontFileIDLen++] = *id;
-+ if (t1FontNameLen == t1FontNameSize) {
-+ t1FontNameSize *= 2;
-+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
-+ sizeof(PST1FontName));
-+ }
-+ t1FontNames[t1FontNameLen].fontFileID = *id;
-+ t1FontNames[t1FontNameLen].psName = psName->copy();
-+ ++t1FontNameLen;
-
- // beginning comment
- writePSFmt("%%BeginResource: font {0:t}\n", psName);
-@@ -2216,18 +2269,21 @@
- embFontList->append("\n");
-
- // convert it to a Type 0 font
-- fontBuf = font->readEmbFontFile(xref, &fontLen);
-- if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
-- if (globalParams->getPSLevel() >= psLevel3) {
-- // Level 3: use a CID font
-- ffT1C->convertToCIDType0(psName->getCString(), 0, NULL,
-- outputFunc, outputStream);
-- } else {
-- // otherwise: use a non-CID composite font
-- ffT1C->convertToType0(psName->getCString(), 0, NULL,
-- outputFunc, outputStream);
-+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
-+ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
-+ if (globalParams->getPSLevel() >= psLevel3) {
-+ // Level 3: use a CID font
-+ ffT1C->convertToCIDType0(psName->getCString(), NULL, 0,
-+ outputFunc, outputStream);
-+ } else {
-+ // otherwise: use a non-CID composite font
-+ ffT1C->convertToType0(psName->getCString(), NULL, 0,
-+ outputFunc, outputStream);
-+ }
-+ delete ffT1C;
- }
-- delete ffT1C;
-+ gfree(fontBuf);
- }
-- gfree(fontBuf);
-
- // ending comment
- writePS("%%EndResource\n");
-@@ -2239,23 +2295,50 @@
- char *fontBuf;
- int fontLen;
- FoFiTrueType *ffTT;
-- int i;
-
-- // check if font is already embedded
-- for (i = 0; i < fontFileIDLen; ++i) {
-- if (fontFileIDs[i].num == id->num &&
-- fontFileIDs[i].gen == id->gen) {
-- psName->appendf("_{0:d}", nextTrueTypeNum++);
-- break;
-+ // beginning comment
-+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
-+ embFontList->append("%%+ font ");
-+ embFontList->append(psName->getCString());
-+ embFontList->append("\n");
-+
-+ // convert it to a Type 0 font
-+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
-+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-+ if (globalParams->getPSLevel() >= psLevel3) {
-+ // Level 3: use a CID font
-+ ffTT->convertToCIDType2(psName->getCString(),
-+ ((GfxCIDFont *)font)->getCIDToGID(),
-+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
-+ needVerticalMetrics,
-+ outputFunc, outputStream);
-+ } else {
-+ // otherwise: use a non-CID composite font
-+ ffTT->convertToType0(psName->getCString(),
-+ ((GfxCIDFont *)font)->getCIDToGID(),
-+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
-+ needVerticalMetrics,
-+ outputFunc, outputStream);
-+ }
-+ delete ffTT;
- }
-+ gfree(fontBuf);
- }
-
-- // add entry to fontFileIDs list
-- if (fontFileIDLen >= fontFileIDSize) {
-- fontFileIDSize += 64;
-- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
-- }
-- fontFileIDs[fontFileIDLen++] = *id;
-+ // ending comment
-+ writePS("%%EndResource\n");
-+}
-+
-+void PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font,
-+ GString *fileName,
-+ GString *psName,
-+ GBool needVerticalMetrics) {
-+ FoFiTrueType *ffTT;
-+ int *codeToGID;
-+ int codeToGIDLen;
-+ CharCodeToUnicode *ctu;
-+ Unicode uBuf[8];
-+ int cmap, code;
-
- // beginning comment
- writePSFmt("%%BeginResource: font {0:t}\n", psName);
-@@ -2264,26 +2347,62 @@
- embFontList->append("\n");
-
- // convert it to a Type 0 font
-- fontBuf = font->readEmbFontFile(xref, &fontLen);
-- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-- if (globalParams->getPSLevel() >= psLevel3) {
-- // Level 3: use a CID font
-- ffTT->convertToCIDType2(psName->getCString(),
-- ((GfxCIDFont *)font)->getCIDToGID(),
-- ((GfxCIDFont *)font)->getCIDToGIDLen(),
-- needVerticalMetrics,
-- outputFunc, outputStream);
-+ //~ this should use fontNum to load the correct font
-+ if ((ffTT = FoFiTrueType::load(fileName->getCString()))) {
-+
-+ // check for embedding permission
-+ if (ffTT->getEmbeddingRights() >= 1) {
-+
-+ // create a CID-to-GID mapping, via Unicode
-+ if ((ctu = ((GfxCIDFont *)font)->getToUnicode())) {
-+ // look for a Unicode cmap
-+ for (cmap = 0; cmap < ffTT->getNumCmaps(); ++cmap) {
-+ if ((ffTT->getCmapPlatform(cmap) == 3 &&
-+ ffTT->getCmapEncoding(cmap) == 1) ||
-+ ffTT->getCmapPlatform(cmap) == 0) {
-+ break;
-+ }
-+ }
-+ if (cmap < ffTT->getNumCmaps()) {
-+ // map CID -> Unicode -> GID
-+ codeToGIDLen = ctu->getLength();
-+ codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int));
-+ for (code = 0; code < codeToGIDLen; ++code) {
-+ if (ctu->mapToUnicode(code, uBuf, 8) > 0) {
-+ codeToGID[code] = ffTT->mapCodeToGID(cmap, uBuf[0]);
-+ } else {
-+ codeToGID[code] = 0;
-+ }
-+ }
-+ if (globalParams->getPSLevel() >= psLevel3) {
-+ // Level 3: use a CID font
-+ ffTT->convertToCIDType2(psName->getCString(),
-+ codeToGID, codeToGIDLen,
-+ needVerticalMetrics,
-+ outputFunc, outputStream);
-+ } else {
-+ // otherwise: use a non-CID composite font
-+ ffTT->convertToType0(psName->getCString(),
-+ codeToGID, codeToGIDLen,
-+ needVerticalMetrics,
-+ outputFunc, outputStream);
-+ }
-+ gfree(codeToGID);
-+ }
-+ ctu->decRefCnt();
-+ } else {
-+ error(errSyntaxError, -1,
-+ "Couldn't find a mapping to Unicode for font '{0:s}'",
-+ font->getName() ? font->getName()->getCString() : "(unnamed)");
-+ }
- } else {
-- // otherwise: use a non-CID composite font
-- ffTT->convertToType0(psName->getCString(),
-- ((GfxCIDFont *)font)->getCIDToGID(),
-- ((GfxCIDFont *)font)->getCIDToGIDLen(),
-- needVerticalMetrics,
-- outputFunc, outputStream);
-+ error(errSyntaxError, -1,
-+ "TrueType font '%s' does not allow embedding",
-+ font->getName() ? font->getName()->getCString() : "(unnamed)");
-+
- }
- delete ffTT;
- }
-- gfree(fontBuf);
-
- // ending comment
- writePS("%%EndResource\n");
-@@ -2297,18 +2416,22 @@
- int i;
-
- // check if font is already embedded
-- for (i = 0; i < fontFileIDLen; ++i) {
-- if (fontFileIDs[i].num == id->num &&
-- fontFileIDs[i].gen == id->gen)
-+ for (i = 0; i < t1FontNameLen; ++i) {
-+ if (t1FontNames[i].fontFileID.num == id->num &&
-+ t1FontNames[i].fontFileID.gen == id->gen) {
-+ psName->clear();
-+ psName->insert(0, t1FontNames[i].psName);
- return;
-+ }
- }
--
-- // add entry to fontFileIDs list
-- if (fontFileIDLen >= fontFileIDSize) {
-- fontFileIDSize += 64;
-- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
-- }
-- fontFileIDs[fontFileIDLen++] = *id;
-+ if (t1FontNameLen == t1FontNameSize) {
-+ t1FontNameSize *= 2;
-+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
-+ sizeof(PST1FontName));
-+ }
-+ t1FontNames[t1FontNameLen].fontFileID = *id;
-+ t1FontNames[t1FontNameLen].psName = psName->copy();
-+ ++t1FontNameLen;
-
- // beginning comment
- writePSFmt("%%BeginResource: font {0:t}\n", psName);
-@@ -2317,21 +2440,27 @@
- embFontList->append("\n");
-
- // convert it to a Type 0 font
-- fontBuf = font->readEmbFontFile(xref, &fontLen);
-- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-- if (ffTT->isOpenTypeCFF()) {
-- if (globalParams->getPSLevel() >= psLevel3) {
-- // Level 3: use a CID font
-- ffTT->convertToCIDType0(psName->getCString(),
-- ((GfxCIDFont *)font)->getCIDToGID(),
-- ((GfxCIDFont *)font)->getCIDToGIDLen(),
-- outputFunc, outputStream);
-- } else {
-- // otherwise: use a non-CID composite font
-- ffTT->convertToType0(psName->getCString(),
-- ((GfxCIDFont *)font)->getCIDToGID(),
-- ((GfxCIDFont *)font)->getCIDToGIDLen(),
-- outputFunc, outputStream);
-+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
-+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-+ if (ffTT->isOpenTypeCFF()) {
-+ if (globalParams->getPSLevel() >= psLevel3) {
-+ // Level 3: use a CID font
-+ ffTT->convertToCIDType0(psName->getCString(),
-+ ((GfxCIDFont *)font)->getCIDToGID(),
-+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
-+ outputFunc, outputStream);
-+ } else {
-+ // otherwise: use a non-CID composite font
-+ ffTT->convertToType0(psName->getCString(),
-+ ((GfxCIDFont *)font)->getCIDToGID(),
-+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
-+ outputFunc, outputStream);
-+ }
- }
-+ delete ffTT;
- }
-- delete ffTT;
-+ gfree(fontBuf);
- }
-- gfree(fontBuf);
-
- // ending comment
- writePS("%%EndResource\n");
-@@ -2390,9 +2519,10 @@
- box.y1 = m[1];
- box.x2 = m[2];
- box.y2 = m[3];
- gfx = new Gfx(doc, this, resDict, &box, NULL);
- inType3Char = gTrue;
- for (i = 0; i < charProcs->getLength(); ++i) {
-+ t3FillColorOnly = gFalse;
- t3Cacheable = gFalse;
- t3NeedsRestore = gFalse;
- writePS("/");
-@@ -2430,9 +2560,45 @@
- writePS("%%EndResource\n");
- }
-
-+// Make a unique PS font name, based on the names given in the PDF
-+// font object, and an object ID (font file object for
-+GString *PSOutputDev::makePSFontName(GfxFont *font, Ref *id) {
-+ GString *psName, *s;
-+
-+ if ((s = font->getEmbeddedFontName())) {
-+ psName = filterPSName(s);
-+ if (!fontNames->lookupInt(psName)) {
-+ fontNames->add(psName->copy(), 1);
-+ return psName;
-+ }
-+ delete psName;
-+ }
-+ if ((s = font->getName())) {
-+ psName = filterPSName(s);
-+ if (!fontNames->lookupInt(psName)) {
-+ fontNames->add(psName->copy(), 1);
-+ return psName;
-+ }
-+ delete psName;
-+ }
-+ psName = GString::format("FF{0:d}_{1:d}", id->num, id->gen);
-+ if ((s = font->getEmbeddedFontName())) {
-+ s = filterPSName(s);
-+ psName->append('_')->append(s);
-+ delete s;
-+ } else if ((s = font->getName())) {
-+ s = filterPSName(s);
-+ psName->append('_')->append(s);
-+ delete s;
-+ }
-+ fontNames->add(psName->copy(), 1);
-+ return psName;
-+}
-+
- void PSOutputDev::setupImages(Dict *resDict) {
-- Object xObjDict, xObj, xObjRef, subtypeObj;
-- int i;
-+ Object xObjDict, xObj, xObjRef, subtypeObj, maskObj, maskRef;
-+ Ref imgID;
-+ int i, j;
-
- if (!(mode == psModeForm || inType3Char || preload)) {
- return;
-@@ -2447,9 +2613,32 @@
- xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
- if (subtypeObj.isName("Image")) {
- if (xObjRef.isRef()) {
-- setupImage(xObjRef.getRef(), xObj.getStream());
-+ imgID = xObjRef.getRef();
-+ for (j = 0; j < imgIDLen; ++j) {
-+ if (imgIDs[j].num == imgID.num && imgIDs[j].gen == imgID.gen) {
-+ break;
-+ }
-+ }
-+ if (j == imgIDLen) {
-+ if (imgIDLen >= imgIDSize) {
-+ if (imgIDSize == 0) {
-+ imgIDSize = 64;
-+ } else {
-+ imgIDSize *= 2;
-+ }
-+ imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref));
-+ }
-+ imgIDs[imgIDLen++] = imgID;
-+ setupImage(imgID, xObj.getStream(), gFalse);
-+ if (level >= psLevel3 &&
-+ xObj.streamGetDict()->lookup("Mask", &maskObj)->isStream()) {
-+ setupImage(imgID, maskObj.getStream(), gTrue);
-+ }
-+ maskObj.free();
-+ }
- } else {
- error(errSyntaxError, -1,
- "Image in resource dict is not an indirect reference");
- }
- }
- subtypeObj.free();
-@@ -2461,30 +2650,12 @@
- xObjDict.free();
- }
-
--void PSOutputDev::setupImage(Ref id, Stream *str) {
-+void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
- GBool useRLE, useCompressed, useASCIIHex;
- GString *s;
- int c;
- int size, line, col, i;
-
-- // check if image is already setup
-- for (i = 0; i < imgIDLen; ++i) {
-- if (imgIDs[i].num == id.num && imgIDs[i].gen == id.gen) {
-- return;
-- }
-- }
--
-- // add entry to imgIDs list
-- if (imgIDLen >= imgIDSize) {
-- if (imgIDSize == 0) {
-- imgIDSize = 64;
-- } else {
-- imgIDSize *= 2;
-- }
-- imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref));
-- }
-- imgIDs[imgIDLen++] = id;
--
- // filters
- //~ this does not correctly handle the DeviceN color space
- //~ -- need to use DeviceNRecoder
-@@ -2493,17 +2664,21 @@
- useCompressed = gFalse;
- useASCIIHex = gTrue;
- } else {
-- s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
-- if (s) {
-+ if (globalParams->getPSUncompressPreloadedImages()) {
- useRLE = gFalse;
-- useCompressed = gTrue;
-- delete s;
-- } else {
-- useRLE = gTrue;
- useCompressed = gFalse;
-+ } else {
-+ s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
-+ if (s) {
-+ useRLE = gFalse;
-+ useCompressed = gTrue;
-+ delete s;
-+ } else {
-+ useRLE = gTrue;
-+ useCompressed = gFalse;
-+ }
- }
-- useASCIIHex = level == psLevel1 || level == psLevel1Sep ||
-- globalParams->getPSASCIIHex();
-+ useASCIIHex = globalParams->getPSASCIIHex();
- }
- if (useCompressed) {
- str = str->getUndecodedStream();
-@@ -2552,8 +2727,8 @@
- if (useRLE) {
- ++size;
- }
-- writePSFmt("{0:d} array dup /ImData_{1:d}_{2:d} exch def\n",
-- size, id.num, id.gen);
-+ writePSFmt("{0:d} array dup /{1:s}Data_{2:d}_{3:d} exch def\n",
-+ size, mask ? "Mask" : "Im", id.num, id.gen);
- str->close();
-
- // write the data into the array
-@@ -2722,12 +2898,14 @@
- int rotateA, GBool useMediaBox, GBool crop,
- int sliceX, int sliceY,
- int sliceW, int sliceH,
- GBool printing,
- GBool (*abortCheckCbk)(void *data),
- void *abortCheckCbkData) {
--#if HAVE_SPLASH
- PreScanOutputDev *scan;
- GBool rasterize;
-+#if HAVE_SPLASH
-+ GBool mono;
-+ double dpi;
- SplashOutputDev *splashOut;
- SplashColor paperColor;
- PDFRectangle box;
-@@ -2737,43 +2915,33 @@
- Object obj;
- Guchar *p;
- Guchar col[4];
-+ double hDPI2, vDPI2;
- double m0, m1, m2, m3, m4, m5;
-+ int nStripes, stripeH, stripeY;
- int c, w, h, x, y, comp, i;
-+#endif
-
-- scan = new PreScanOutputDev();
-- page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop,
-- sliceX, sliceY, sliceW, sliceH,
-- printing, catalog, abortCheckCbk, abortCheckCbkData);
-- rasterize = scan->usesTransparency();
-- delete scan;
-+ if (globalParams->getPSAlwaysRasterize()) {
-+ rasterize = gTrue;
-+ } else {
-+ scan = new PreScanOutputDev();
-+ page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop,
-+ sliceX, sliceY, sliceW, sliceH,
-+ printing, abortCheckCbk, abortCheckCbkData);
-+ rasterize = scan->usesTransparency() || scan->usesPatternImageMask();
-+ delete scan;
-+ }
- if (!rasterize) {
- return gTrue;
- }
-
-- // rasterize the page
-- if (level == psLevel1) {
-- paperColor[0] = 0xff;
-- splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse,
-- paperColor, gTrue, gFalse);
--#if SPLASH_CMYK
-- } else if (level == psLevel1Sep) {
-- paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0;
-- splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse,
-- paperColor, gTrue, gFalse);
--#endif
-- } else {
-- paperColor[0] = paperColor[1] = paperColor[2] = 0xff;
-- splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse,
-- paperColor, gTrue, gFalse);
-- }
-- splashOut->startDoc(xref);
-- page->displaySlice(splashOut, splashDPI, splashDPI, rotateA,
-- useMediaBox, crop,
-- sliceX, sliceY, sliceW, sliceH,
-- printing, catalog, abortCheckCbk, abortCheckCbkData);
-+#if HAVE_SPLASH
-+ // get the rasterization parameters
-+ dpi = globalParams->getPSRasterResolution();
-+ mono = globalParams->getPSRasterMono();
-
- // start the PS page
-- page->makeBox(splashDPI, splashDPI, rotateA, useMediaBox, gFalse,
-+ page->makeBox(dpi, dpi, rotateA, useMediaBox, gFalse,
- sliceX, sliceY, sliceW, sliceH, &box, &crop);
- rotateA += page->getRotate();
- if (rotateA >= 360) {
-@@ -2781,166 +2949,215 @@
- } else if (rotateA < 0) {
- rotateA += 360;
- }
-- state = new GfxState(splashDPI, splashDPI, &box, rotateA, gFalse);
-- startPage(page->getNum(), state);
-- delete state;
-- switch (rotateA) {
-- case 0:
-- default: // this should never happen
-+ state = new GfxState(dpi, dpi, &box, rotateA, gFalse);
-+ startPage(page->getNum(), state);
-+ delete state;
-+
-+ // set up the SplashOutputDev
-+ if (mono || level == psLevel1) {
-+ paperColor[0] = 0xff;
-+ splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse,
-+ paperColor, gFalse,
-+ globalParams->getAntialiasPrinting());
-+#if SPLASH_CMYK
-+ } else if (level == psLevel1Sep) {
-+ paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0;
-+ splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse,
-+ paperColor, gFalse,
-+ globalParams->getAntialiasPrinting());
-+#endif
-+ } else {
-+ paperColor[0] = paperColor[1] = paperColor[2] = 0xff;
-+ splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse,
-+ paperColor, gFalse,
-+ globalParams->getAntialiasPrinting());
-+ }
-+ splashOut->startDoc(xref);
-+
-+ // break the page into stripes
-+ hDPI2 = xScale * dpi;
-+ vDPI2 = yScale * dpi;
-+ if (sliceW < 0 || sliceH < 0) {
-+ if (useMediaBox) {
-+ box = *page->getMediaBox();
-+ } else {
-+ box = *page->getCropBox();
-+ }
-+ sliceX = sliceY = 0;
-+ sliceW = (int)((box.x2 - box.x1) * hDPI2 / 72.0);
-+ sliceH = (int)((box.y2 - box.y1) * vDPI2 / 72.0);
-+ }
-+ nStripes = (int)ceil((double)(sliceW * sliceH) /
-+ (double)rasterizationSliceSize);
-+ stripeH = (sliceH + nStripes - 1) / nStripes;
-+
-+ // render the stripes
-+ for (stripeY = sliceY; stripeY < sliceH; stripeY += stripeH) {
-+
-+ // rasterize a stripe
-+ page->makeBox(hDPI2, vDPI2, 0, useMediaBox, gFalse,
-+ sliceX, stripeY, sliceW, stripeH, &box, &crop);
- m0 = box.x2 - box.x1;
- m1 = 0;
- m2 = 0;
- m3 = box.y2 - box.y1;
- m4 = box.x1;
- m5 = box.y1;
-- break;
-- case 90:
-- m0 = 0;
-- m1 = box.y2 - box.y1;
-- m2 = -(box.x2 - box.x1);
-- m3 = 0;
-- m4 = box.x2;
-- m5 = box.y1;
-- break;
-- case 180:
-- m0 = -(box.x2 - box.x1);
-- m1 = 0;
-- m2 = 0;
-- m3 = -(box.y2 - box.y1);
-- m4 = box.x2;
-- m5 = box.y2;
-- break;
-- case 270:
-- m0 = 0;
-- m1 = -(box.y2 - box.y1);
-- m2 = box.x2 - box.x1;
-- m3 = 0;
-- m4 = box.x1;
-- m5 = box.y2;
-- break;
-- }
--
-- //~ need to add the process colors
--
-- // draw the rasterized image
-- bitmap = splashOut->getBitmap();
-- w = bitmap->getWidth();
-- h = bitmap->getHeight();
-- writePS("gsave\n");
-- writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] concat\n",
-- m0, m1, m2, m3, m4, m5);
-- switch (level) {
-- case psLevel1:
-- writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
-- w, h, w, -h, h);
-- p = bitmap->getDataPtr();
-- i = 0;
-- for (y = 0; y < h; ++y) {
-- for (x = 0; x < w; ++x) {
-- writePSFmt("{0:02x}", *p++);
-- if (++i == 32) {
-- writePSChar('\n');
-- i = 0;
-- }
-- }
-- }
-- if (i != 0) {
-- writePSChar('\n');
-- }
-- break;
-- case psLevel1Sep:
-- writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
-- w, h, w, -h, h);
-- p = bitmap->getDataPtr();
-- i = 0;
-- col[0] = col[1] = col[2] = col[3] = 0;
-- for (y = 0; y < h; ++y) {
-- for (comp = 0; comp < 4; ++comp) {
-+ page->displaySlice(splashOut, hDPI2, vDPI2,
-+ (360 - page->getRotate()) % 360, useMediaBox, crop,
-+ sliceX, stripeY, sliceW, stripeH,
-+ printing, abortCheckCbk, abortCheckCbkData);
-+
-+ // draw the rasterized image
-+ bitmap = splashOut->getBitmap();
-+ w = bitmap->getWidth();
-+ h = bitmap->getHeight();
-+ writePS("gsave\n");
-+ writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
-+ m0, m1, m2, m3, m4, m5);
-+ switch (level) {
-+ case psLevel1:
-+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
-+ w, h, w, -h, h);
-+ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
-+ i = 0;
-+ for (y = 0; y < h; ++y) {
- for (x = 0; x < w; ++x) {
-- writePSFmt("{0:02x}", p[4*x + comp]);
-- col[comp] |= p[4*x + comp];
-+ writePSFmt("{0:02x}", *p++);
- if (++i == 32) {
- writePSChar('\n');
- i = 0;
- }
- }
- }
-- p += bitmap->getRowSize();
-- }
-- if (i != 0) {
-+ if (i != 0) {
-+ writePSChar('\n');
-+ }
-+ break;
-+ case psLevel1Sep:
-+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
-+ w, h, w, -h, h);
-+ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
-+ i = 0;
-+ col[0] = col[1] = col[2] = col[3] = 0;
-+ for (y = 0; y < h; ++y) {
-+ for (comp = 0; comp < 4; ++comp) {
-+ for (x = 0; x < w; ++x) {
-+ writePSFmt("{0:02x}", p[4*x + comp]);
-+ col[comp] |= p[4*x + comp];
-+ if (++i == 32) {
-+ writePSChar('\n');
-+ i = 0;
-+ }
-+ }
-+ }
-+ p -= bitmap->getRowSize();
-+ }
-+ if (i != 0) {
-+ writePSChar('\n');
-+ }
-+ if (col[0]) {
-+ processColors |= psProcessCyan;
-+ }
-+ if (col[1]) {
-+ processColors |= psProcessMagenta;
-+ }
-+ if (col[2]) {
-+ processColors |= psProcessYellow;
-+ }
-+ if (col[3]) {
-+ processColors |= psProcessBlack;
-+ }
-+ break;
-+ case psLevel2:
-+ case psLevel2Sep:
-+ case psLevel3:
-+ case psLevel3Sep:
-+ if (mono) {
-+ writePS("/DeviceGray setcolorspace\n");
-+ } else {
-+ writePS("/DeviceRGB setcolorspace\n");
-+ }
-+ writePS("<<\n /ImageType 1\n");
-+ writePSFmt(" /Width {0:d}\n", bitmap->getWidth());
-+ writePSFmt(" /Height {0:d}\n", bitmap->getHeight());
-+ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
-+ writePS(" /BitsPerComponent 8\n");
-+ if (mono) {
-+ writePS(" /Decode [0 1]\n");
-+ } else {
-+ writePS(" /Decode [0 1 0 1 0 1]\n");
-+ }
-+ writePS(" /DataSource currentfile\n");
-+ if (globalParams->getPSASCIIHex()) {
-+ writePS(" /ASCIIHexDecode filter\n");
-+ } else {
-+ writePS(" /ASCII85Decode filter\n");
-+ }
-+ writePS(" /RunLengthDecode filter\n");
-+ writePS(">>\n");
-+ writePS("image\n");
-+ obj.initNull();
-+ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
-+ str0 = new MemStream((char *)p, 0, w * h * (mono ? 1 : 3), &obj);
-+ str = new RunLengthEncoder(str0);
-+ if (globalParams->getPSASCIIHex()) {
-+ str = new ASCIIHexEncoder(str);
-+ } else {
-+ str = new ASCII85Encoder(str);
-+ }
-+ str->reset();
-+ while ((c = str->getChar()) != EOF) {
-+ writePSChar(c);
-+ }
-+ str->close();
-+ delete str;
-+ delete str0;
- writePSChar('\n');
-+ processColors |= mono ? psProcessBlack : psProcessCMYK;
-+ break;
- }
-- if (col[0]) {
-- processColors |= psProcessCyan;
-- }
-- if (col[1]) {
-- processColors |= psProcessMagenta;
-- }
-- if (col[2]) {
-- processColors |= psProcessYellow;
-- }
-- if (col[3]) {
-- processColors |= psProcessBlack;
-- }
-- break;
-- case psLevel2:
-- case psLevel2Sep:
-- case psLevel3:
-- case psLevel3Sep:
-- writePS("/DeviceRGB setcolorspace\n");
-- writePS("<<\n /ImageType 1\n");
-- writePSFmt(" /Width {0:d}\n", bitmap->getWidth());
-- writePSFmt(" /Height {0:d}\n", bitmap->getHeight());
-- writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
-- writePS(" /BitsPerComponent 8\n");
-- writePS(" /Decode [0 1 0 1 0 1]\n");
-- writePS(" /DataSource currentfile\n");
-- if (globalParams->getPSASCIIHex()) {
-- writePS(" /ASCIIHexDecode filter\n");
-- } else {
-- writePS(" /ASCII85Decode filter\n");
-- }
-- writePS(" /RunLengthDecode filter\n");
-- writePS(">>\n");
-- writePS("image\n");
-- obj.initNull();
-- str0 = new MemStream((char *)bitmap->getDataPtr(), 0, w * h * 3, &obj);
-- str = new RunLengthEncoder(str0);
-- if (globalParams->getPSASCIIHex()) {
-- str = new ASCIIHexEncoder(str);
-- } else {
-- str = new ASCII85Encoder(str);
-- }
-- str->reset();
-- while ((c = str->getChar()) != EOF) {
-- writePSChar(c);
-- }
-- str->close();
-- delete str;
-- delete str0;
-- processColors |= psProcessCMYK;
-- break;
-+ writePS("grestore\n");
- }
-+
- delete splashOut;
-- writePS("grestore\n");
-
- // finish the PS page
- endPage();
-
- return gFalse;
--#else
-+
-+#else // HAVE_SPLASH
-+
-+ error(errSyntaxWarning, -1,
-+ "PDF page uses transparency and PSOutputDev was built without"
-+ " the Splash rasterizer - output may not be correct");
- return gTrue;
--#endif
-+#endif // HAVE_SPLASH
- }
-
- void PSOutputDev::startPage(int pageNum, GfxState *state) {
-- int x1, y1, x2, y2, width, height;
-+ Page *page;
-+ int x1, y1, x2, y2, width, height, t;
- int imgWidth, imgHeight, imgWidth2, imgHeight2;
- GBool landscape;
--
-+ GString *s;
-
- if (mode == psModePS) {
- writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage);
-+ if (paperMatch) {
-+ page = doc->getCatalog()->getPage(pageNum);
-+ imgLLX = imgLLY = 0;
-+ imgURX = (int)ceil(page->getMediaWidth());
-+ imgURY = (int)ceil(page->getMediaHeight());
-+ if (state->getRotate() == 90 || state->getRotate() == 270) {
-+ t = imgURX;
-+ imgURX = imgURY;
-+ imgURY = t;
-+ }
-+ writePSFmt("%%PageMedia: {0:d}x{1:d}\n", imgURX, imgURY);
-+ writePSFmt("%%PageBoundingBox: 0 0 {0:d} {1:d}\n", imgURX, imgURY);
-+ }
- writePS("%%BeginPageSetup\n");
- }
-
-@@ -2966,20 +3183,25 @@
- height = y2 - y1;
- tx = ty = 0;
- // rotation and portrait/landscape mode
-- if (rotate0 >= 0) {
-+ if (paperMatch) {
-+ rotate = (360 - state->getRotate()) % 360;
-+ landscape = gFalse;
-+ } else if (rotate0 >= 0) {
- rotate = (360 - rotate0) % 360;
- landscape = gFalse;
- } else {
- rotate = (360 - state->getRotate()) % 360;
- if (rotate == 0 || rotate == 180) {
-- if (width > height && width > imgWidth) {
-+ if ((width < height && imgWidth > imgHeight && height > imgHeight) ||
-+ (width > height && imgWidth < imgHeight && width > imgWidth)) {
- rotate += 90;
- landscape = gTrue;
- } else {
- landscape = gFalse;
- }
- } else { // rotate == 90 || rotate == 270
-- if (height > width && height > imgWidth) {
-+ if ((height < width && imgWidth > imgHeight && width > imgHeight) ||
-+ (height > width && imgWidth < imgHeight && height > imgWidth)) {
- rotate = 270 - rotate;
- landscape = gTrue;
- } else {
-@@ -2989,6 +3211,9 @@
- }
- writePSFmt("%%PageOrientation: {0:s}\n",
- landscape ? "Landscape" : "Portrait");
-+ if (paperMatch) {
-+ writePSFmt("{0:d} {1:d} pdfSetupPaper\n", imgURX, imgURY);
-+ }
- writePS("pdfStartPage\n");
- if (rotate == 0) {
- imgWidth2 = imgWidth;
-@@ -3015,9 +3240,9 @@
- xScale = xScale0;
- yScale = yScale0;
- } else if ((globalParams->getPSShrinkLarger() &&
-- (width > imgWidth2 || height > imgHeight2)) ||
-- (globalParams->getPSExpandSmaller() &&
-- (width < imgWidth2 && height < imgHeight2))) {
-+ (width > imgWidth2 || height > imgHeight2)) ||
-+ (globalParams->getPSExpandSmaller() &&
-+ (width < imgWidth2 && height < imgHeight2))) {
- xScale = (double)imgWidth2 / (double)width;
- yScale = (double)imgHeight2 / (double)height;
- if (yScale < xScale) {
-@@ -3038,8 +3263,8 @@
- }
- // center
- if (tx0 >= 0 && ty0 >= 0) {
-- tx += rotate == 0 ? tx0 : ty0;
-- ty += rotate == 0 ? ty0 : -tx0;
-+ tx += (rotate == 0 || rotate == 180) ? tx0 : ty0;
-+ ty += (rotate == 0 || rotate == 180) ? ty0 : -tx0;
- } else if (globalParams->getPSCenter()) {
- if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
- tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2;
-@@ -3049,22 +3274,21 @@
- ty += (imgHeight2 - yScale * height) / 2;
- }
- }
-- tx += rotate == 0 ? imgLLX : imgLLY;
-- ty += rotate == 0 ? imgLLY : -imgLLX;
-+ tx += (rotate == 0 || rotate == 180) ? imgLLX : imgLLY;
-+ ty += (rotate == 0 || rotate == 180) ? imgLLY : -imgLLX;
- if (tx != 0 || ty != 0) {
- writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty);
- }
- if (xScale != 1 || yScale != 1) {
- writePSFmt("{0:.6f} {1:.6f} scale\n", xScale, yScale);
- }
- if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
- writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re W\n",
- clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0);
- } else {
- writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1);
- }
-
-- writePS("%%EndPageSetup\n");
- ++seqPage;
- break;
-
-@@ -3101,6 +3325,18 @@
- rotate = 0;
- break;
- }
-+
-+ if (customCodeCbk) {
-+ if ((s = (*customCodeCbk)(this, psOutCustomPageSetup, pageNum,
-+ customCodeCbkData))) {
-+ writePS(s->getCString());
-+ delete s;
-+ }
-+ }
-+
-+ if (mode == psModePS) {
-+ writePS("%%EndPageSetup\n");
-+ }
- }
-
- void PSOutputDev::endPage() {
-@@ -3458,25 +3693,33 @@
-+void PSOutputDev::saveTextPos(GfxState *state) {
-+ writePS("currentpoint\n");
-+}
-+
-+void PSOutputDev::restoreTextPos(GfxState *state) {
-+ writePS("m\n");
-+}
-+
- void PSOutputDev::stroke(GfxState *state) {
- doPath(state->getPath());
-- if (t3String) {
-- // if we're construct a cacheable Type 3 glyph, we need to do
-+ if (inType3Char && t3FillColorOnly) {
-+ // if we're constructing a cacheable Type 3 glyph, we need to do
- // everything in the fill color
- writePS("Sf\n");
- } else {
-@@ -3494,19 +3737,19 @@
- writePS("f*\n");
- }
-
--void PSOutputDev::tilingPatternFill(GfxState *state, Object *str,
-+void PSOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str,
- int paintType, Dict *resDict,
- double *mat, double *bbox,
- int x0, int y0, int x1, int y1,
- double xStep, double yStep) {
- PDFRectangle box;
-- Gfx *gfx;
-+ Gfx *gfx2;
-
- // define a Type 3 font
- writePS("8 dict begin\n");
- writePS("/FontType 3 def\n");
- writePS("/FontMatrix [1 0 0 1 0 0] def\n");
- writePSFmt("/FontBBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}] def\n",
- bbox[0], bbox[1], bbox[2], bbox[3]);
- writePS("/Encoding 256 array def\n");
- writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
-@@ -3526,34 +3769,37 @@
- box.y1 = bbox[1];
- box.x2 = bbox[2];
- box.y2 = bbox[3];
- gfx = new Gfx(doc, this, resDict, &box, NULL);
- writePS("/x {\n");
- if (paintType == 2) {
- writePSFmt("{0:.6g} 0 {1:.6g} {2:.6g} {3:.6g} {4:.6g} setcachedevice\n",
- xStep, bbox[0], bbox[1], bbox[2], bbox[3]);
-+ t3FillColorOnly = gTrue;
- } else {
- if (x1 - 1 <= x0) {
- writePS("1 0 setcharwidth\n");
- } else {
- writePSFmt("{0:.6g} 0 setcharwidth\n", xStep);
- }
-+ t3FillColorOnly = gFalse;
- }
- inType3Char = gTrue;
- ++numTilingPatterns;
-- gfx->display(str);
-+ gfx2->display(str);
- --numTilingPatterns;
- inType3Char = gFalse;
- writePS("} def\n");
-- delete gfx;
-+ delete gfx2;
- writePS("end\n");
- writePS("currentdict end\n");
- writePSFmt("/xpdfTile{0:d} exch definefont pop\n", numTilingPatterns);
-
- // draw the tiles
- writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns);
-+ writePS("fCol\n");
- writePSFmt("gsave [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
- mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
- writePSFmt("{0:d} 1 {1:d} {{ {2:.6g} exch {3:.6g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n",
- y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1);
- writePS("grestore\n");
- }
-@@ -3698,7 +3944,10 @@
- double xMin, yMin, xMax, yMax;
- double x0, y0, r0, x1, y1, r1, t0, t1;
- double xa, ya, ra;
-- double sz, xz, yz, sMin, sMax, sa, ta;
-+ double sz, sMin, sMax, h, ta;
-+ double sLeft, sRight, sTop, sBottom, sZero, sDiag;
-+ GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero;
-+ GBool haveSMin, haveSMax;
- double theta, alpha, a1, a2;
- GBool enclosed;
- int i;
-@@ -3717,19 +3966,23 @@
-
- // Compute the point at which r(s) = 0; check for the enclosed
- // circles case; and compute the angles for the tangent lines.
-- if (r0 == r1) {
-- enclosed = x0 == x1 && y0 == y1;
-+ h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
-+ 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) {
-+ enclosed = gTrue;
-+ theta = 0; // make gcc happy
-+ sz = 0; // make gcc happy
- } else {
-+ enclosed = gFalse;
- sz = -r0 / (r1 - r0);
-- xz = x0 + sz * (x1 - x0);
-- yz = y0 + sz * (y1 - y0);
-- enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
-- theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
-- if (r0 > r1) {
-- theta = -theta;
-- }
-+ theta = asin((r1 - r0) / h);
- }
- if (enclosed) {
- a1 = 0;
-@@ -3749,80 +4002,122 @@
- sMin = 0;
- sMax = 1;
- } else {
-- sMin = 1;
-- sMax = 0;
-- // solve for x(s) + r(s) = xMin
-- if ((x1 + r1) - (x0 + r0) != 0) {
-- sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
-- if (sa < sMin) {
-- sMin = sa;
-- } else if (sa > sMax) {
-- sMax = sa;
-- }
-- }
-- // solve for x(s) - r(s) = xMax
-- if ((x1 - r1) - (x0 - r0) != 0) {
-- sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
-- if (sa < sMin) {
-- sMin = sa;
-- } else if (sa > sMax) {
-- sMax = sa;
-- }
-- }
-- // solve for y(s) + r(s) = yMin
-- if ((y1 + r1) - (y0 + r0) != 0) {
-- sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
-- if (sa < sMin) {
-- sMin = sa;
-- } else if (sa > sMax) {
-- sMax = sa;
-- }
-- }
-- // solve for y(s) - r(s) = yMax
-- if ((y1 - r1) - (y0 - r0) != 0) {
-- sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
-- if (sa < sMin) {
-- sMin = sa;
-- } else if (sa > sMax) {
-- sMax = sa;
-- }
-- }
-- // check against sz
-- if (r0 < r1) {
-- if (sMin < sz) {
-- sMin = sz;
-- }
-- } else if (r0 > r1) {
-- if (sMax > sz) {
-- sMax = sz;
-- }
-+ // solve x(sLeft) + r(sLeft) = xMin
-+ if ((haveSLeft = fabs((x1 + r1) - (x0 + r0)) > 0.000001)) {
-+ sLeft = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
-+ } else {
-+ sLeft = 0; // make gcc happy
-+ }
-+ // solve x(sRight) - r(sRight) = xMax
-+ if ((haveSRight = fabs((x1 - r1) - (x0 - r0)) > 0.000001)) {
-+ sRight = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
-+ } else {
-+ sRight = 0; // make gcc happy
-+ }
-+ // solve y(sBottom) + r(sBottom) = yMin
-+ if ((haveSBottom = fabs((y1 + r1) - (y0 + r0)) > 0.000001)) {
-+ sBottom = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
-+ } else {
-+ sBottom = 0; // make gcc happy
-+ }
-+ // solve y(sTop) - r(sTop) = yMax
-+ if ((haveSTop = fabs((y1 - r1) - (y0 - r0)) > 0.000001)) {
-+ sTop = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
-+ } else {
-+ sTop = 0; // make gcc happy
-+ }
-+ // solve r(sZero) = 0
-+ if ((haveSZero = fabs(r1 - r0) > 0.000001)) {
-+ sZero = -r0 / (r1 - r0);
-+ } else {
-+ sZero = 0; // make gcc happy
-+ }
-+ // solve r(sDiag) = sqrt((xMax-xMin)^2 + (yMax-yMin)^2)
-+ if (haveSZero) {
-+ sDiag = (sqrt((xMax - xMin) * (xMax - xMin) +
-+ (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
-+ } else {
-+ sDiag = 0; // make gcc happy
- }
-- // check the 'extend' flags
-- if (!shading->getExtend0() && sMin < 0) {
-+ // compute sMin
-+ if (shading->getExtend0()) {
-+ sMin = 0;
-+ haveSMin = gFalse;
-+ if (x0 < x1 && haveSLeft && sLeft < 0) {
-+ sMin = sLeft;
-+ haveSMin = gTrue;
-+ } else if (x0 > x1 && haveSRight && sRight < 0) {
-+ sMin = sRight;
-+ haveSMin = gTrue;
-+ }
-+ if (y0 < y1 && haveSBottom && sBottom < 0) {
-+ if (!haveSMin || sBottom > sMin) {
-+ sMin = sBottom;
-+ haveSMin = gTrue;
-+ }
-+ } else if (y0 > y1 && haveSTop && sTop < 0) {
-+ if (!haveSMin || sTop > sMin) {
-+ sMin = sTop;
-+ haveSMin = gTrue;
-+ }
-+ }
-+ if (haveSZero && sZero < 0) {
-+ if (!haveSMin || sZero > sMin) {
-+ sMin = sZero;
-+ }
-+ }
-+ } else {
- sMin = 0;
- }
-- if (!shading->getExtend1() && sMax > 1) {
-+ // compute sMax
-+ if (shading->getExtend1()) {
-+ sMax = 1;
-+ haveSMax = gFalse;
-+ if (x1 < x0 && haveSLeft && sLeft > 1) {
-+ sMax = sLeft;
-+ haveSMax = gTrue;
-+ } else if (x1 > x0 && haveSRight && sRight > 1) {
-+ sMax = sRight;
-+ haveSMax = gTrue;
-+ }
-+ if (y1 < y0 && haveSBottom && sBottom > 1) {
-+ if (!haveSMax || sBottom < sMax) {
-+ sMax = sBottom;
-+ haveSMax = gTrue;
-+ }
-+ } else if (y1 > y0 && haveSTop && sTop > 1) {
-+ if (!haveSMax || sTop < sMax) {
-+ sMax = sTop;
-+ haveSMax = gTrue;
-+ }
-+ }
-+ if (haveSZero && sDiag > 1) {
-+ if (!haveSMax || sDiag < sMax) {
-+ sMax = sDiag;
-+ }
-+ }
-+ } else {
- sMax = 1;
- }
- }
-
- // generate the PS code
-@@ -3970,15 +4265,16 @@
- GString *s2;
-- double dx, dy, dx2, dy2, originX, originY;
-+ double dx, dy, originX, originY;
- char *p;
- UnicodeMap *uMap;
- CharCode code;
- Unicode u[8];
- char buf[8];
-- int len, nChars, uLen, n, m, i, j;
-+ double *dxdy;
-+ int dxdySize, len, nChars, uLen, n, m, i, j;
-
- // check for invisible text -- this is used by Acrobat Capture
- if (state->getRender() == 3) {
-@@ -4003,6 +4299,10 @@
- for (i = 0; i < font16EncLen; ++i) {
- if (font->getID()->num == font16Enc[i].fontID.num &&
- font->getID()->gen == font16Enc[i].fontID.gen) {
-+ if (!font16Enc[i].enc) {
-+ // font substitution failed, so don't output any text
-+ return;
-+ }
- uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
- break;
- }
-@@ -4019,63 +4319,89 @@
- }
- }
-
-- // compute width of chars in string, ignoring char spacing and word
-- // spacing -- the Tj operator will adjust for the metrics of the
-- // font that's actually used
-- dx = dy = 0;
-+ // compute the positioning (dx, dy) for each char in the string
- nChars = 0;
- p = s->getCString();
- len = s->getLength();
- s2 = new GString();
-+ dxdySize = font->isCIDFont() ? 8 : s->getLength();
-+ dxdy = (double *)gmallocn(2 * dxdySize, sizeof(double));
- while (len > 0) {
- n = font->getNextChar(p, len, &code,
- u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
-- &dx2, &dy2, &originX, &originY);
-+ &dx, &dy, &originX, &originY);
-+ dx *= state->getFontSize();
-+ dy *= state->getFontSize();
-+ if (wMode) {
-+ dy += state->getCharSpace();
-+ if (n == 1 && *p == ' ') {
-+ dy += state->getWordSpace();
-+ }
-+ } else {
-+ dx += state->getCharSpace();
-+ if (n == 1 && *p == ' ') {
-+ dx += state->getWordSpace();
-+ }
-+ }
-+ dx *= state->getHorizScaling();
- if (font->isCIDFont()) {
- if (uMap) {
-+ if (nChars + uLen > dxdySize) {
-+ do {
-+ dxdySize *= 2;
-+ } while (nChars + uLen > dxdySize);
-+ dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double));
-+ }
- for (i = 0; i < uLen; ++i) {
- m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
- for (j = 0; j < m; ++j) {
- s2->append(buf[j]);
- }
-+ //~ this really needs to get the number of chars in the target
-+ //~ encoding - which may be more than the number of Unicode
-+ //~ chars
-+ dxdy[2 * nChars] = dx;
-+ dxdy[2 * nChars + 1] = dy;
-+ ++nChars;
- }
-- //~ this really needs to get the number of chars in the target
-- //~ encoding - which may be more than the number of Unicode
-- //~ chars
-- nChars += uLen;
- } else {
-+ if (nChars + 1 > dxdySize) {
-+ dxdySize *= 2;
-+ dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double));
-+ }
- s2->append((char)((code >> 8) & 0xff));
- s2->append((char)(code & 0xff));
-+ dxdy[2 * nChars] = dx;
-+ dxdy[2 * nChars + 1] = dy;
- ++nChars;
- }
- } else {
- if (!codeToGID || codeToGID[code] >= 0) {
- s2->append((char)code);
-+ dxdy[2 * nChars] = dx;
-+ dxdy[2 * nChars + 1] = dy;
-+ ++nChars;
- }
- }
-- dx += dx2;
-- dy += dy2;
- p += n;
- len -= n;
- }
-- dx *= state->getFontSize() * state->getHorizScaling();
-- dy *= state->getFontSize();
- if (uMap) {
- uMap->decRefCnt();
- }
-
-- if (s2->getLength() > 0) {
-+ if (nChars > 0) {
- writePSString(s2);
-- if (font->isCIDFont()) {
-- if (wMode) {
-- writePSFmt(" {0:d} {1:.4g} Tj16V\n", nChars, dy);
-- } else {
-- writePSFmt(" {0:d} {1:.4g} Tj16\n", nChars, dx);
-+ writePS("\n[");
-+ for (i = 0; i < 2 * nChars; ++i) {
-+ if (i > 0) {
-+ writePS("\n");
- }
-- } else {
-- writePSFmt(" {0:.4g} Tj\n", dx);
-+ writePSFmt("{0:.6g}", dxdy[i]);
- }
-+ writePS("] Tj\n");
- }
-+ gfree(dxdy);
- delete s2;
-
- if (state->getRender() & 4) {
-@@ -4730,24 +5056,32 @@
-
- // data source
- if (mode == psModeForm || inType3Char || preload) {
-- writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
-+ writePS(" /DataSource { pdfImStr }\n");
- } else {
- writePS(" /DataSource currentfile\n");
- }
-
- // filters
-- s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
-- " ");
-- if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
-- inlineImg || !s) {
-- useRLE = gTrue;
-- useASCII = !(mode == psModeForm || inType3Char || preload);
-+ if ((mode == psModeForm || inType3Char || preload) &&
-+ globalParams->getPSUncompressPreloadedImages()) {
-+ s = NULL;
-+ useRLE = gFalse;
- useCompressed = gFalse;
-+ useASCII = gFalse;
- } else {
-- useRLE = gFalse;
-- useASCII = str->isBinary() &&
-- !(mode == psModeForm || inType3Char || preload);
-- useCompressed = gTrue;
-+ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
-+ " ");
-+ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
-+ inlineImg || !s) {
-+ useRLE = gTrue;
-+ useASCII = !(mode == psModeForm || inType3Char || preload);
-+ useCompressed = gFalse;
-+ } else {
-+ useRLE = gFalse;
-+ useASCII = str->isBinary() &&
-+ !(mode == psModeForm || inType3Char || preload);
-+ useCompressed = gTrue;
-+ }
- }
- if (useASCII) {
- writePSFmt(" /ASCII{0:s}Decode filter\n",
-@@ -4872,6 +5206,7 @@
- int n, numComps;
- GBool useRLE, useASCII, useASCIIHex, useCompressed;
- GBool maskUseRLE, maskUseASCII, maskUseCompressed;
-+ GString *maskFilters;
- GfxSeparationColorSpace *sepCS;
- GfxColor color;
- GfxCMYK cmyk;
-@@ -4881,6 +5216,83 @@
- useASCIIHex = globalParams->getPSASCIIHex();
- useRLE = useASCII = useCompressed = gFalse; // make gcc happy
- maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy
-+ maskFilters = NULL; // make gcc happy
-+
-+ // explicit masking
-+ if (maskStr) {
-+
-+ // mask data source
-+ if ((mode == psModeForm || inType3Char || preload) &&
-+ globalParams->getPSUncompressPreloadedImages()) {
-+ s = NULL;
-+ maskUseRLE = gFalse;
-+ maskUseCompressed = gFalse;
-+ maskUseASCII = gFalse;
-+ } else {
-+ s = maskStr->getPSFilter(3, " ");
-+ if (!s) {
-+ maskUseRLE = gTrue;
-+ maskUseASCII = !(mode == psModeForm || inType3Char || preload);
-+ maskUseCompressed = gFalse;
-+ } else {
-+ maskUseRLE = gFalse;
-+ maskUseASCII = maskStr->isBinary() &&
-+ !(mode == psModeForm || inType3Char || preload);
-+ maskUseCompressed = gTrue;
-+ }
-+ }
-+ maskFilters = new GString();
-+ if (maskUseASCII) {
-+ maskFilters->appendf(" /ASCII{0:s}Decode filter\n",
-+ useASCIIHex ? "Hex" : "85");
-+ }
-+ if (maskUseRLE) {
-+ maskFilters->append(" /RunLengthDecode filter\n");
-+ }
-+ if (maskUseCompressed) {
-+ maskFilters->append(s);
-+ }
-+ if (s) {
-+ delete s;
-+ }
-+ if (mode == psModeForm || inType3Char || preload) {
-+ writePSFmt("MaskData_{0:d}_{1:d} pdfMaskInit\n",
-+ ref->getRefNum(), ref->getRefGen());
-+ } else {
-+ writePS("currentfile\n");
-+ writePS(maskFilters->getCString());
-+ writePS("pdfMask\n");
-+
-+ // add RunLengthEncode and ASCIIHex/85 encode filters
-+ if (maskUseCompressed) {
-+ maskStr = maskStr->getUndecodedStream();
-+ }
-+ if (maskUseRLE) {
-+ maskStr = new RunLengthEncoder(maskStr);
-+ }
-+ if (maskUseASCII) {
-+ if (useASCIIHex) {
-+ maskStr = new ASCIIHexEncoder(maskStr);
-+ } else {
-+ maskStr = new ASCII85Encoder(maskStr);
-+ }
-+ }
-+
-+ // copy the stream data
-+ maskStr->reset();
-+ while ((c = maskStr->getChar()) != EOF) {
-+ writePSChar(c);
-+ }
-+ maskStr->close();
-+ writePSChar('\n');
-+ writePS("%-EOD-\n");
-+
-+ // delete encoders
-+ if (maskUseRLE || maskUseASCII) {
-+ delete maskStr;
-+ }
-+ }
-+ }
-
- // color space
- if (colorMap) {
-@@ -5015,24 +5427,32 @@
-
- // data source
- if (mode == psModeForm || inType3Char || preload) {
-- writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
-+ writePS(" /DataSource { pdfImStr }\n");
- } else {
- writePS(" /DataSource currentfile\n");
- }
-
- // filters
-- s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
-- " ");
-- if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
-- inlineImg || !s) {
-- useRLE = gTrue;
-- useASCII = !(mode == psModeForm || inType3Char || preload);
-+ if ((mode == psModeForm || inType3Char || preload) &&
-+ globalParams->getPSUncompressPreloadedImages()) {
-+ s = NULL;
-+ useRLE = gFalse;
- useCompressed = gFalse;
-+ useASCII = gFalse;
- } else {
-- useRLE = gFalse;
-- useASCII = str->isBinary() &&
-- !(mode == psModeForm || inType3Char || preload);
-- useCompressed = gTrue;
-+ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
-+ " ");
-+ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
-+ inlineImg || !s) {
-+ useRLE = gTrue;
-+ useASCII = !(mode == psModeForm || inType3Char || preload);
-+ useCompressed = gFalse;
-+ } else {
-+ useRLE = gFalse;
-+ useASCII = str->isBinary() &&
-+ !(mode == psModeForm || inType3Char || preload);
-+ useCompressed = gTrue;
-+ }
- }
- if (useASCII) {
- writePSFmt(" /ASCII{0:s}Decode filter\n",
-@@ -5065,30 +5485,13 @@
- maskInvert ? 1 : 0, maskInvert ? 0 : 1);
-
- // mask data source
-- writePS(" /DataSource currentfile\n");
-- s = maskStr->getPSFilter(3, " ");
-- if (!s) {
-- maskUseRLE = gTrue;
-- maskUseASCII = gTrue;
-- maskUseCompressed = gFalse;
-+ if (mode == psModeForm || inType3Char || preload) {
-+ writePS(" /DataSource {pdfMaskSrc}\n");
-+ writePS(maskFilters->getCString());
- } else {
-- maskUseRLE = gFalse;
-- maskUseASCII = maskStr->isBinary();
-- maskUseCompressed = gTrue;
-- }
-- if (maskUseASCII) {
-- writePSFmt(" /ASCII{0:s}Decode filter\n",
-- useASCIIHex ? "Hex" : "85");
-- }
-- if (maskUseRLE) {
-- writePS(" /RunLengthDecode filter\n");
-- }
-- if (maskUseCompressed) {
-- writePS(s->getCString());
-- }
-- if (s) {
-- delete s;
-+ writePS(" /DataSource maskStream\n");
- }
-+ delete maskFilters;
-
- writePS(">>\n");
- writePS(">>\n");
-@@ -5116,39 +5519,6 @@
-
- }
-
-- // explicit masking
-- if (maskStr) {
--
-- if (maskUseCompressed) {
-- maskStr = maskStr->getUndecodedStream();
-- }
--
-- // add RunLengthEncode and ASCIIHex/85 encode filters
-- if (maskUseRLE) {
-- maskStr = new RunLengthEncoder(maskStr);
-- }
-- if (maskUseASCII) {
-- if (useASCIIHex) {
-- maskStr = new ASCIIHexEncoder(maskStr);
-- } else {
-- maskStr = new ASCII85Encoder(maskStr);
-- }
-- }
--
-- // copy the stream data
-- maskStr->reset();
-- while ((c = maskStr->getChar()) != EOF) {
-- writePSChar(c);
-- }
-- maskStr->close();
-- writePSChar('\n');
--
-- // delete encoders
-- if (maskUseRLE || maskUseASCII) {
-- delete maskStr;
-- }
-- }
--
- // get rid of the array and index
- if (mode == psModeForm || inType3Char || preload) {
- writePS("pop pop\n");
-@@ -5196,6 +5566,13 @@
- delete str;
- }
- }
-+
-+ // close the mask stream
-+ if (maskStr) {
-+ if (!(mode == psModeForm || inType3Char || preload)) {
-+ writePS("pdfMaskEnd\n");
-+ }
-+ }
- }
-
- void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
-@@ -5898,6 +6275,7 @@
- t3URY = ury;
- t3String = new GString();
- writePS("q\n");
-+ t3FillColorOnly = gTrue;
- t3Cacheable = gTrue;
- t3NeedsRestore = gTrue;
- }
-diff -ru xpdf-3.02/xpdf/PSOutputDev.h xpdf-3.03/xpdf/PSOutputDev.h
---- xpdf-3.02/xpdf/PSOutputDev.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/PSOutputDev.h 2011-08-15 23:08:53.000000000 +0200
-@@ -21,15 +21,20 @@
- #include "GlobalParams.h"
- #include "OutputDev.h"
-
-+class GHash;
-+class PDFDoc;
-+class XRef;
- class Function;
- class GfxPath;
- class GfxFont;
- class GfxColorSpace;
- class GfxSeparationColorSpace;
- class PDFRectangle;
-+struct PST1FontName;
- struct PSFont8Info;
- struct PSFont16Enc;
- class PSOutCustomColor;
-+class PSOutputDev;
-
- //------------------------------------------------------------------------
- // PSOutputDev
-@@ -48,25 +53,38 @@
- psGeneric // write to a generic stream
- };
-
--typedef void (*PSOutputFunc)(void *stream, const char *data, int len);
-+enum PSOutCustomCodeLocation {
-+ psOutCustomDocSetup,
-+ psOutCustomPageSetup
-+};
-+
-+typedef void (*PSOutputFunc)(void *stream, const char *data, int len);
-+
-+typedef GString *(*PSOutCustomCodeCbk)(PSOutputDev *psOut,
-+ PSOutCustomCodeLocation loc, int n,
-+ void *data);
-
- class PSOutputDev: public OutputDev {
- public:
-
- // Open a PostScript output file, and write the prolog.
- PSOutputDev(char *fileName, PDFDoc *docA,
- int firstPage, int lastPage, PSOutMode modeA,
- int imgLLXA = 0, int imgLLYA = 0,
- int imgURXA = 0, int imgURYA = 0,
-- GBool manualCtrlA = gFalse);
-+ GBool manualCtrlA = gFalse,
-+ PSOutCustomCodeCbk customCodeCbkA = NULL,
-+ void *customCodeCbkDataA = NULL);
-
- // Open a PSOutputDev that will write to a generic stream.
- PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
- PDFDoc *docA,
- int firstPage, int lastPage, PSOutMode modeA,
- int imgLLXA = 0, int imgLLYA = 0,
- int imgURXA = 0, int imgURYA = 0,
-- GBool manualCtrlA = gFalse);
-+ GBool manualCtrlA = gFalse,
-+ PSOutCustomCodeCbk customCodeCbkA = NULL,
-+ void *customCodeCbkDataA = NULL);
-
- // Destructor -- writes the trailer and closes the file.
- virtual ~PSOutputDev();
-@@ -171,12 +189,14 @@
- virtual void updateHorizScaling(GfxState *state);
- virtual void updateTextPos(GfxState *state);
- virtual void updateTextShift(GfxState *state, double shift);
-+ virtual void saveTextPos(GfxState *state);
-+ virtual void restoreTextPos(GfxState *state);
-
- //----- path painting
- virtual void stroke(GfxState *state);
- virtual void fill(GfxState *state);
- virtual void eoFill(GfxState *state);
-- virtual void tilingPatternFill(GfxState *state, Object *str,
-+ virtual void tilingPatternFill(GfxState *state, Gfx *gfx, Object *str,
- int paintType, Dict *resDict,
- double *mat, double *bbox,
- int x0, int y0, int x1, int y1,
-@@ -244,10 +264,10 @@
- private:
-
- void init(PSOutputFunc outputFuncA, void *outputStreamA,
- PSFileType fileTypeA, PDFDoc *docA,
- int firstPage, int lastPage, PSOutMode modeA,
- int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
- GBool manualCtrlA);
-@@ -256,14 +282,20 @@
- void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName);
- void setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, GString *psName);
- void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName);
-- void setupExternalTrueTypeFont(GfxFont *font, GString *psName);
-+ void setupExternalTrueTypeFont(GfxFont *font, GString *fileName,
-+ GString *psName);
- void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName);
- void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName,
- GBool needVerticalMetrics);
-+ void setupExternalCIDTrueTypeFont(GfxFont *font,
-+ GString *fileName,
-+ GString *psName,
-+ GBool needVerticalMetrics);
- void setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, GString *psName);
- void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict);
-+ GString *makePSFontName(GfxFont *font, Ref *id);
- void setupImages(Dict *resDict);
-- void setupImage(Ref id, Stream *str);
-+ void setupImage(Ref id, Stream *str, GBool mask);
- void setupForms(Dict *resDict);
- void setupForm(Ref id, Object *strObj);
- void addProcessColor(double c, double m, double y, double k);
-@@ -308,6 +335,7 @@
- PSOutMode mode; // PostScript mode (PS, EPS, form)
- int paperWidth; // width of paper, in pts
- int paperHeight; // height of paper, in pts
-+ GBool paperMatch; // true if paper size is set to match each page
- int imgLLX, imgLLY, // imageable area, in pts
- imgURX, imgURY;
- GBool preload; // load all images into memory, and
-@@ -322,20 +350,21 @@
- void *underlayCbkData;
- void (*overlayCbk)(PSOutputDev *psOut, void *data);
- void *overlayCbkData;
-+ GString *(*customCodeCbk)(PSOutputDev *psOut,
-+ PSOutCustomCodeLocation loc, int n,
-+ void *data);
-+ void *customCodeCbkData;
-
- PDFDoc *doc;
- XRef *xref; // the xref table for this PDF file
-
- Ref *fontIDs; // list of object IDs of all used fonts
- int fontIDLen; // number of entries in fontIDs array
- int fontIDSize; // size of fontIDs array
-- Ref *fontFileIDs; // list of object IDs of all embedded fonts
-- int fontFileIDLen; // number of entries in fontFileIDs array
-- int fontFileIDSize; // size of fontFileIDs array
-- GString **fontFileNames; // list of names of all embedded external fonts
-- int fontFileNameLen; // number of entries in fontFileNames array
-- int fontFileNameSize; // size of fontFileNames array
-- int nextTrueTypeNum; // next unique number to append to a TrueType
-- // font name
-+ GHash *fontNames; // all used font names
-+ PST1FontName *t1FontNames; // font names for Type 1/1C fonts
-+ int t1FontNameLen; // number of entries in t1FontNames array
-+ int t1FontNameSize; // size of t1FontNames array
- PSFont8Info *font8Info; // info for 8-bit fonts
- int font8InfoLen; // number of entries in font8Info array
- int font8InfoSize; // size of font8Info array
-@@ -354,6 +383,8 @@
- int numTilingPatterns; // current number of nested tiling patterns
- int nextFunc; // next unique number to use for a function
-
-+ GList *paperSizes; // list of used paper sizes, if paperMatch
-+ // is true [PSOutPaperSize]
- double tx0, ty0; // global translation
- double xScale0, yScale0; // global scaling
- int rotate0; // rotation angle (0, 90, 180, 270)
-@@ -378,6 +409,7 @@
- GString *t3String; // Type 3 content string
- double t3WX, t3WY, // Type 3 character parameters
- t3LLX, t3LLY, t3URX, t3URY;
-+ GBool t3FillColorOnly; // operators should only use the fill color
- GBool t3Cacheable; // cleared if char is not cacheable
- GBool t3NeedsRestore; // set if a 'q' operator was issued
-
-@@ -388,7 +420,6 @@
-
- GBool ok; // set up ok?
-
--
- friend class WinPDFPrinter;
- };
-
-diff -ru xpdf-3.02/xpdf/SplashOutputDev.cc xpdf-3.03/xpdf/SplashOutputDev.cc
---- xpdf-3.02/xpdf/SplashOutputDev.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/SplashOutputDev.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -14,14 +14,18 @@
-
- #include <string.h>
- #include <math.h>
-+#include <limits.h>
- #include "gfile.h"
- #include "GlobalParams.h"
- #include "Error.h"
- #include "Object.h"
-+#include "Gfx.h"
- #include "GfxFont.h"
- #include "Link.h"
- #include "CharCodeToUnicode.h"
- #include "FontEncodingTables.h"
-+#include "BuiltinFont.h"
-+#include "BuiltinFontTables.h"
- #include "FoFiTrueType.h"
- #include "SplashBitmap.h"
- #include "SplashGlyphBitmap.h"
-@@ -45,6 +49,13 @@
-
- //------------------------------------------------------------------------
-
-+// Type 3 font cache size parameters
-+#define type3FontCacheAssoc 8
-+#define type3FontCacheMaxSets 8
-+#define type3FontCacheSize (128*1024)
-+
-+//------------------------------------------------------------------------
-+
- // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
- static inline Guchar div255(int x) {
- return (Guchar)((x + (x >> 8) + 0x80) >> 8);
-@@ -180,64 +191,100 @@
- }
- }
-
--static void cvtRGBToHSV(Guchar r, Guchar g, Guchar b, int *h, int *s, int *v) {
-- int cmax, cmid, cmin, x;
-+static int getLum(int r, int g, int b) {
-+ return (int)(0.3 * r + 0.59 * g + 0.11 * b);
-+}
-
-- if (r >= g) {
-- if (g >= b) { x = 0; cmax = r; cmid = g; cmin = b; }
-- else if (b >= r) { x = 4; cmax = b; cmid = r; cmin = g; }
-- else { x = 5; cmax = r; cmid = b; cmin = g; }
-- } else {
-- if (r >= b) { x = 1; cmax = g; cmid = r; cmin = b; }
-- else if (g >= b) { x = 2; cmax = g; cmid = b; cmin = r; }
-- else { x = 3; cmax = b; cmid = g; cmin = r; }
-- }
-- if (cmax == cmin) {
-- *h = *s = 0;
-+static int getSat(int r, int g, int b) {
-+ int rgbMin, rgbMax;
-+
-+ rgbMin = rgbMax = r;
-+ if (g < rgbMin) {
-+ rgbMin = g;
-+ } else if (g > rgbMax) {
-+ rgbMax = g;
-+ }
-+ if (b < rgbMin) {
-+ rgbMin = b;
-+ } else if (b > rgbMax) {
-+ rgbMax = b;
-+ }
-+ return rgbMax - rgbMin;
-+}
-+
-+static void clipColor(int rIn, int gIn, int bIn,
-+ Guchar *rOut, Guchar *gOut, Guchar *bOut) {
-+ int lum, rgbMin, rgbMax;
-+
-+ lum = getLum(rIn, gIn, bIn);
-+ rgbMin = rgbMax = rIn;
-+ if (gIn < rgbMin) {
-+ rgbMin = gIn;
-+ } else if (gIn > rgbMax) {
-+ rgbMax = gIn;
-+ }
-+ if (bIn < rgbMin) {
-+ rgbMin = bIn;
-+ } else if (bIn > rgbMax) {
-+ rgbMax = bIn;
-+ }
-+ if (rgbMin < 0) {
-+ *rOut = (Guchar)(lum + ((rIn - lum) * lum) / (lum - rgbMin));
-+ *gOut = (Guchar)(lum + ((gIn - lum) * lum) / (lum - rgbMin));
-+ *bOut = (Guchar)(lum + ((bIn - lum) * lum) / (lum - rgbMin));
-+ } else if (rgbMax > 255) {
-+ *rOut = (Guchar)(lum + ((rIn - lum) * (255 - lum)) / (rgbMax - lum));
-+ *gOut = (Guchar)(lum + ((gIn - lum) * (255 - lum)) / (rgbMax - lum));
-+ *bOut = (Guchar)(lum + ((bIn - lum) * (255 - lum)) / (rgbMax - lum));
- } else {
-- *h = x * 60;
-- if (x & 1) {
-- *h += ((cmax - cmid) * 60) / (cmax - cmin);
-- } else {
-- *h += ((cmid - cmin) * 60) / (cmax - cmin);
-- }
-- *s = (255 * (cmax - cmin)) / cmax;
-+ *rOut = rIn;
-+ *gOut = gIn;
-+ *bOut = bIn;
- }
-- *v = cmax;
- }
-
--static void cvtHSVToRGB(int h, int s, int v, Guchar *r, Guchar *g, Guchar *b) {
-- int x, f, cmax, cmid, cmin;
-+static void setLum(Guchar rIn, Guchar gIn, Guchar bIn, int lum,
-+ Guchar *rOut, Guchar *gOut, Guchar *bOut) {
-+ int d;
-+
-+ d = lum - getLum(rIn, gIn, bIn);
-+ clipColor(rIn + d, gIn + d, bIn + d, rOut, gOut, bOut);
-+}
-+
-+static void setSat(Guchar rIn, Guchar gIn, Guchar bIn, int sat,
-+ Guchar *rOut, Guchar *gOut, Guchar *bOut) {
-+ int rgbMin, rgbMid, rgbMax;
-+ Guchar *minOut, *midOut, *maxOut;
-
-- if (s == 0) {
-- *r = *g = *b = v;
-+ if (rIn < gIn) {
-+ rgbMin = rIn; minOut = rOut;
-+ rgbMid = gIn; midOut = gOut;
- } else {
-- x = h / 60;
-- f = h % 60;
-- cmax = v;
-- if (x & 1) {
-- cmid = div255(v * 255 - ((s * f) / 60));
-- } else {
-- cmid = div255(v * (255 - ((s * (60 - f)) / 60)));
-- }
-- cmin = div255(v * (255 - s));
-- switch (x) {
-- case 0: *r = cmax; *g = cmid; *b = cmin; break;
-- case 1: *g = cmax; *r = cmid; *b = cmin; break;
-- case 2: *g = cmax; *b = cmid; *r = cmin; break;
-- case 3: *b = cmax; *g = cmid; *r = cmin; break;
-- case 4: *b = cmax; *r = cmid; *g = cmin; break;
-- case 5: *r = cmax; *b = cmid; *g = cmin; break;
-- }
-+ rgbMin = gIn; minOut = gOut;
-+ rgbMid = rIn; midOut = rOut;
- }
-+ if (bIn > rgbMid) {
-+ rgbMax = bIn; maxOut = bOut;
-+ } else if (bIn > rgbMin) {
-+ rgbMax = rgbMid; maxOut = midOut;
-+ rgbMid = bIn; midOut = bOut;
-+ } else {
-+ rgbMax = rgbMid; maxOut = midOut;
-+ rgbMid = rgbMin; midOut = minOut;
-+ rgbMin = bIn; minOut = bOut;
-+ }
-+ if (rgbMax > rgbMin) {
-+ *midOut = (Guchar)((rgbMid - rgbMin) * sat) / (rgbMax - rgbMin);
-+ *maxOut = (Guchar)sat;
-+ } else {
-+ *midOut = *maxOut = 0;
-+ }
-+ *minOut = 0;
- }
-
- static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest,
- SplashColorPtr blend, SplashColorMode cm) {
-- int hs, ss, vs, hd, sd, vd;
--#if SPLASH_CMYK
-- Guchar r, g, b;
--#endif
-+ Guchar r0, g0, b0, r1, g1, b1;
-
- switch (cm) {
- case splashModeMono1:
-@@ -246,25 +293,22 @@
- break;
- case splashModeRGB8:
- case splashModeBGR8:
-- cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
-- cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
-- cvtHSVToRGB(hs, sd, vd, &blend[0], &blend[1], &blend[2]);
-+ setSat(src[0], src[1], src[2], getSat(dest[0], dest[1], dest[2]),
-+ &r0, &g0, &b0);
-+ setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]),
-+ &blend[0], &blend[1], &blend[2]);
- break;
- #if SPLASH_CMYK
- case splashModeCMYK8:
-- //~ (0xff - ...) should be clipped
-- cvtRGBToHSV(0xff - (src[0] + src[3]),
-- 0xff - (src[1] + src[3]),
-- 0xff - (src[2] + src[3]), &hs, &ss, &vs);
-- cvtRGBToHSV(0xff - (dest[0] + dest[3]),
-- 0xff - (dest[1] + dest[3]),
-- 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
-- cvtHSVToRGB(hs, sd, vd, &r, &g, &b);
-- //~ should do black generation
-- blend[0] = 0xff - r;
-- blend[1] = 0xff - g;
-- blend[2] = 0xff - b;
-- blend[3] = 0;
-+ // NB: inputs have already been converted to additive mode
-+ setSat(src[0], src[1], src[2], getSat(dest[0], dest[1], dest[2]),
-+ &r0, &g0, &b0);
-+ setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]),
-+ &r1, &g1, &b1);
-+ blend[0] = r1;
-+ blend[1] = g1;
-+ blend[2] = b1;
-+ blend[3] = dest[3];
- break;
- #endif
- }
-@@ -273,10 +317,7 @@
- static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest,
- SplashColorPtr blend,
- SplashColorMode cm) {
-- int hs, ss, vs, hd, sd, vd;
--#if SPLASH_CMYK
-- Guchar r, g, b;
--#endif
-+ Guchar r0, g0, b0, r1, g1, b1;
-
- switch (cm) {
- case splashModeMono1:
-@@ -285,25 +326,22 @@
- break;
- case splashModeRGB8:
- case splashModeBGR8:
-- cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
-- cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
-- cvtHSVToRGB(hd, ss, vd, &blend[0], &blend[1], &blend[2]);
-+ setSat(dest[0], dest[1], dest[2], getSat(src[0], src[1], src[2]),
-+ &r0, &g0, &b0);
-+ setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]),
-+ &blend[0], &blend[1], &blend[2]);
- break;
- #if SPLASH_CMYK
- case splashModeCMYK8:
-- //~ (0xff - ...) should be clipped
-- cvtRGBToHSV(0xff - (src[0] + src[3]),
-- 0xff - (src[1] + src[3]),
-- 0xff - (src[2] + src[3]), &hs, &ss, &vs);
-- cvtRGBToHSV(0xff - (dest[0] + dest[3]),
-- 0xff - (dest[1] + dest[3]),
-- 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
-- cvtHSVToRGB(hd, ss, vd, &r, &g, &b);
-- //~ should do black generation
-- blend[0] = 0xff - r;
-- blend[1] = 0xff - g;
-- blend[2] = 0xff - b;
-- blend[3] = 0;
-+ // NB: inputs have already been converted to additive mode
-+ setSat(dest[0], dest[1], dest[2], getSat(src[0], src[1], src[2]),
-+ &r0, &g0, &b0);
-+ setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]),
-+ &r1, &g1, &b1);
-+ blend[0] = r1;
-+ blend[1] = g1;
-+ blend[2] = b1;
-+ blend[3] = dest[3];
- break;
- #endif
- }
-@@ -311,7 +349,6 @@
-
- static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest,
- SplashColorPtr blend, SplashColorMode cm) {
-- int hs, ss, vs, hd, sd, vd;
- #if SPLASH_CMYK
- Guchar r, g, b;
- #endif
-@@ -323,25 +360,18 @@
- break;
- case splashModeRGB8:
- case splashModeBGR8:
-- cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
-- cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
-- cvtHSVToRGB(hs, ss, vd, &blend[0], &blend[1], &blend[2]);
-+ setLum(src[0], src[1], src[2], getLum(dest[0], dest[1], dest[2]),
-+ &blend[0], &blend[1], &blend[2]);
- break;
- #if SPLASH_CMYK
- case splashModeCMYK8:
-- //~ (0xff - ...) should be clipped
-- cvtRGBToHSV(0xff - (src[0] + src[3]),
-- 0xff - (src[1] + src[3]),
-- 0xff - (src[2] + src[3]), &hs, &ss, &vs);
-- cvtRGBToHSV(0xff - (dest[0] + dest[3]),
-- 0xff - (dest[1] + dest[3]),
-- 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
-- cvtHSVToRGB(hs, ss, vd, &r, &g, &b);
-- //~ should do black generation
-- blend[0] = 0xff - r;
-- blend[1] = 0xff - g;
-- blend[2] = 0xff - b;
-- blend[3] = 0;
-+ // NB: inputs have already been converted to additive mode
-+ setLum(src[0], src[1], src[2], getLum(dest[0], dest[1], dest[2]),
-+ &r, &g, &b);
-+ blend[0] = r;
-+ blend[1] = g;
-+ blend[2] = b;
-+ blend[3] = dest[3];
- break;
- #endif
- }
-@@ -350,7 +380,6 @@
- static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest,
- SplashColorPtr blend,
- SplashColorMode cm) {
-- int hs, ss, vs, hd, sd, vd;
- #if SPLASH_CMYK
- Guchar r, g, b;
- #endif
-@@ -362,25 +391,18 @@
- break;
- case splashModeRGB8:
- case splashModeBGR8:
-- cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
-- cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
-- cvtHSVToRGB(hd, sd, vs, &blend[0], &blend[1], &blend[2]);
-+ setLum(dest[0], dest[1], dest[2], getLum(src[0], src[1], src[2]),
-+ &blend[0], &blend[1], &blend[2]);
- break;
- #if SPLASH_CMYK
- case splashModeCMYK8:
-- //~ (0xff - ...) should be clipped
-- cvtRGBToHSV(0xff - (src[0] + src[3]),
-- 0xff - (src[1] + src[3]),
-- 0xff - (src[2] + src[3]), &hs, &ss, &vs);
-- cvtRGBToHSV(0xff - (dest[0] + dest[3]),
-- 0xff - (dest[1] + dest[3]),
-- 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
-- cvtHSVToRGB(hd, sd, vs, &r, &g, &b);
-- //~ should do black generation
-- blend[0] = 0xff - r;
-- blend[1] = 0xff - g;
-- blend[2] = 0xff - b;
-- blend[3] = 0;
-+ // NB: inputs have already been converted to additive mode
-+ setLum(dest[0], dest[1], dest[2], getLum(src[0], src[1], src[2]),
-+ &r, &g, &b);
-+ blend[0] = r;
-+ blend[1] = g;
-+ blend[2] = b;
-+ blend[3] = src[3];
- break;
- #endif
- }
-@@ -510,21 +503,23 @@
- glyphW = glyphWA;
- glyphH = glyphHA;
- validBBox = validBBoxA;
-+ // sanity check for excessively large glyphs (which most likely
-+ // indicate an incorrect BBox)
-+ i = glyphW * glyphH;
-+ if (i > 100000 || glyphW > INT_MAX / glyphH || glyphW <= 0 || glyphH <= 0) {
-+ glyphW = glyphH = 100;
-+ validBBox = gFalse;
-+ }
- if (aa) {
- glyphSize = glyphW * glyphH;
- } else {
- glyphSize = ((glyphW + 7) >> 3) * glyphH;
- }
-- cacheAssoc = 8;
-- if (glyphSize <= 256) {
-- cacheSets = 8;
-- } else if (glyphSize <= 512) {
-- cacheSets = 4;
-- } else if (glyphSize <= 1024) {
-- cacheSets = 2;
-- } else {
-- cacheSets = 1;
-- }
-+ cacheAssoc = type3FontCacheAssoc;
-+ for (cacheSets = type3FontCacheMaxSets;
-+ cacheSets > 1 &&
-+ cacheSets * cacheAssoc * glyphSize > type3FontCacheSize;
-+ cacheSets >>= 1) ;
- cacheData = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize);
- cacheTags = (T3FontCacheTag *)gmallocn(cacheSets * cacheAssoc,
- sizeof(T3FontCacheTag));
-@@ -584,6 +579,7 @@
- colorMode = colorModeA;
- bitmapRowPad = bitmapRowPadA;
- bitmapTopDown = bitmapTopDownA;
-+ bitmapUpsideDown = gFalse;
- allowAntialias = allowAntialiasA;
- vectorAntialias = allowAntialias &&
- globalParams->getVectorAntialias() &&
-@@ -591,12 +587,15 @@
- setupScreenParams(72.0, 72.0);
- reverseVideo = reverseVideoA;
- splashColorCopy(paperColor, paperColorA);
-+ skipHorizText = gFalse;
-+ skipRotatedText = gFalse;
-
- xref = NULL;
-
- bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode,
- colorMode != splashModeMono1, bitmapTopDown);
- splash = new Splash(bitmap, vectorAntialias, &screenParams);
-+ splash->setMinLineWidth(globalParams->getMinLineWidth());
- splash->clear(paperColor, 0);
-
- fontEngine = NULL;
-@@ -609,6 +608,8 @@
- textClipPath = NULL;
-
- transpGroupStack = NULL;
-+
-+ nestCount = 0;
- }
-
- void SplashOutputDev::setupScreenParams(double hDPI, double vDPI) {
-@@ -723,15 +726,18 @@
- bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode,
- colorMode != splashModeMono1, bitmapTopDown);
- }
- splash = new Splash(bitmap, vectorAntialias, &screenParams);
-+ splash->setMinLineWidth(globalParams->getMinLineWidth());
- if (state) {
- ctm = state->getCTM();
- mat[0] = (SplashCoord)ctm[0];
-@@ -835,7 +841,10 @@
- }
-
- void SplashOutputDev::updateFlatness(GfxState *state) {
-+#if 0 // Acrobat ignores the flatness setting, and always renders curves
-+ // with a fairly small flatness value
- splash->setFlatness(state->getFlatness());
-+#endif
- }
-
- void SplashOutputDev::updateLineJoin(GfxState *state) {
-@@ -868,14 +877,24 @@
- GfxCMYK cmyk;
- #endif
-
-- state->getFillGray(&gray);
-- state->getFillRGB(&rgb);
-+ switch (colorMode) {
-+ case splashModeMono1:
-+ case splashModeMono8:
-+ state->getFillGray(&gray);
-+ splash->setFillPattern(getColor(gray));
-+ break;
-+ case splashModeRGB8:
-+ case splashModeBGR8:
-+ state->getFillRGB(&rgb);
-+ splash->setFillPattern(getColor(&rgb));
-+ break;
- #if SPLASH_CMYK
-- state->getFillCMYK(&cmyk);
-- splash->setFillPattern(getColor(gray, &rgb, &cmyk));
--#else
-- splash->setFillPattern(getColor(gray, &rgb));
-+ case splashModeCMYK8:
-+ state->getFillCMYK(&cmyk);
-+ splash->setFillPattern(getColor(&cmyk));
-+ break;
- #endif
-+ }
- }
-
- void SplashOutputDev::updateStrokeColor(GfxState *state) {
-@@ -885,28 +904,41 @@
- GfxCMYK cmyk;
- #endif
-
-- state->getStrokeGray(&gray);
-- state->getStrokeRGB(&rgb);
-+ switch (colorMode) {
-+ case splashModeMono1:
-+ case splashModeMono8:
-+ state->getStrokeGray(&gray);
-+ splash->setStrokePattern(getColor(gray));
-+ break;
-+ case splashModeRGB8:
-+ case splashModeBGR8:
-+ state->getStrokeRGB(&rgb);
-+ splash->setStrokePattern(getColor(&rgb));
-+ break;
- #if SPLASH_CMYK
-- state->getStrokeCMYK(&cmyk);
-- splash->setStrokePattern(getColor(gray, &rgb, &cmyk));
--#else
-- splash->setStrokePattern(getColor(gray, &rgb));
-+ case splashModeCMYK8:
-+ state->getStrokeCMYK(&cmyk);
-+ splash->setStrokePattern(getColor(&cmyk));
-+ break;
- #endif
-+ }
- }
-
--#if SPLASH_CMYK
--SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb,
-- GfxCMYK *cmyk) {
--#else
--SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) {
--#endif
-- SplashPattern *pattern;
-+SplashPattern *SplashOutputDev::getColor(GfxGray gray) {
- SplashColor color;
-- GfxColorComp r, g, b;
-
- if (reverseVideo) {
- gray = gfxColorComp1 - gray;
-+ }
-+ color[0] = colToByte(gray);
-+ return new SplashSolidColor(color);
-+}
-+
-+SplashPattern *SplashOutputDev::getColor(GfxRGB *rgb) {
-+ GfxColorComp r, g, b;
-+ SplashColor color;
-+
-+ if (reverseVideo) {
- r = gfxColorComp1 - rgb->r;
- g = gfxColorComp1 - rgb->g;
- b = gfxColorComp1 - rgb->b;
-@@ -915,33 +947,58 @@
- g = rgb->g;
- b = rgb->b;
- }
-+ color[0] = colToByte(r);
-+ color[1] = colToByte(g);
-+ color[2] = colToByte(b);
-+ return new SplashSolidColor(color);
-+}
-
-- pattern = NULL; // make gcc happy
-- switch (colorMode) {
-- case splashModeMono1:
-- case splashModeMono8:
-- color[0] = colToByte(gray);
-- pattern = new SplashSolidColor(color);
-- break;
-- case splashModeRGB8:
-- case splashModeBGR8:
-- color[0] = colToByte(r);
-- color[1] = colToByte(g);
-- color[2] = colToByte(b);
-- pattern = new SplashSolidColor(color);
-- break;
- #if SPLASH_CMYK
-- case splashModeCMYK8:
-- color[0] = colToByte(cmyk->c);
-- color[1] = colToByte(cmyk->m);
-- color[2] = colToByte(cmyk->y);
-- color[3] = colToByte(cmyk->k);
-- pattern = new SplashSolidColor(color);
-- break;
-+SplashPattern *SplashOutputDev::getColor(GfxCMYK *cmyk) {
-+ SplashColor color;
-+
-+ color[0] = colToByte(cmyk->c);
-+ color[1] = colToByte(cmyk->m);
-+ color[2] = colToByte(cmyk->y);
-+ color[3] = colToByte(cmyk->k);
-+ return new SplashSolidColor(color);
-+}
- #endif
-- }
-
-- return pattern;
- }
-
- void SplashOutputDev::updateBlendMode(GfxState *state) {
-@@ -956,35 +1013,82 @@
- void SplashOutputDev::updateFont(GfxState *state) {
- needFontUpdate = gTrue;
- }
-
- void SplashOutputDev::doUpdateFont(GfxState *state) {
- GfxFont *gfxFont;
-+ GfxFontLoc *fontLoc;
- GfxFontType fontType;
- SplashOutFontFileID *id;
- SplashFontFile *fontFile;
-+ int fontNum;
- FoFiTrueType *ff;
- Ref embRef;
- Object refObj, strObj;
-- GString *tmpFileName, *fileName, *substName;
-+ GString *tmpFileName, *fileName;
- FILE *tmpFile;
- int *codeToGID;
-- DisplayFontParam *dfp;
- CharCodeToUnicode *ctu;
- double *textMat;
-- double m11, m12, m21, m22, w1, w2, fontSize;
-+ double m11, m12, m21, m22, fontSize;
-+ double w, fontScaleMin, fontScaleAvg, fontScale;
-+ Gushort ww;
- SplashCoord mat[4];
- char *name;
- Unicode uBuf[8];
-- int c, substIdx, n, code, cmap;
-+ int c, substIdx, n, code, cmap, i;
-
- needFontUpdate = gFalse;
- font = NULL;
- tmpFileName = NULL;
- substIdx = -1;
-- dfp = NULL;
-
- if (!(gfxFont = state->getFont())) {
- goto err1;
-@@ -994,6 +1098,13 @@
- goto err1;
- }
-
-+ // sanity-check the font size - skip anything larger than 10 inches
-+ // (this avoids problems allocating memory for the font cache)
-+ if (state->getTransformedFontSize()
-+ > 10 * (state->getHDPI() + state->getVDPI())) {
-+ goto err1;
-+ }
-+
- // check the font file cache
- id = new SplashOutFontFileID(gfxFont->getID());
- if ((fontFile = fontEngine->getFontFile(id))) {
-@@ -1001,19 +1112,32 @@
-
- } else {
-
-- // if there is an embedded font, write it to disk
-- if (gfxFont->getEmbeddedFontID(&embRef)) {
-+ fileName = NULL;
-+ fontNum = 0;
-+
-+ if (!(fontLoc = gfxFont->locateFont(xref, gFalse))) {
-+ error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
-+ gfxFont->getName() ? gfxFont->getName()->getCString()
-+ : "(unnamed)");
-+ goto err2;
-+ }
-+
-+ // embedded font
-+ if (fontLoc->locType == gfxFontLocEmbedded) {
-+ gfxFont->getEmbeddedFontID(&embRef);
- if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
-- error(-1, "Couldn't create temporary font file");
-+ error(errIO, -1, "Couldn't create temporary font file");
-+ delete fontLoc;
- goto err2;
- }
- refObj.initRef(embRef.num, embRef.gen);
- refObj.fetch(xref, &strObj);
- refObj.free();
- if (!strObj.isStream()) {
-- error(-1, "Embedded font object is wrong type");
-+ error(errSyntaxError, -1, "Embedded font object is wrong type");
- strObj.free();
- fclose(tmpFile);
-+ delete fontLoc;
- goto err2;
- }
- strObj.streamReset();
-@@ -1025,94 +1149,53 @@
- fclose(tmpFile);
- fileName = tmpFileName;
-
-- // if there is an external font file, use it
-- } else if (!(fileName = gfxFont->getExtFontFile())) {
--
-- // look for a display font mapping or a substitute font
-- if (gfxFont->isCIDFont()) {
-- if (((GfxCIDFont *)gfxFont)->getCollection()) {
-- dfp = globalParams->
-- getDisplayCIDFont(gfxFont->getName(),
-- ((GfxCIDFont *)gfxFont)->getCollection());
-- }
-- } else {
-- if (gfxFont->getName()) {
-- dfp = globalParams->getDisplayFont(gfxFont->getName());
-- }
-- if (!dfp) {
-- // 8-bit font substitution
-- if (gfxFont->isFixedWidth()) {
-- substIdx = 8;
-- } else if (gfxFont->isSerif()) {
-- substIdx = 4;
-- } else {
-- substIdx = 0;
-- }
-- if (gfxFont->isBold()) {
-- substIdx += 2;
-- }
-- if (gfxFont->isItalic()) {
-- substIdx += 1;
-- }
-- substName = new GString(splashOutSubstFonts[substIdx].name);
-- dfp = globalParams->getDisplayFont(substName);
-- delete substName;
-- id->setSubstIdx(substIdx);
-- }
-- }
-- if (!dfp) {
-- error(-1, "Couldn't find a font for '%s'",
-- gfxFont->getName() ? gfxFont->getName()->getCString()
-- : "(unnamed)");
-- goto err2;
-- }
-- switch (dfp->kind) {
-- case displayFontT1:
-- fileName = dfp->t1.fileName;
-- fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
-- break;
-- case displayFontTT:
-- fileName = dfp->tt.fileName;
-- fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
-- break;
-+ // external font
-+ } else { // gfxFontLocExternal
-+ fileName = fontLoc->path;
-+ fontNum = fontLoc->fontNum;
-+ if (fontLoc->substIdx >= 0) {
-+ id->setSubstIdx(fontLoc->substIdx);
- }
- }
-
- // load the font file
-- switch (fontType) {
-+ switch (fontLoc->fontType) {
- case fontType1:
- if (!(fontFile = fontEngine->loadType1Font(
-- id,
-- fileName->getCString(),
-- fileName == tmpFileName,
-- (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
-- error(-1, "Couldn't create a font for '%s'",
-+ id,
-+ fileName->getCString(),
-+ fileName == tmpFileName,
-+ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
-+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
-+ delete fontLoc;
- goto err2;
- }
- break;
- case fontType1C:
- if (!(fontFile = fontEngine->loadType1CFont(
-- id,
-- fileName->getCString(),
-- fileName == tmpFileName,
-- (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
-- error(-1, "Couldn't create a font for '%s'",
-+ id,
-+ fileName->getCString(),
-+ fileName == tmpFileName,
-+ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
-+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
-+ delete fontLoc;
- goto err2;
- }
- break;
- case fontType1COT:
- if (!(fontFile = fontEngine->loadOpenTypeT1CFont(
-- id,
-- fileName->getCString(),
-- fileName == tmpFileName,
-- (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
-- error(-1, "Couldn't create a font for '%s'",
-+ id,
-+ fileName->getCString(),
-+ fileName == tmpFileName,
-+ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
-+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
-+ delete fontLoc;
- goto err2;
- }
- break;
-@@ -1122,18 +1205,33 @@
- codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
- n = 256;
- delete ff;
-+ // if we're substituting for a non-TrueType font, we need to mark
-+ // all notdef codes as "do not draw" (rather than drawing TrueType
-+ // notdef glyphs)
-+ if (gfxFont->getType() != fontTrueType &&
-+ gfxFont->getType() != fontTrueTypeOT) {
-+ for (i = 0; i < 256; ++i) {
-+ if (codeToGID[i] == 0) {
-+ codeToGID[i] = -1;
-+ }
-+ }
-+ }
- } else {
- codeToGID = NULL;
- n = 0;
- }
- if (!(fontFile = fontEngine->loadTrueTypeFont(
- id,
-- fileName->getCString(),
-+ fileName->getCString(), fontNum,
- fileName == tmpFileName,
-- codeToGID, n))) {
-- error(-1, "Couldn't create a font for '%s'",
-+ codeToGID, n,
-+ gfxFont->getEmbeddedFontName()
-+ ? gfxFont->getEmbeddedFontName()->getCString()
-+ : (char *)NULL))) {
-+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
-+ delete fontLoc;
- goto err2;
- }
- break;
-@@ -1143,20 +1241,32 @@
- id,
- fileName->getCString(),
- fileName == tmpFileName))) {
-- error(-1, "Couldn't create a font for '%s'",
-+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
-+ delete fontLoc;
- goto err2;
- }
- break;
- case fontCIDType0COT:
- if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
- n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
- codeToGID = (int *)gmallocn(n, sizeof(int));
- memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
- n * sizeof(int));
- } else {
- codeToGID = NULL;
- n = 0;
- }
- if (!(fontFile = fontEngine->loadOpenTypeCFFFont(
- id,
- codeToGID, n))) {
- error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
-+ delete fontLoc;
- goto err2;
- }
- break;
-@@ -1164,9 +1274,17 @@
- case fontCIDType2OT:
- codeToGID = NULL;
- n = 0;
-- if (dfp) {
-+ if (fontLoc->locType == gfxFontLocEmbedded) {
-+ if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
-+ n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
-+ codeToGID = (int *)gmallocn(n, sizeof(int));
-+ memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
-+ n * sizeof(int));
-+ }
-+ } else {
- // create a CID-to-GID mapping, via Unicode
- if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) {
-+ //~ this should use fontNum to load the correct font
- if ((ff = FoFiTrueType::load(fileName->getCString()))) {
- // look for a Unicode cmap
- for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) {
-@@ -1179,12 +1297,12 @@
- if (cmap < ff->getNumCmaps()) {
- // map CID -> Unicode -> GID
- n = ctu->getLength();
-- codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
-+ codeToGID = (int *)gmallocn(n, sizeof(int));
- for (code = 0; code < n; ++code) {
- if (ctu->mapToUnicode(code, uBuf, 8) > 0) {
- codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]);
- } else {
-- codeToGID[code] = 0;
-+ codeToGID[code] = -1;
- }
- }
- }
-@@ -1192,26 +1310,24 @@
- }
- ctu->decRefCnt();
- } else {
-- error(-1, "Couldn't find a mapping to Unicode for font '%s'",
-+ error(errSyntaxError, -1,
-+ "Couldn't find a mapping to Unicode for font '{0:s}'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
- }
-- } else {
-- if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
-- n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
-- codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
-- memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
-- n * sizeof(Gushort));
-- }
- }
- if (!(fontFile = fontEngine->loadTrueTypeFont(
- id,
-- fileName->getCString(),
-+ fileName->getCString(), fontNum,
- fileName == tmpFileName,
-- codeToGID, n))) {
-- error(-1, "Couldn't create a font for '%s'",
-+ codeToGID, n,
-+ gfxFont->getEmbeddedFontName()
-+ ? gfxFont->getEmbeddedFontName()->getCString()
-+ : (char *)NULL))) {
-+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
- gfxFont->getName() ? gfxFont->getName()->getCString()
- : "(unnamed)");
-+ delete fontLoc;
- goto err2;
- }
- break;
-@@ -1219,6 +1335,8 @@
- // this shouldn't happen
- goto err2;
- }
-+
-+ delete fontLoc;
- }
-
- // get the font matrix
-@@ -1230,26 +1348,42 @@
- m22 = textMat[3] * fontSize;
-
- // for substituted fonts: adjust the font matrix -- compare the
-- // width of 'm' in the original font and the substituted font
-+ // widths of letters and digits (A-Z, a-z, 0-9) in the original font
-+ // and the substituted font
- substIdx = ((SplashOutFontFileID *)fontFile->getID())->getSubstIdx();
-- if (substIdx >= 0) {
-+ if (substIdx >= 0 && substIdx < 12) {
-+ fontScaleMin = 1;
-+ fontScaleAvg = 0;
-+ n = 0;
- for (code = 0; code < 256; ++code) {
- if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
-- name[0] == 'm' && name[1] == '\0') {
-- break;
-+ name[0] && !name[1] &&
-+ ((name[0] >= 'A' && name[0] <= 'Z') ||
-+ (name[0] >= 'a' && name[0] <= 'z') ||
-+ (name[0] >= '0' && name[0] <= '9'))) {
-+ w = ((Gfx8BitFont *)gfxFont)->getWidth(code);
-+ builtinFontSubst[substIdx]->widths->getWidth(name, &ww);
-+ if (w > 0.01 && ww > 10) {
-+ w /= ww * 0.001;
-+ if (w < fontScaleMin) {
-+ fontScaleMin = w;
-+ }
-+ fontScaleAvg += w;
-+ ++n;
-+ }
- }
- }
-- if (code < 256) {
-- w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
-- w2 = splashOutSubstFonts[substIdx].mWidth;
-- if (!gfxFont->isSymbolic()) {
-- // if real font is substantially narrower than substituted
-- // font, reduce the font size accordingly
-- if (w1 > 0.01 && w1 < 0.9 * w2) {
-- w1 /= w2;
-- m11 *= w1;
-- m21 *= w1;
-- }
-+ // if real font is narrower than substituted font, reduce the font
-+ // size accordingly -- this currently uses a scale factor halfway
-+ // between the minimum and average computed scale factors, which
-+ // is a bit of a kludge, but seems to produce mostly decent
-+ // results
-+ if (n) {
-+ fontScaleAvg /= n;
-+ if (fontScaleAvg < 1) {
-+ fontScale = 0.5 * (fontScaleMin + fontScaleAvg);
-+ m11 *= fontScale;
-+ m12 *= fontScale;
- }
- }
- }
-@@ -1302,15 +1440,155 @@
- splash->fill(path, gTrue);
- delete path;
- }
-
-+void SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str,
-+ int paintType, Dict *resDict,
-+ double *mat, double *bbox,
-+ int x0, int y0, int x1, int y1,
-+ double xStep, double yStep) {
-+ double tileXMin, tileYMin, tileXMax, tileYMax, tx, ty;
-+ int tileX0, tileY0, tileW, tileH, tileSize;
-+ SplashBitmap *origBitmap, *tileBitmap;
-+ Splash *origSplash;
-+ SplashColor color;
-+ double mat1[6];
-+ double xa, ya, xb, yb, xc, yc;
-+ int x, y, xx, yy, i;
-+
-+ // transform the four corners of the bbox from pattern space to
-+ // device space and compute the device space bbox
-+ state->transform(bbox[0] * mat[0] + bbox[1] * mat[2] + mat[4],
-+ bbox[0] * mat[1] + bbox[1] * mat[3] + mat[5],
-+ &tx, &ty);
-+ tileXMin = tileXMax = tx;
-+ tileYMin = tileYMax = ty;
-+ state->transform(bbox[2] * mat[0] + bbox[1] * mat[2] + mat[4],
-+ bbox[2] * mat[1] + bbox[1] * mat[3] + mat[5],
-+ &tx, &ty);
-+ if (tx < tileXMin) {
-+ tileXMin = tx;
-+ } else if (tx > tileXMax) {
-+ tileXMax = tx;
-+ }
-+ if (ty < tileYMin) {
-+ tileYMin = ty;
-+ } else if (ty > tileYMax) {
-+ tileYMax = ty;
-+ }
-+ state->transform(bbox[2] * mat[0] + bbox[3] * mat[2] + mat[4],
-+ bbox[2] * mat[1] + bbox[3] * mat[3] + mat[5],
-+ &tx, &ty);
-+ if (tx < tileXMin) {
-+ tileXMin = tx;
-+ } else if (tx > tileXMax) {
-+ tileXMax = tx;
-+ }
-+ if (ty < tileYMin) {
-+ tileYMin = ty;
-+ } else if (ty > tileYMax) {
-+ tileYMax = ty;
-+ }
-+ state->transform(bbox[0] * mat[0] + bbox[3] * mat[2] + mat[4],
-+ bbox[0] * mat[1] + bbox[3] * mat[3] + mat[5],
-+ &tx, &ty);
-+ if (tx < tileXMin) {
-+ tileXMin = tx;
-+ } else if (tx > tileXMax) {
-+ tileXMax = tx;
-+ }
-+ if (ty < tileYMin) {
-+ tileYMin = ty;
-+ } else if (ty > tileYMax) {
-+ tileYMax = ty;
-+ }
-+ if (tileXMin == tileXMax || tileYMin == tileYMax) {
-+ return;
-+ }
-+
-+ tileX0 = (int)floor(tileXMin);
-+ tileY0 = (int)floor(tileYMin);
-+ tileW = (int)ceil(tileXMax) - tileX0;
-+ tileH = (int)ceil(tileYMax) - tileY0;
-+
-+ // check for an excessively large tile size
-+ tileSize = tileW * tileH;
-+ if (tileSize > 1000000 || tileSize < 0) {
-+ mat1[0] = mat[0];
-+ mat1[1] = mat[1];
-+ mat1[2] = mat[2];
-+ mat1[3] = mat[3];
-+ for (y = y0; y < y1; ++y) {
-+ for (x = x0; x < x1; ++x) {
-+ xa = x * xStep;
-+ ya = y * yStep;
-+ mat1[4] = xa * mat[0] + ya * mat[2] + mat[4];
-+ mat1[5] = xa * mat[1] + ya * mat[3] + mat[5];
-+ gfx->drawForm(str, resDict, mat1, bbox);
-+ }
-+ }
-+ return;
-+ }
-+
-+ // create a temporary bitmap
-+ origBitmap = bitmap;
-+ origSplash = splash;
-+ bitmap = tileBitmap = new SplashBitmap(tileW, tileH, bitmapRowPad,
-+ colorMode, gTrue, bitmapTopDown);
-+ splash = new Splash(bitmap, vectorAntialias, origSplash->getScreen());
-+ splash->setMinLineWidth(globalParams->getMinLineWidth());
-+ for (i = 0; i < splashMaxColorComps; ++i) {
-+ color[i] = 0;
-+ }
-+ splash->clear(color);
-+ ++nestCount;
-+
-+ // copy the fill color (for uncolored tiling patterns)
-+ // (and stroke color, to handle buggy PDF files)
-+ splash->setFillPattern(origSplash->getFillPattern()->copy());
-+ splash->setStrokePattern(origSplash->getStrokePattern()->copy());
-+
-+ // render the tile
-+ state->shiftCTM(-tileX0, -tileY0);
-+ updateCTM(state, 0, 0, 0, 0, 0, 0);
-+ gfx->drawForm(str, resDict, mat, bbox);
-+ state->shiftCTM(tileX0, tileY0);
-+ updateCTM(state, 0, 0, 0, 0, 0, 0);
-+
-+ // restore the original bitmap
-+ --nestCount;
-+ delete splash;
-+ bitmap = origBitmap;
-+ splash = origSplash;
-+ splash->setOverprintMask(0xffffffff);
-+
-+ // draw the tiles
-+ for (y = y0; y < y1; ++y) {
-+ for (x = x0; x < x1; ++x) {
-+ xa = x * xStep;
-+ ya = y * yStep;
-+ xb = xa * mat[0] + ya * mat[2];
-+ yb = xa * mat[1] + ya * mat[3];
-+ state->transformDelta(xb, yb, &xc, &yc);
-+ xx = (int)(xc + tileX0 + 0.5);
-+ yy = (int)(yc + tileY0 + 0.5);
-+ splash->composite(tileBitmap, 0, 0, xx, yy, tileW, tileH,
-+ gFalse, gFalse);
-+ }
-+ }
-+
-+ delete tileBitmap;
-+}
-+
- void SplashOutputDev::clip(GfxState *state) {
- SplashPath *path;
-
-@@ -1375,6 +1655,18 @@
- Unicode *u, int uLen) {
- SplashPath *path;
- int render;
-+ GBool doFill, doStroke, doClip, strokeAdjust;
-+ double m[4];
-+ GBool horiz;
-+
-+ if (skipHorizText || skipRotatedText) {
-+ state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]);
-+ horiz = m[0] > 0 && fabs(m[1]) < 0.001 &&
-+ fabs(m[2]) < 0.001 && m[3] < 0;
-+ if ((skipHorizText && horiz) || (skipRotatedText && !horiz)) {
-+ return;
-+ }
-+ }
-
- // check for invisible text -- this is used by Acrobat Capture
- render = state->getRender();
-@@ -1392,36 +1684,76 @@
- x -= originX;
- y -= originY;
-
-- // fill
-- if (!(render & 1)) {
-- if (!state->getFillColorSpace()->isNonMarking()) {
-- splash->fillChar((SplashCoord)x, (SplashCoord)y, code, font);
-+ doFill = !(render & 1) && !state->getFillColorSpace()->isNonMarking();
-+ doStroke = ((render & 3) == 1 || (render & 3) == 2) &&
-+ !state->getStrokeColorSpace()->isNonMarking();
-+ doClip = render & 4;
-+
-+ path = NULL;
-+ if (doStroke || doClip) {
-+ if ((path = font->getGlyphPath(code))) {
-+ path->offset((SplashCoord)x, (SplashCoord)y);
- }
- }
-
-+ // don't use stroke adjustment when stroking text -- the results
-+ // tend to be ugly (because characters with horizontal upper or
-+ // lower edges get misaligned relative to the other characters)
-+ strokeAdjust = gFalse; // make gcc happy
-+ if (doStroke) {
-+ strokeAdjust = splash->getStrokeAdjust();
-+ splash->setStrokeAdjust(gFalse);
-+ }
-+
-+ // fill and stroke
-+ if (doFill && doStroke) {
-+ if (path) {
-+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
-+ state->getOverprintMode(), state->getFillColor());
-+ splash->fill(path, gFalse);
-+ setOverprintMask(state->getStrokeColorSpace(),
-+ state->getStrokeOverprint(),
-+ state->getOverprintMode(),
-+ state->getStrokeColor());
-+ splash->stroke(path);
-+ }
-+
-+ // fill
-+ } else if (doFill) {
-+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
-+ state->getOverprintMode(), state->getFillColor());
-+ splash->fillChar((SplashCoord)x, (SplashCoord)y, code, font);
-+
- // stroke
-- if ((render & 3) == 1 || (render & 3) == 2) {
-- if (!state->getStrokeColorSpace()->isNonMarking()) {
-- if ((path = font->getGlyphPath(code))) {
-- path->offset((SplashCoord)x, (SplashCoord)y);
-- splash->stroke(path);
-- delete path;
-- }
-+ } else if (doStroke) {
-+ if (path) {
-+ setOverprintMask(state->getStrokeColorSpace(),
-+ state->getStrokeOverprint(),
-+ state->getOverprintMode(),
-+ state->getStrokeColor());
-+ splash->stroke(path);
- }
- }
-
- // clip
-- if (render & 4) {
-- if ((path = font->getGlyphPath(code))) {
-- path->offset((SplashCoord)x, (SplashCoord)y);
-+ if (doClip) {
-+ if (path) {
- if (textClipPath) {
- textClipPath->append(path);
-- delete path;
- } else {
- textClipPath = path;
-+ path = NULL;
- }
- }
- }
-+
-+ if (doStroke) {
-+ splash->setStrokeAdjust(strokeAdjust);
-+ }
-+
-+ if (path) {
-+ delete path;
-+ }
- }
-
- GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y,
-@@ -1433,9 +1765,20 @@
- T3FontCache *t3Font;
- T3GlyphStack *t3gs;
- GBool validBBox;
-+ double m[4];
-+ GBool horiz;
- double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
- int i, j;
-
-+ if (skipHorizText || skipRotatedText) {
-+ state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]);
-+ horiz = m[0] > 0 && fabs(m[1]) < 0.001 &&
-+ fabs(m[2]) < 0.001 && m[3] < 0;
-+ if ((skipHorizText && horiz) || (skipRotatedText && !horiz)) {
-+ return gTrue;
-+ }
-+ }
-+
- if (!(gfxFont = state->getFont())) {
- return gFalse;
- }
-@@ -1517,10 +1860,10 @@
- validBBox = gTrue;
- }
- t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3],
-- (int)floor(xMin - xt),
-- (int)floor(yMin - yt),
-- (int)ceil(xMax) - (int)floor(xMin) + 3,
-- (int)ceil(yMax) - (int)floor(yMin) + 3,
-+ (int)floor(xMin - xt) - 2,
-+ (int)floor(yMin - yt) - 2,
-+ (int)ceil(xMax) - (int)floor(xMin) + 4,
-+ (int)ceil(yMax) - (int)floor(yMin) + 4,
- validBBox,
- colorMode != splashModeMono1);
- }
-@@ -1547,6 +1890,8 @@
- t3GlyphStack->cacheTag = NULL;
- t3GlyphStack->cacheData = NULL;
-
-+ haveT3Dx = gFalse;
-+
- return gFalse;
- }
-
-@@ -1555,6 +1900,7 @@
- double *ctm;
-
- if (t3GlyphStack->cacheTag) {
-+ --nestCount;
- memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(),
- t3GlyphStack->cache->glyphSize);
- delete bitmap;
-@@ -1574,6 +1920,7 @@
- }
-
- void SplashOutputDev::type3D0(GfxState *state, double wx, double wy) {
-+ haveT3Dx = gTrue;
- }
-
- void SplashOutputDev::type3D1(GfxState *state, double wx, double wy,
-@@ -1584,6 +1931,12 @@
- double xt, yt, xMin, xMax, yMin, yMax, x1, y1;
- int i, j;
-
-+ // ignore multiple d0/d1 operators
-+ if (haveT3Dx) {
-+ return;
-+ }
-+ haveT3Dx = gTrue;
-+
- t3Font = t3GlyphStack->cache;
-
- // check for a valid bbox
-@@ -1662,7 +2015,7 @@
- t3GlyphStack->origSplash->getScreen());
- color[0] = 0;
- splash->clear(color);
-- color[0] = 1;
-+ color[0] = 0xff;
- } else {
- bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
- splashModeMono8, gFalse);
-@@ -1672,18 +2025,23 @@
- splash->clear(color);
- color[0] = 0xff;
- }
-+ splash->setMinLineWidth(globalParams->getMinLineWidth());
- splash->setFillPattern(new SplashSolidColor(color));
- splash->setStrokePattern(new SplashSolidColor(color));
- //~ this should copy other state from t3GlyphStack->origSplash?
-+ //~ [this is likely the same situation as in beginTransparencyGroup()]
- state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
- -t3Font->glyphX, -t3Font->glyphY);
- updateCTM(state, 0, 0, 0, 0, 0, 0);
-+ ++nestCount;
- }
-
-@@ -1717,9 +2075,10 @@
- if (imgMaskData->y == imgMaskData->height) {
- return gFalse;
- }
-- for (x = 0, p = imgMaskData->imgStr->getLine(), q = line;
-- x < imgMaskData->width;
-- ++x) {
-+ if (!(p = imgMaskData->imgStr->getLine())) {
-+ return gFalse;
-+ }
-+ for (x = 0, q = line; x < imgMaskData->width; ++x) {
- *q++ = *p++ ^ imgMaskData->invert;
- }
- ++imgMaskData->y;
-@@ -1736,6 +2095,8 @@
- if (state->getFillColorSpace()->isNonMarking()) {
- return;
- }
-+ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
-+ state->getOverprintMode(), state->getFillColor());
-
- ctm = state->getCTM();
- mat[0] = ctm[0];
-@@ -1765,6 +2126,46 @@
- str->close();
- }
-
-+void SplashOutputDev::setSoftMaskFromImageMask(GfxState *state,
-+ Object *ref, Stream *str,
-+ int width, int height,
-+ GBool invert,
-+ GBool inlineImg) {
-+ double *ctm;
-+ SplashCoord mat[6];
-+ SplashOutImageMaskData imgMaskData;
-+ SplashBitmap *maskBitmap;
-+ Splash *maskSplash;
-+ SplashColor maskColor;
-+
-+ ctm = state->getCTM();
-+ mat[0] = ctm[0];
-+ mat[1] = ctm[1];
-+ mat[2] = -ctm[2];
-+ mat[3] = -ctm[3];
-+ mat[4] = ctm[2] + ctm[4];
-+ mat[5] = ctm[3] + ctm[5];
-+ imgMaskData.imgStr = new ImageStream(str, width, 1, 1);
-+ imgMaskData.imgStr->reset();
-+ imgMaskData.invert = invert ? 0 : 1;
-+ imgMaskData.width = width;
-+ imgMaskData.height = height;
-+ imgMaskData.y = 0;
-+ maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
-+ 1, splashModeMono8, gFalse);
-+ maskSplash = new Splash(maskBitmap, gTrue);
-+ maskColor[0] = 0;
-+ maskSplash->clear(maskColor);
-+ maskColor[0] = 0xff;
-+ maskSplash->setFillPattern(new SplashSolidColor(maskColor));
-+ maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData,
-+ width, height, mat, gFalse);
-+ delete imgMaskData.imgStr;
-+ str->close();
-+ delete maskSplash;
-+ splash->setSoftMask(maskBitmap);
-+}
-+
- struct SplashOutImageData {
- ImageStream *imgStr;
- GfxImageColorMap *colorMap;
-@@ -1789,6 +2190,9 @@
- if (imgData->y == imgData->height) {
- return gFalse;
- }
-+ if (!(p = imgData->imgStr->getLine())) {
-+ return gFalse;
-+ }
-
- nComps = imgData->colorMap->getNumPixelComps();
-
-@@ -1796,17 +2200,13 @@
- switch (imgData->colorMode) {
- case splashModeMono1:
- case splashModeMono8:
-- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
-- x < imgData->width;
-- ++x, ++p) {
-+ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
- *q++ = imgData->lookup[*p];
- }
- break;
- case splashModeRGB8:
- case splashModeBGR8:
-- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
-- x < imgData->width;
-- ++x, ++p) {
-+ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
- col = &imgData->lookup[3 * *p];
- *q++ = col[0];
- *q++ = col[1];
-@@ -1815,9 +2215,7 @@
- break;
- #if SPLASH_CMYK
- case splashModeCMYK8:
-- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
-- x < imgData->width;
-- ++x, ++p) {
-+ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
- col = &imgData->lookup[4 * *p];
- *q++ = col[0];
- *q++ = col[1];
-@@ -1831,18 +2229,14 @@
- switch (imgData->colorMode) {
- case splashModeMono1:
- case splashModeMono8:
-- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
-- x < imgData->width;
-- ++x, p += nComps) {
-+ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
- imgData->colorMap->getGray(p, &gray);
- *q++ = colToByte(gray);
- }
- break;
- case splashModeRGB8:
- case splashModeBGR8:
-- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
-- x < imgData->width;
-- ++x, p += nComps) {
-+ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
- imgData->colorMap->getRGB(p, &rgb);
- *q++ = colToByte(rgb.r);
- *q++ = colToByte(rgb.g);
-@@ -1851,9 +2245,7 @@
- break;
- #if SPLASH_CMYK
- case splashModeCMYK8:
-- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
-- x < imgData->width;
-- ++x, p += nComps) {
-+ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
- imgData->colorMap->getCMYK(p, &cmyk);
- *q++ = colToByte(cmyk.c);
- *q++ = colToByte(cmyk.m);
-@@ -1885,10 +2277,13 @@
- if (imgData->y == imgData->height) {
- return gFalse;
- }
-+ if (!(p = imgData->imgStr->getLine())) {
-+ return gFalse;
-+ }
-
- nComps = imgData->colorMap->getNumPixelComps();
-
-- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine;
-+ for (x = 0, q = colorLine, aq = alphaLine;
- x < imgData->width;
- ++x, p += nComps) {
- alpha = 0;
-@@ -1904,7 +2299,6 @@
- case splashModeMono1:
- case splashModeMono8:
- *q++ = imgData->lookup[*p];
-- *aq++ = alpha;
- break;
- case splashModeRGB8:
- case splashModeBGR8:
-@@ -1912,7 +2306,6 @@
- *q++ = col[0];
- *q++ = col[1];
- *q++ = col[2];
-- *aq++ = alpha;
- break;
- #if SPLASH_CMYK
- case splashModeCMYK8:
-@@ -1921,17 +2314,16 @@
- *q++ = col[1];
- *q++ = col[2];
- *q++ = col[3];
-- *aq++ = alpha;
- break;
- #endif
- }
-+ *aq++ = alpha;
- } else {
- switch (imgData->colorMode) {
- case splashModeMono1:
- case splashModeMono8:
- imgData->colorMap->getGray(p, &gray);
- *q++ = colToByte(gray);
-- *aq++ = alpha;
- break;
- case splashModeRGB8:
- case splashModeBGR8:
-@@ -1939,7 +2331,6 @@
- *q++ = colToByte(rgb.r);
- *q++ = colToByte(rgb.g);
- *q++ = colToByte(rgb.b);
-- *aq++ = alpha;
- break;
- #if SPLASH_CMYK
- case splashModeCMYK8:
-@@ -1948,10 +2339,10 @@
- *q++ = colToByte(cmyk.m);
- *q++ = colToByte(cmyk.y);
- *q++ = colToByte(cmyk.k);
-- *aq++ = alpha;
- break;
- #endif
- }
-+ *aq++ = alpha;
- }
- }
-
-@@ -1976,6 +2367,9 @@
- Guchar pix;
- int n, i;
-
-+ setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
-+ state->getOverprintMode(), NULL);
-+
- ctm = state->getCTM();
- mat[0] = ctm[0];
- mat[1] = ctm[1];
-@@ -2012,7 +2406,7 @@
- break;
- case splashModeRGB8:
- case splashModeBGR8:
-- imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
-+ imgData.lookup = (SplashColorPtr)gmallocn(n, 3);
- for (i = 0; i < n; ++i) {
- pix = (Guchar)i;
- colorMap->getRGB(&pix, &rgb);
-@@ -2023,7 +2417,7 @@
- break;
- #if SPLASH_CMYK
- case splashModeCMYK8:
-- imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
-+ imgData.lookup = (SplashColorPtr)gmallocn(n, 4);
- for (i = 0; i < n; ++i) {
- pix = (Guchar)i;
- colorMap->getCMYK(&pix, &cmyk);
-@@ -2034,7 +2428,6 @@
- }
- break;
- #endif
-- break;
- }
- }
-
-@@ -2071,7 +2464,6 @@
- Guchar *alphaLine) {
- SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data;
- Guchar *p, *aq;
-- SplashColor maskColor;
- SplashColorPtr q, col;
- GfxRGB rgb;
- GfxGray gray;
-@@ -2079,25 +2471,35 @@
- GfxCMYK cmyk;
- #endif
- Guchar alpha;
-+ Guchar *maskPtr;
-+ int maskBit;
- int nComps, x;
-
- if (imgData->y == imgData->height) {
- return gFalse;
- }
-+ if (!(p = imgData->imgStr->getLine())) {
-+ return gFalse;
-+ }
-
- nComps = imgData->colorMap->getNumPixelComps();
-
-- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine;
-+ maskPtr = imgData->mask->getDataPtr() +
-+ imgData->y * imgData->mask->getRowSize();
-+ maskBit = 0x80;
-+ for (x = 0, q = colorLine, aq = alphaLine;
- x < imgData->width;
- ++x, p += nComps) {
-- imgData->mask->getPixel(x, imgData->y, maskColor);
-- alpha = maskColor[0] ? 0xff : 0x00;
-+ alpha = (*maskPtr & maskBit) ? 0xff : 0x00;
-+ if (!(maskBit >>= 1)) {
-+ ++maskPtr;
-+ maskBit = 0x80;
-+ }
- if (imgData->lookup) {
- switch (imgData->colorMode) {
- case splashModeMono1:
- case splashModeMono8:
- *q++ = imgData->lookup[*p];
-- *aq++ = alpha;
- break;
- case splashModeRGB8:
- case splashModeBGR8:
-@@ -2105,7 +2507,6 @@
- *q++ = col[0];
- *q++ = col[1];
- *q++ = col[2];
-- *aq++ = alpha;
- break;
- #if SPLASH_CMYK
- case splashModeCMYK8:
-@@ -2114,17 +2515,16 @@
- *q++ = col[1];
- *q++ = col[2];
- *q++ = col[3];
-- *aq++ = alpha;
- break;
- #endif
- }
-+ *aq++ = alpha;
- } else {
- switch (imgData->colorMode) {
- case splashModeMono1:
- case splashModeMono8:
- imgData->colorMap->getGray(p, &gray);
- *q++ = colToByte(gray);
-- *aq++ = alpha;
- break;
- case splashModeRGB8:
- case splashModeBGR8:
-@@ -2132,7 +2532,6 @@
- *q++ = colToByte(rgb.r);
- *q++ = colToByte(rgb.g);
- *q++ = colToByte(rgb.b);
-- *aq++ = alpha;
- break;
- #if SPLASH_CMYK
- case splashModeCMYK8:
-@@ -2141,10 +2540,10 @@
- *q++ = colToByte(cmyk.m);
- *q++ = colToByte(cmyk.y);
- *q++ = colToByte(cmyk.k);
-- *aq++ = alpha;
- break;
- #endif
- }
-+ *aq++ = alpha;
- }
- }
-
-@@ -2175,6 +2574,9 @@
- Guchar pix;
- int n, i;
-
-+ setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
-+ state->getOverprintMode(), NULL);
-+
- // If the mask is higher resolution than the image, use
- // drawSoftMaskedImage() instead.
- if (maskWidth > width || maskHeight > height) {
-@@ -2318,6 +2720,9 @@
- Guchar pix;
- int n, i;
-
-+ setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
-+ state->getOverprintMode(), NULL);
-+
- ctm = state->getCTM();
- mat[0] = ctm[0];
- mat[1] = ctm[1];
-@@ -2433,7 +2838,7 @@
- SplashTransparencyGroup *transpGroup;
- SplashColor color;
- double xMin, yMin, xMax, yMax, x, y;
-- int tx, ty, w, h;
-+ int tx, ty, w, h, i;
-
- // transform the bbox
- state->transform(bbox[0], bbox[1], &x, &y);
-@@ -2475,14 +2880,14 @@
- tx = (int)floor(xMin);
- if (tx < 0) {
- tx = 0;
-- } else if (tx > bitmap->getWidth()) {
-- tx = bitmap->getWidth();
-+ } else if (tx >= bitmap->getWidth()) {
-+ tx = bitmap->getWidth() - 1;
- }
- ty = (int)floor(yMin);
- if (ty < 0) {
- ty = 0;
-- } else if (ty > bitmap->getHeight()) {
-- ty = bitmap->getHeight();
-+ } else if (ty >= bitmap->getHeight()) {
-+ ty = bitmap->getHeight() - 1;
- }
- w = (int)ceil(xMax) - tx + 1;
- if (tx + w > bitmap->getWidth()) {
-@@ -2512,31 +2917,47 @@
- transpGroup->origBitmap = bitmap;
- transpGroup->origSplash = splash;
-
-- //~ this ignores the blendingColorSpace arg
-+ //~ this handles the blendingColorSpace arg for soft masks, but
-+ //~ not yet for transparency groups
-+
-+ // switch to the blending color space
-+ if (forSoftMask && isolated && blendingColorSpace) {
-+ if (blendingColorSpace->getMode() == csDeviceGray ||
-+ blendingColorSpace->getMode() == csCalGray ||
-+ (blendingColorSpace->getMode() == csICCBased &&
-+ blendingColorSpace->getNComps() == 1)) {
-+ colorMode = splashModeMono8;
-+ } else if (blendingColorSpace->getMode() == csDeviceRGB ||
-+ blendingColorSpace->getMode() == csCalRGB ||
-+ (blendingColorSpace->getMode() == csICCBased &&
-+ blendingColorSpace->getNComps() == 3)) {
-+ //~ does this need to use BGR8?
-+ colorMode = splashModeRGB8;
-+#if SPLASH_CMYK
-+ } else if (blendingColorSpace->getMode() == csDeviceCMYK ||
-+ (blendingColorSpace->getMode() == csICCBased &&
-+ blendingColorSpace->getNComps() == 4)) {
-+ colorMode = splashModeCMYK8;
-+#endif
-+ }
-+ }
-
- // create the temporary bitmap
- bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue,
- bitmapTopDown);
- splash = new Splash(bitmap, vectorAntialias,
- transpGroup->origSplash->getScreen());
-+ splash->setMinLineWidth(globalParams->getMinLineWidth());
-+ //~ Acrobat apparently copies at least the fill and stroke colors, and
-+ //~ maybe other state(?) -- but not the clipping path (and not sure
-+ //~ what else)
-+ //~ [this is likely the same situation as in type3D1()]
-+ splash->setFillPattern(transpGroup->origSplash->getFillPattern()->copy());
-+ splash->setStrokePattern(
-+ transpGroup->origSplash->getStrokePattern()->copy());
- if (isolated) {
-- switch (colorMode) {
-- case splashModeMono1:
-- case splashModeMono8:
-- color[0] = 0;
-- break;
-- case splashModeRGB8:
-- case splashModeBGR8:
-- color[0] = color[1] = color[2] = 0;
-- break;
--#if SPLASH_CMYK
-- case splashModeCMYK8:
-- color[0] = color[1] = color[2] = color[3] = 0;
-- break;
--#endif
-- default:
-- // make gcc happy
-- break;
-+ for (i = 0; i < splashMaxColorComps; ++i) {
-+ color[i] = 0;
- }
- splash->clear(color, 0);
- } else {
-@@ -2546,16 +2967,16 @@
- transpGroup->tBitmap = bitmap;
- state->shiftCTM(-tx, -ty);
- updateCTM(state, 0, 0, 0, 0, 0, 0);
-+ ++nestCount;
- }
-
- void SplashOutputDev::endTransparencyGroup(GfxState *state) {
-- double *ctm;
--
- // restore state
-+ --nestCount;
- delete splash;
- bitmap = transpGroupStack->origBitmap;
-+ colorMode = bitmap->getMode();
- splash = transpGroupStack->origSplash;
-- ctm = state->getCTM();
- state->shiftCTM(transpGroupStack->tx, transpGroupStack->ty);
- updateCTM(state, 0, 0, 0, 0, 0, 0);
- }
-@@ -2573,9 +2994,12 @@
-
- // paint the transparency group onto the parent bitmap
- // - the clip path was set in the parent's state)
-- splash->composite(tBitmap, 0, 0, tx, ty,
-- tBitmap->getWidth(), tBitmap->getHeight(),
-- gFalse, !isolated);
-+ if (tx < bitmap->getWidth() && ty < bitmap->getHeight()) {
-+ splash->setOverprintMask(0xffffffff);
-+ splash->composite(tBitmap, 0, 0, tx, ty,
-+ tBitmap->getWidth(), tBitmap->getHeight(),
-+ gFalse, !isolated);
-+ }
-
- // pop the stack
- transpGroup = transpGroupStack;
-@@ -2606,13 +3030,13 @@
- tBitmap = transpGroupStack->tBitmap;
-
- // composite with backdrop color
-- if (!alpha && colorMode != splashModeMono1) {
-+ if (!alpha && tBitmap->getMode() != splashModeMono1) {
- //~ need to correctly handle the case where no blending color
- //~ space is given
- tSplash = new Splash(tBitmap, vectorAntialias,
- transpGroupStack->origSplash->getScreen());
- if (transpGroupStack->blendingColorSpace) {
-- switch (colorMode) {
-+ switch (tBitmap->getMode()) {
- case splashModeMono1:
- // transparency is not supported in mono1 mode
- break;
-@@ -2648,36 +3072,38 @@
- 1, splashModeMono8, gFalse);
- memset(softMask->getDataPtr(), 0,
- softMask->getRowSize() * softMask->getHeight());
-- p = softMask->getDataPtr() + ty * softMask->getRowSize() + tx;
-- for (y = 0; y < tBitmap->getHeight(); ++y) {
-- for (x = 0; x < tBitmap->getWidth(); ++x) {
-- tBitmap->getPixel(x, y, color);
-- if (alpha) {
-- //~ unimplemented
-- } else {
-- // convert to luminosity
-- switch (colorMode) {
-- case splashModeMono1:
-- case splashModeMono8:
-- lum = color[0] / 255.0;
-- break;
-- case splashModeRGB8:
-- case splashModeBGR8:
-- lum = (0.3 / 255.0) * color[0] +
-- (0.59 / 255.0) * color[1] +
-- (0.11 / 255.0) * color[2];
-- break;
--#if SPLASH_CMYK
-- case splashModeCMYK8:
-- lum = (1 - color[4] / 255.0)
-- - (0.3 / 255.0) * color[0]
-- - (0.59 / 255.0) * color[1]
-- - (0.11 / 255.0) * color[2];
-- if (lum < 0) {
-- lum = 0;
-- }
-- break;
-+ if (tx < softMask->getWidth() && ty < softMask->getHeight()) {
-+ p = softMask->getDataPtr() + ty * softMask->getRowSize() + tx;
-+ for (y = 0; y < tBitmap->getHeight(); ++y) {
-+ for (x = 0; x < tBitmap->getWidth(); ++x) {
-+ if (alpha) {
-+ lum = tBitmap->getAlpha(x, y) / 255.0;
-+ } else {
-+ tBitmap->getPixel(x, y, color);
-+ // convert to luminosity
-+ switch (tBitmap->getMode()) {
-+ case splashModeMono1:
-+ case splashModeMono8:
-+ lum = color[0] / 255.0;
-+ break;
-+ case splashModeRGB8:
-+ case splashModeBGR8:
-+ lum = (0.3 / 255.0) * color[0] +
-+ (0.59 / 255.0) * color[1] +
-+ (0.11 / 255.0) * color[2];
-+ break;
-+#if SPLASH_CMYK
-+ case splashModeCMYK8:
-+ lum = (1 - color[3] / 255.0)
-+ - (0.3 / 255.0) * color[0]
-+ - (0.59 / 255.0) * color[1]
-+ - (0.11 / 255.0) * color[2];
-+ if (lum < 0) {
-+ lum = 0;
-+ }
-+ break;
- #endif
-+ }
- }
- if (transferFunc) {
- transferFunc->transform(&lum, &lum2);
-@@ -2686,8 +3112,8 @@
- }
- p[x] = (int)(lum2 * 255.0 + 0.5);
- }
-+ p += softMask->getRowSize();
- }
-- p += softMask->getRowSize();
- }
- splash->setSoftMask(softMask);
-
-@@ -2743,39 +3169,49 @@
- rgb.r = byteToCol(r);
- rgb.g = byteToCol(g);
- rgb.b = byteToCol(b);
-- gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g + 0.5);
-- if (gray > gfxColorComp1) {
-- gray = gfxColorComp1;
-- }
-+ switch (colorMode) {
-+ case splashModeMono1:
-+ case splashModeMono8:
-+ gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g + 0.5);
-+ if (gray > gfxColorComp1) {
-+ gray = gfxColorComp1;
-+ }
-+ splash->setFillPattern(getColor(gray));
-+ break;
-+ case splashModeRGB8:
-+ case splashModeBGR8:
-+ splash->setFillPattern(getColor(&rgb));
-+ break;
- #if SPLASH_CMYK
-- cmyk.c = gfxColorComp1 - rgb.r;
-- cmyk.m = gfxColorComp1 - rgb.g;
-- cmyk.y = gfxColorComp1 - rgb.b;
-- cmyk.k = 0;
-- splash->setFillPattern(getColor(gray, &rgb, &cmyk));
--#else
-- splash->setFillPattern(getColor(gray, &rgb));
-+ case splashModeCMYK8:
-+ cmyk.c = gfxColorComp1 - rgb.r;
-+ cmyk.m = gfxColorComp1 - rgb.g;
-+ cmyk.y = gfxColorComp1 - rgb.b;
-+ cmyk.k = 0;
-+ splash->setFillPattern(getColor(&cmyk));
-+ break;
- #endif
-+ }
- }
-
--SplashFont *SplashOutputDev::getFont(GString *name, double *textMatA) {
-- DisplayFontParam *dfp;
-+SplashFont *SplashOutputDev::getFont(GString *name, SplashCoord *textMatA) {
- Ref ref;
- SplashOutFontFileID *id;
-+ GfxFontLoc *fontLoc;
- SplashFontFile *fontFile;
- SplashFont *fontObj;
- FoFiTrueType *ff;
-- Gushort *codeToGID;
-+ int *codeToGID;
- Unicode u;
- SplashCoord textMat[4];
- int cmap, i;
-
-- for (i = 0; i < 16; ++i) {
-- if (!name->cmp(splashOutSubstFonts[i].name)) {
-+ for (i = 0; i < nBuiltinFonts; ++i) {
-+ if (!name->cmp(builtinFonts[i].name)) {
- break;
- }
- }
-- if (i == 16) {
-+ if (i == nBuiltinFonts) {
- return NULL;
- }
- ref.num = i;
-@@ -2788,12 +3224,16 @@
-
- // load the font file
- } else {
-- dfp = globalParams->getDisplayFont(name);
-- if (dfp && dfp->kind == displayFontT1) {
-- fontFile = fontEngine->loadType1Font(id, dfp->t1.fileName->getCString(),
-+ if (!(fontLoc = GfxFont::locateBase14Font(name))) {
-+ return NULL;
-+ }
-+ if (fontLoc->fontType == fontType1) {
-+ fontFile = fontEngine->loadType1Font(id, fontLoc->path->getCString(),
- gFalse, winAnsiEncoding);
-- } else if (dfp && dfp->kind == displayFontTT) {
-- if (!(ff = FoFiTrueType::load(dfp->tt.fileName->getCString()))) {
-+ } else if (fontLoc->fontType == fontTrueType) {
-+ if (!(ff = FoFiTrueType::load(fontLoc->path->getCString()))) {
-+ delete fontLoc;
-+ delete id;
- return NULL;
- }
- for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) {
-@@ -2805,9 +3245,11 @@
- }
- if (cmap == ff->getNumCmaps()) {
- delete ff;
-+ delete fontLoc;
-+ delete id;
- return NULL;
- }
-- codeToGID = (Gushort *)gmallocn(256, sizeof(Gushort));
-+ codeToGID = (int *)gmallocn(256, sizeof(int));
- for (i = 0; i < 256; ++i) {
- codeToGID[i] = 0;
- if (winAnsiEncoding[i] &&
-@@ -2817,11 +3259,18 @@
- }
- delete ff;
- fontFile = fontEngine->loadTrueTypeFont(id,
-- dfp->tt.fileName->getCString(),
-- gFalse, codeToGID, 256);
-+ fontLoc->path->getCString(),
-+ fontLoc->fontNum,
-+ gFalse, codeToGID, 256, NULL);
- } else {
-+ delete fontLoc;
-+ delete id;
- return NULL;
- }
-+ delete fontLoc;
-+ }
-+ if (!fontFile) {
-+ return NULL;
- }
-
- // create the scaled font
-@@ -2835,11 +3284,7 @@
- }
-
- #if 1 //~tmp: turn off anti-aliasing temporarily
--GBool SplashOutputDev::getVectorAntialias() {
-- return splash->getVectorAntialias();
--}
--
--void SplashOutputDev::setVectorAntialias(GBool vaa) {
-- splash->setVectorAntialias(vaa);
-+void SplashOutputDev::setInShading(GBool sh) {
-+ splash->setInShading(sh);
- }
- #endif
-diff -ru xpdf-3.02/xpdf/SplashOutputDev.h xpdf-3.03/xpdf/SplashOutputDev.h
---- xpdf-3.02/xpdf/SplashOutputDev.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/SplashOutputDev.h 2011-08-15 23:08:53.000000000 +0200
-@@ -58,15 +58,21 @@
-
- // Does this device use upside-down coordinates?
- // (Upside-down means (0,0) is the top left corner of the page.)
-- virtual GBool upsideDown() { return gTrue; }
-+ virtual GBool upsideDown() { return bitmapTopDown ^ bitmapUpsideDown; }
-
- // Does this device use drawChar() or drawString()?
- virtual GBool useDrawChar() { return gTrue; }
-
-+ // Does this device use tilingPatternFill()? If this returns false,
-+ // tiling pattern fills will be reduced to a series of other drawing
-+ // operations.
-+ virtual GBool useTilingPatternFill() { return gTrue; }
-+
- // Does this device use beginType3Char/endType3Char? Otherwise,
- // text in Type 3 fonts will be drawn with drawChar/drawString.
- virtual GBool interpretType3Chars() { return gTrue; }
-
-+
- //----- initialization and control
-
- // Start a page.
-@@ -103,6 +110,11 @@
- virtual void stroke(GfxState *state);
- virtual void fill(GfxState *state);
- virtual void eoFill(GfxState *state);
-+ virtual void tilingPatternFill(GfxState *state, Gfx *gfx, Object *str,
-+ int paintType, Dict *resDict,
-+ double *mat, double *bbox,
-+ int x0, int y0, int x1, int y1,
-+ double xStep, double yStep);
-
- //----- path clipping
- virtual void clip(GfxState *state);
-@@ -124,6 +136,10 @@
- virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
- int width, int height, GBool invert,
- GBool inlineImg);
-+ virtual void setSoftMaskFromImageMask(GfxState *state,
-+ Object *ref, Stream *str,
-+ int width, int height, GBool invert,
-+ GBool inlineImg);
- virtual void drawImage(GfxState *state, Object *ref, Stream *str,
- int width, int height, GfxImageColorMap *colorMap,
- int *maskColors, GBool inlineImg);
-@@ -174,6 +190,10 @@
- // caller.
- SplashBitmap *takeBitmap();
-
-+ // Set this flag to true to generate an upside-down bitmap (useful
-+ // for Windows BMP files).
-+ void setBitmapUpsideDown(GBool f) { bitmapUpsideDown = f; }
-+
- // Get the Splash object.
- Splash *getSplash() { return splash; }
-
-@@ -187,26 +207,36 @@
- void setFillColor(int r, int g, int b);
-
- // Get a font object for a Base-14 font, using the Latin-1 encoding.
-- SplashFont *getFont(GString *name, double *textMatA);
-+ SplashFont *getFont(GString *name, SplashCoord *textMatA);
-
- SplashFont *getCurrentFont() { return font; }
-
-+ // If <skipTextA> is true, don't draw horizontal text.
-+ // If <skipRotatedTextA> is true, don't draw rotated (non-horizontal) text.
-+ void setSkipText(GBool skipHorizTextA, GBool skipRotatedTextA)
-+ { skipHorizText = skipHorizTextA; skipRotatedText = skipRotatedTextA; }
-+
-+ int getNestCount() { return nestCount; }
-+
-+
- #if 1 //~tmp: turn off anti-aliasing temporarily
-- virtual GBool getVectorAntialias();
-- virtual void setVectorAntialias(GBool vaa);
-+ virtual void setInShading(GBool sh);
- #endif
-
- private:
-
- void setupScreenParams(double hDPI, double vDPI);
-+ SplashPattern *getColor(GfxGray gray);
-+ SplashPattern *getColor(GfxRGB *rgb);
- #if SPLASH_CMYK
-- SplashPattern *getColor(GfxGray gray, GfxRGB *rgb, GfxCMYK *cmyk);
--#else
-- SplashPattern *getColor(GfxGray gray, GfxRGB *rgb);
-+ SplashPattern *getColor(GfxCMYK *cmyk);
- #endif
-@@ -219,11 +249,14 @@
- SplashColorMode colorMode;
- int bitmapRowPad;
- GBool bitmapTopDown;
-+ GBool bitmapUpsideDown;
- GBool allowAntialias;
- GBool vectorAntialias;
- GBool reverseVideo; // reverse video mode
- SplashColor paperColor; // paper color
- SplashScreenParams screenParams;
-+ GBool skipHorizText;
-+ GBool skipRotatedText;
-
- XRef *xref; // xref table for current document
-
-@@ -235,6 +268,7 @@
- t3FontCache[splashOutT3FontCacheSize];
- int nT3Fonts; // number of valid entries in t3FontCache
- T3GlyphStack *t3GlyphStack; // Type 3 glyph context stack
-+ GBool haveT3Dx; // set after seeing a d0/d1 operator
-
- SplashFont *font; // current font
- GBool needFontUpdate; // set when the font needs to be updated
-@@ -242,6 +276,8 @@
-
- SplashTransparencyGroup * // transparency group stack
- transpGroupStack;
-+
-+ int nestCount;
- };
-
- #endif
-diff -ru xpdf-3.02/xpdf/TextOutputDev.cc xpdf-3.03/xpdf/TextOutputDev.cc
---- xpdf-3.02/xpdf/TextOutputDev.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/TextOutputDev.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -545,7 +618,7 @@
-
- // insert the new word
- if (cursor && wordBaseIdx == cursorBaseIdx &&
-- word->primaryCmp(cursor) > 0) {
-+ word->primaryCmp(cursor) >= 0) {
- w0 = cursor;
- w1 = cursor->next;
- } else {
-@@ -928,7 +1001,7 @@
- xMax = blk->xMin + d1 * (blk->xMax - blk->xMin);
- yMin = blk->yMin + d2 * (blk->yMax - blk->yMin);
- yMax = blk->yMin + d3 * (blk->yMax - blk->yMin);
-- base = blk->yMin + base * (blk->yMax - blk->yMin);
-+ base = blk->yMin + d4 * (blk->yMax - blk->yMin);
- break;
- case 1:
- xMin = blk->xMax - d3 * (blk->xMax - blk->xMin);
-@@ -1150,15 +1223,15 @@
- }
- }
-
--void TextBlock::coalesce(UnicodeMap *uMap) {
-+void TextBlock::coalesce(UnicodeMap *uMap, double fixedPitch) {
- TextWord *word0, *word1, *word2, *bestWord0, *bestWord1, *lastWord;
- TextLine *line, *line0, *line1;
- int poolMinBaseIdx, startBaseIdx, minBaseIdx, maxBaseIdx;
- int baseIdx, bestWordBaseIdx, idx0, idx1;
- double minBase, maxBase;
-- double fontSize, delta, priDelta, secDelta;
-+ double fontSize, wordSpacing, delta, priDelta, secDelta;
- TextLine **lineArray;
-- GBool found;
-+ GBool found, overlap;
- int col1, col2;
- int i, j, k;
-
-@@ -1168,11 +1241,7 @@
- while (word0) {
- priDelta = dupMaxPriDelta * word0->fontSize;
- secDelta = dupMaxSecDelta * word0->fontSize;
-- if (rot == 0 || rot == 3) {
-- maxBaseIdx = pool->getBaseIdx(word0->base + secDelta);
-- } else {
-- maxBaseIdx = pool->getBaseIdx(word0->base - secDelta);
-- }
-+ maxBaseIdx = pool->getBaseIdx(word0->base + secDelta);
- found = gFalse;
- word1 = word2 = NULL; // make gcc happy
- for (idx1 = idx0; idx1 <= maxBaseIdx; ++idx1) {
-@@ -1269,6 +1338,7 @@
- maxBase = word0->base + maxIntraLineDelta * fontSize;
- minBaseIdx = pool->getBaseIdx(minBase);
- maxBaseIdx = pool->getBaseIdx(maxBase);
-+ wordSpacing = fixedPitch ? fixedPitch : maxWordSpacing * fontSize;
-
- // find the rest of the words in this line
- while (1) {
-@@ -1277,25 +1347,32 @@
- // this line
- bestWordBaseIdx = 0;
- bestWord0 = bestWord1 = NULL;
-- for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) {
-+ overlap = gFalse;
-+ for (baseIdx = minBaseIdx;
-+ !overlap && baseIdx <= maxBaseIdx;
-+ ++baseIdx) {
- for (word0 = NULL, word1 = pool->getPool(baseIdx);
- word1;
- word0 = word1, word1 = word1->next) {
- if (word1->base >= minBase &&
-- word1->base <= maxBase &&
-- (delta = lastWord->primaryDelta(word1)) >=
-- minCharSpacing * fontSize) {
-- if (delta < maxWordSpacing * fontSize &&
-- (!bestWord1 || word1->primaryCmp(bestWord1) < 0)) {
-- bestWordBaseIdx = baseIdx;
-- bestWord0 = word0;
-- bestWord1 = word1;
-+ word1->base <= maxBase) {
-+ delta = lastWord->primaryDelta(word1);
-+ if (delta < minCharSpacing * fontSize) {
-+ overlap = gTrue;
-+ break;
-+ } else {
-+ if (delta < wordSpacing &&
-+ (!bestWord1 || word1->primaryCmp(bestWord1) < 0)) {
-+ bestWordBaseIdx = baseIdx;
-+ bestWord0 = word0;
-+ bestWord1 = word1;
-+ }
-+ break;
- }
-- break;
- }
- }
- }
-- if (!bestWord1) {
-+ if (overlap || !bestWord1) {
- break;
- }
-
-@@ -1342,52 +1419,79 @@
-
- // column assignment
- nColumns = 0;
-- for (i = 0; i < nLines; ++i) {
-- line0 = lineArray[i];
-- col1 = 0;
-- for (j = 0; j < i; ++j) {
-- line1 = lineArray[j];
-- if (line1->primaryDelta(line0) >= 0) {
-- col2 = line1->col[line1->len] + 1;
-- } else {
-- k = 0; // make gcc happy
-- switch (rot) {
-- case 0:
-- for (k = 0;
-- k < line1->len &&
-- line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
-- ++k) ;
-- break;
-- case 1:
-- for (k = 0;
-- k < line1->len &&
-- line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
-- ++k) ;
-- break;
-- case 2:
-- for (k = 0;
-- k < line1->len &&
-- line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
-- ++k) ;
-- break;
-- case 3:
-- for (k = 0;
-- k < line1->len &&
-- line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
-- ++k) ;
-- break;
-- }
-- col2 = line1->col[k];
-+ if (fixedPitch) {
-+ for (i = 0; i < nLines; ++i) {
-+ line0 = lineArray[i];
-+ col1 = 0; // make gcc happy
-+ switch (rot) {
-+ case 0:
-+ col1 = (int)((line0->xMin - xMin) / fixedPitch + 0.5);
-+ break;
-+ case 1:
-+ col1 = (int)((line0->yMin - yMin) / fixedPitch + 0.5);
-+ break;
-+ case 2:
-+ col1 = (int)((xMax - line0->xMax) / fixedPitch + 0.5);
-+ break;
-+ case 3:
-+ col1 = (int)((yMax - line0->yMax) / fixedPitch + 0.5);
-+ break;
- }
-- if (col2 > col1) {
-- col1 = col2;
-+ for (k = 0; k <= line0->len; ++k) {
-+ line0->col[k] += col1;
-+ }
-+ if (line0->col[line0->len] > nColumns) {
-+ nColumns = line0->col[line0->len];
- }
- }
-- for (k = 0; k <= line0->len; ++k) {
-- line0->col[k] += col1;
-- }
-- if (line0->col[line0->len] > nColumns) {
-- nColumns = line0->col[line0->len];
-+ } else {
-+ for (i = 0; i < nLines; ++i) {
-+ line0 = lineArray[i];
-+ col1 = 0;
-+ for (j = 0; j < i; ++j) {
-+ line1 = lineArray[j];
-+ if (line1->primaryDelta(line0) >= 0) {
-+ col2 = line1->col[line1->len] + 1;
-+ } else {
-+ k = 0; // make gcc happy
-+ switch (rot) {
-+ case 0:
-+ for (k = 0;
-+ k < line1->len &&
-+ line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
-+ ++k) ;
-+ break;
-+ case 1:
-+ for (k = 0;
-+ k < line1->len &&
-+ line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
-+ ++k) ;
-+ break;
-+ case 2:
-+ for (k = 0;
-+ k < line1->len &&
-+ line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
-+ ++k) ;
-+ break;
-+ case 3:
-+ for (k = 0;
-+ k < line1->len &&
-+ line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
-+ ++k) ;
-+ break;
-+ }
-+ col2 = line1->col[k];
-+ }
-+ if (col2 > col1) {
-+ col1 = col2;
-+ }
-+ }
-+ for (k = 0; k <= line0->len; ++k) {
-+ line0->col[k] += col1;
-+ }
-+ if (line0->col[line0->len] > nColumns) {
-+ nColumns = line0->col[line0->len];
-+ }
- }
- }
- gfree(lineArray);
-@@ -1744,6 +1848,9 @@
- nest = 0;
- nTinyChars = 0;
- lastCharOverlap = gFalse;
-+ actualText = NULL;
-+ actualTextLen = 0;
-+ actualTextNBytes = 0;
- if (!rawOrder) {
- for (rot = 0; rot < 4; ++rot) {
- pools[rot] = new TextPool();
-@@ -1799,6 +1906,7 @@
- delete curWord;
- curWord = NULL;
- }
-+ gfree(actualText);
- if (rawOrder) {
- while (rawWords) {
- word = rawWords;
-@@ -1817,6 +1925,8 @@
- gfree(blocks);
- }
- deleteGList(fonts, TextFontInfo);
-+ deleteGList(underlines, TextUnderline);
-+ deleteGList(links, TextLink);
-
- curWord = NULL;
- charPos = 0;
-@@ -1824,6 +1934,9 @@
- curFontSize = 0;
- nest = 0;
- nTinyChars = 0;
-+ actualText = NULL;
-+ actualTextLen = 0;
-+ actualTextNBytes = 0;
- if (!rawOrder) {
- for (rot = 0; rot < 4; ++rot) {
- pools[rot] = new TextPool();
-@@ -1834,6 +1947,8 @@
- rawWords = NULL;
- rawLastWord = NULL;
- fonts = new GList();
-+ underlines = new GList();
-+ links = new GList();
- }
-
- void TextPage::updateFont(GfxState *state) {
-@@ -1993,7 +2124,7 @@
- // (2) this character overlaps the previous one (duplicated text), or
- // (3) the previous character was an overlap (we want each duplicated
- // character to be in a word by itself at this stage),
-- // (4) the font size has changed
-+ // (4) the font or font size has changed
- if (curWord && curWord->len > 0) {
- base = sp = delta = 0; // make gcc happy
- switch (curWord->rot) {
-@@ -2024,6 +2155,7 @@
- sp < -minDupBreakOverlap * curWord->fontSize ||
- sp > minWordBreakSpace * curWord->fontSize ||
- fabs(base - curWord->base) > 0.5 ||
-+ curFont != curWord->font ||
- curFontSize != curWord->fontSize) {
- endWord();
- }
-@@ -2057,15 +2189,46 @@
- }
- }
- charPos += nBytes;
- }
-
-+void TextPage::incCharCount(int nChars) {
-+ charPos += nChars;
-+}
-+
-@@ -2109,7 +2272,7 @@
- links->append(new TextLink(xMin, yMin, xMax, yMax, link));
- }
-
--void TextPage::coalesce(GBool physLayout, GBool doHTML) {
-+void TextPage::coalesce(GBool physLayout, double fixedPitch, GBool doHTML) {
- UnicodeMap *uMap;
- TextPool *pool;
- TextWord *word0, *word1, *word2;
-@@ -2139,7 +2302,7 @@
- blkList = NULL;
- lastBlk = NULL;
- nBlocks = 0;
-- primaryRot = -1;
-+ primaryRot = 0;
-
- #if 0 // for debugging
- printf("*** initial words ***\n");
-@@ -2603,7 +2766,7 @@
- //~ addition to primary rotation
-
- // coalesce the block, and add it to the list
-- blk->coalesce(uMap);
-+ blk->coalesce(uMap, fixedPitch);
- if (lastBlk) {
- lastBlk->next = blk;
- } else {
-@@ -2611,11 +2774,12 @@
- }
- lastBlk = blk;
- count[rot] += blk->charCount;
-- if (primaryRot < 0 || count[rot] > count[primaryRot]) {
-- primaryRot = rot;
-- }
- ++nBlocks;
- }
-+
-+ if (count[rot] > count[primaryRot]) {
-+ primaryRot = rot;
-+ }
- }
-
- #if 0 // for debugging
-@@ -2674,76 +2838,108 @@
-
- //----- column assignment
-
-- // sort blocks into xy order for column assignment
-- blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
-- for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
-- blocks[i] = blk;
-- }
-- qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot);
-+ if (physLayout && fixedPitch) {
-
-- // column assignment
-- for (i = 0; i < nBlocks; ++i) {
-- blk0 = blocks[i];
-- col1 = 0;
-- for (j = 0; j < i; ++j) {
-- blk1 = blocks[j];
-- col2 = 0; // make gcc happy
-+ blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
-+ for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
-+ blocks[i] = blk;
-+ col1 = 0; // make gcc happy
- switch (primaryRot) {
- case 0:
-- if (blk0->xMin > blk1->xMax) {
-- col2 = blk1->col + blk1->nColumns + 3;
-- } else if (blk1->xMax == blk1->xMin) {
-- col2 = blk1->col;
-- } else {
-- col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) /
-- (blk1->xMax - blk1->xMin)) *
-- blk1->nColumns);
-- }
-+ col1 = (int)(blk->xMin / fixedPitch + 0.5);
- break;
- case 1:
-- if (blk0->yMin > blk1->yMax) {
-- col2 = blk1->col + blk1->nColumns + 3;
-- } else if (blk1->yMax == blk1->yMin) {
-- col2 = blk1->col;
-- } else {
-- col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) /
-- (blk1->yMax - blk1->yMin)) *
-- blk1->nColumns);
-- }
-+ col1 = (int)(blk->yMin / fixedPitch + 0.5);
- break;
- case 2:
-- if (blk0->xMax < blk1->xMin) {
-- col2 = blk1->col + blk1->nColumns + 3;
-- } else if (blk1->xMin == blk1->xMax) {
-- col2 = blk1->col;
-- } else {
-- col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) /
-- (blk1->xMin - blk1->xMax)) *
-- blk1->nColumns);
-- }
-+ col1 = (int)((pageWidth - blk->xMax) / fixedPitch + 0.5);
- break;
- case 3:
-- if (blk0->yMax < blk1->yMin) {
-- col2 = blk1->col + blk1->nColumns + 3;
-- } else if (blk1->yMin == blk1->yMax) {
-- col2 = blk1->col;
-- } else {
-- col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) /
-- (blk1->yMin - blk1->yMax)) *
-- blk1->nColumns);
-- }
-+ col1 = (int)((pageHeight - blk->yMax) / fixedPitch + 0.5);
- break;
- }
-- if (col2 > col1) {
-- col1 = col2;
-+ blk->col = col1;
-+ for (line = blk->lines; line; line = line->next) {
-+ for (j = 0; j <= line->len; ++j) {
-+ line->col[j] += col1;
-+ }
- }
- }
-- blk0->col = col1;
-- for (line = blk0->lines; line; line = line->next) {
-- for (j = 0; j <= line->len; ++j) {
-- line->col[j] += col1;
-+
-+ } else {
-+
-+ // sort blocks into xy order for column assignment
-+ blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
-+ for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
-+ blocks[i] = blk;
-+ }
-+ qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot);
-+
-+ // column assignment
-+ for (i = 0; i < nBlocks; ++i) {
-+ blk0 = blocks[i];
-+ col1 = 0;
-+ for (j = 0; j < i; ++j) {
-+ blk1 = blocks[j];
-+ col2 = 0; // make gcc happy
-+ switch (primaryRot) {
-+ case 0:
-+ if (blk0->xMin > blk1->xMax) {
-+ col2 = blk1->col + blk1->nColumns + 3;
-+ } else if (blk1->xMax == blk1->xMin) {
-+ col2 = blk1->col;
-+ } else {
-+ col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) /
-+ (blk1->xMax - blk1->xMin)) *
-+ blk1->nColumns);
-+ }
-+ break;
-+ case 1:
-+ if (blk0->yMin > blk1->yMax) {
-+ col2 = blk1->col + blk1->nColumns + 3;
-+ } else if (blk1->yMax == blk1->yMin) {
-+ col2 = blk1->col;
-+ } else {
-+ col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) /
-+ (blk1->yMax - blk1->yMin)) *
-+ blk1->nColumns);
-+ }
-+ break;
-+ case 2:
-+ if (blk0->xMax < blk1->xMin) {
-+ col2 = blk1->col + blk1->nColumns + 3;
-+ } else if (blk1->xMin == blk1->xMax) {
-+ col2 = blk1->col;
-+ } else {
-+ col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) /
-+ (blk1->xMin - blk1->xMax)) *
-+ blk1->nColumns);
-+ }
-+ break;
-+ case 3:
-+ if (blk0->yMax < blk1->yMin) {
-+ col2 = blk1->col + blk1->nColumns + 3;
-+ } else if (blk1->yMin == blk1->yMax) {
-+ col2 = blk1->col;
-+ } else {
-+ col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) /
-+ (blk1->yMin - blk1->yMax)) *
-+ blk1->nColumns);
-+ }
-+ break;
-+ }
-+ if (col2 > col1) {
-+ col1 = col2;
-+ }
-+ }
-+ blk0->col = col1;
-+ for (line = blk0->lines; line; line = line->next) {
-+ for (j = 0; j <= line->len; ++j) {
-+ line->col[j] += col1;
-+ }
- }
- }
-+
- }
-
- #if 0 // for debugging
-@@ -2753,7 +2949,7 @@
- blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->col,
- blk->nColumns);
- for (line = blk->lines; line; line = line->next) {
-- printf(" line:\n");
-+ printf(" line: col[0]=%d\n", line->col[0]);
- for (word0 = line->words; word0; word0 = word0->next) {
- printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
- word0->xMin, word0->xMax, word0->yMin, word0->yMax,
-@@ -2932,6 +3128,7 @@
- GBool startAtTop, GBool stopAtBottom,
- GBool startAtLast, GBool stopAtLast,
- GBool caseSensitive, GBool backward,
-+ GBool wholeWord,
- double *xMin, double *yMin,
- double *xMax, double *yMax) {
- TextBlock *blk;
-@@ -2989,25 +3186,35 @@
- blk = blocks[i];
-
- // check: is the block above the top limit?
-- if (!startAtTop && (backward ? blk->yMin > yStart : blk->yMax < yStart)) {
-+ // (this only works if the page's primary rotation is zero --
-+ // otherwise the blocks won't be sorted in the useful order)
-+ if (!startAtTop && primaryRot == 0 &&
-+ (backward ? blk->yMin > yStart : blk->yMax < yStart)) {
- continue;
- }
-
- // check: is the block below the bottom limit?
-- if (!stopAtBottom && (backward ? blk->yMax < yStop : blk->yMin > yStop)) {
-+ // (this only works if the page's primary rotation is zero --
-+ // otherwise the blocks won't be sorted in the useful order)
-+ if (!stopAtBottom && primaryRot == 0 &&
-+ (backward ? blk->yMax < yStop : blk->yMin > yStop)) {
- break;
- }
-
- for (line = blk->lines; line; line = line->next) {
-
- // check: is the line above the top limit?
-- if (!startAtTop &&
-+ // (this only works if the page's primary rotation is zero --
-+ // otherwise the lines won't be sorted in the useful order)
-+ if (!startAtTop && primaryRot == 0 &&
- (backward ? line->yMin > yStart : line->yMin < yStart)) {
- continue;
- }
-
- // check: is the line below the bottom limit?
-- if (!stopAtBottom &&
-+ // (this only works if the page's primary rotation is zero --
-+ // otherwise the lines won't be sorted in the useful order)
-+ if (!stopAtBottom && primaryRot == 0 &&
- (backward ? line->yMin < yStop : line->yMin > yStop)) {
- continue;
- }
-@@ -3030,68 +3237,72 @@
- j = backward ? m - len : 0;
- p = txt + j;
- while (backward ? j >= 0 : j <= m - len) {
--
-- // compare the strings
-- for (k = 0; k < len; ++k) {
-- if (p[k] != s2[k]) {
-- break;
-+ if (!wholeWord ||
-+ ((j == 0 || !unicodeTypeAlphaNum(txt[j - 1])) &&
-+ (j + len == m || !unicodeTypeAlphaNum(txt[j + len])))) {
-+
-+ // compare the strings
-+ for (k = 0; k < len; ++k) {
-+ if (p[k] != s2[k]) {
-+ break;
-+ }
- }
-- }
-
-- // found it
-- if (k == len) {
-- switch (line->rot) {
-- case 0:
-- xMin1 = line->edge[j];
-- xMax1 = line->edge[j + len];
-- yMin1 = line->yMin;
-- yMax1 = line->yMax;
-- break;
-- case 1:
-- xMin1 = line->xMin;
-- xMax1 = line->xMax;
-- yMin1 = line->edge[j];
-- yMax1 = line->edge[j + len];
-- break;
-- case 2:
-- xMin1 = line->edge[j + len];
-- xMax1 = line->edge[j];
-- yMin1 = line->yMin;
-- yMax1 = line->yMax;
-- break;
-- case 3:
-- xMin1 = line->xMin;
-- xMax1 = line->xMax;
-- yMin1 = line->edge[j + len];
-- yMax1 = line->edge[j];
-- break;
-- }
-- if (backward) {
-- if ((startAtTop ||
-- yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) &&
-- (stopAtBottom ||
-- yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) {
-- if (!found ||
-- yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) {
-- xMin0 = xMin1;
-- xMax0 = xMax1;
-- yMin0 = yMin1;
-- yMax0 = yMax1;
-- found = gTrue;
-- }
-+ // found it
-+ if (k == len) {
-+ switch (line->rot) {
-+ case 0:
-+ xMin1 = line->edge[j];
-+ xMax1 = line->edge[j + len];
-+ yMin1 = line->yMin;
-+ yMax1 = line->yMax;
-+ break;
-+ case 1:
-+ xMin1 = line->xMin;
-+ xMax1 = line->xMax;
-+ yMin1 = line->edge[j];
-+ yMax1 = line->edge[j + len];
-+ break;
-+ case 2:
-+ xMin1 = line->edge[j + len];
-+ xMax1 = line->edge[j];
-+ yMin1 = line->yMin;
-+ yMax1 = line->yMax;
-+ break;
-+ case 3:
-+ xMin1 = line->xMin;
-+ xMax1 = line->xMax;
-+ yMin1 = line->edge[j + len];
-+ yMax1 = line->edge[j];
-+ break;
- }
-- } else {
-- if ((startAtTop ||
-- yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
-- (stopAtBottom ||
-- yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) {
-- if (!found ||
-- yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
-- xMin0 = xMin1;
-- xMax0 = xMax1;
-- yMin0 = yMin1;
-- yMax0 = yMax1;
-- found = gTrue;
-+ if (backward) {
-+ if ((startAtTop ||
-+ yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) &&
-+ (stopAtBottom ||
-+ yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) {
-+ if (!found ||
-+ yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) {
-+ xMin0 = xMin1;
-+ xMax0 = xMax1;
-+ yMin0 = yMin1;
-+ yMax0 = yMax1;
-+ found = gTrue;
-+ }
-+ }
-+ } else {
-+ if ((startAtTop ||
-+ yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
-+ (stopAtBottom ||
-+ yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) {
-+ if (!found ||
-+ yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
-+ xMin0 = xMin1;
-+ xMax0 = xMax1;
-+ yMin0 = yMin1;
-+ yMax0 = yMax1;
-+ found = gTrue;
-+ }
- }
- }
- }
-@@ -3820,10 +4038,20 @@
- fwrite(text, 1, len, (FILE *)stream);
- }
-
- TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA,
-- GBool rawOrderA, GBool append) {
-+ double fixedPitchA, GBool rawOrderA,
-+ GBool append) {
- text = NULL;
- physLayout = physLayoutA;
-+ fixedPitch = physLayout ? fixedPitchA : 0;
- rawOrder = rawOrderA;
- doHTML = gFalse;
- ok = gTrue;
-@@ -3854,11 +4074,13 @@
- }
-
- TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream,
-- GBool physLayoutA, GBool rawOrderA) {
-+ GBool physLayoutA, double fixedPitchA,
-+ GBool rawOrderA) {
- outputFunc = func;
- outputStream = stream;
- needClose = gFalse;
- physLayout = physLayoutA;
-+ fixedPitch = physLayout ? fixedPitchA : 0;
- rawOrder = rawOrderA;
- doHTML = gFalse;
- text = new TextPage(rawOrderA);
-@@ -3883,12 +4105,16 @@
-
- void TextOutputDev::endPage() {
- text->endPage();
-- text->coalesce(physLayout, doHTML);
-+ text->coalesce(physLayout, fixedPitch, doHTML);
- if (outputStream) {
- text->dump(outputStream, outputFunc, physLayout);
- }
- }
-
-+void TextOutputDev::restoreState(GfxState *state) {
-+ text->updateFont(state);
-+}
-+
- void TextOutputDev::updateFont(GfxState *state) {
- text->updateFont(state);
- }
-@@ -3903,7 +4129,19 @@
- double dx, double dy,
- double originX, double originY,
- CharCode c, int nBytes, Unicode *u, int uLen) {
-- text->addChar(state, x, y, dx, dy, c, nBytes, u, uLen);
-+ text->addChar(state, x - originX, y - originY, dx, dy, c, nBytes, u, uLen);
-+}
-+
-+void TextOutputDev::incCharCount(int nChars) {
-+ text->incCharCount(nChars);
-+}
-+
-@@ -4057,10 +4295,12 @@
- GBool startAtTop, GBool stopAtBottom,
- GBool startAtLast, GBool stopAtLast,
- GBool caseSensitive, GBool backward,
-+ GBool wholeWord,
- double *xMin, double *yMin,
- double *xMax, double *yMax) {
- return text->findText(s, len, startAtTop, stopAtBottom,
-- startAtLast, stopAtLast, caseSensitive, backward,
-+ startAtLast, stopAtLast,
-+ caseSensitive, backward, wholeWord,
- xMin, yMin, xMax, yMax);
- }
-
-diff -ru xpdf-3.02/xpdf/TextOutputDev.h xpdf-3.03/xpdf/TextOutputDev.h
---- xpdf-3.02/xpdf/TextOutputDev.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/TextOutputDev.h 2011-08-15 23:08:53.000000000 +0200
-@@ -280,7 +281,7 @@
-
- void addWord(TextWord *word);
-
-- void coalesce(UnicodeMap *uMap);
-+ void coalesce(UnicodeMap *uMap, double fixedPitch);
-
- // Update this block's priMin and priMax values, looking at <blk>.
- void updatePriMinMax(TextBlock *blk);
-@@ -429,6 +430,15 @@
- double dx, double dy,
- CharCode c, int nBytes, Unicode *u, int uLen);
-
-+ // Add <nChars> invisible characters.
-+ void incCharCount(int nChars);
-+
-@@ -442,7 +452,7 @@
- void addLink(int xMin, int yMin, int xMax, int yMax, Link *link);
-
- // Coalesce strings that look like parts of the same line.
-- void coalesce(GBool physLayout, GBool doHTML);
-+ void coalesce(GBool physLayout, double fixedPitch, GBool doHTML);
-
- // Find a string. If <startAtTop> is true, starts looking at the
- // top of the page; else if <startAtLast> is true, starts looking
-@@ -455,6 +465,7 @@
- GBool startAtTop, GBool stopAtBottom,
- GBool startAtLast, GBool stopAtLast,
- GBool caseSensitive, GBool backward,
-+ GBool wholeWord,
- double *xMin, double *yMin,
- double *xMax, double *yMax);
-
-@@ -502,6 +513,13 @@
- int nTinyChars; // number of "tiny" chars seen so far
- GBool lastCharOverlap; // set if the last added char overlapped the
- // previous char
-@@ -544,14 +562,16 @@
- // is maintained. If <rawOrder> is true, the text is kept in
- // content stream order.
- TextOutputDev(char *fileName, GBool physLayoutA,
-- GBool rawOrderA, GBool append);
-+ double fixedPitchA, GBool rawOrderA,
-+ GBool append);
-
- // Create a TextOutputDev which will write to a generic stream. If
- // <physLayoutA> is true, the original physical layout of the text
- // is maintained. If <rawOrder> is true, the text is kept in
- // content stream order.
- TextOutputDev(TextOutputFunc func, void *stream,
-- GBool physLayoutA, GBool rawOrderA);
-+ GBool physLayoutA, double fixedPitchA,
-+ GBool rawOrderA);
-
- // Destructor.
- virtual ~TextOutputDev();
-@@ -575,6 +595,10 @@
- // Does this device need non-text content?
- virtual GBool needNonText() { return gFalse; }
-
-+ // Does this device require incCharCount to be called for text on
-+ // non-shown layers?
-+ virtual GBool needCharCount() { return gTrue; }
-+
- //----- initialization and control
-
- // Start a page.
-@@ -583,6 +607,9 @@
- // End a page.
- virtual void endPage();
-
-+ //----- save/restore graphics state
-+ virtual void restoreState(GfxState *state);
-+
- //----- update text state
- virtual void updateFont(GfxState *state);
-
-@@ -593,6 +620,9 @@
- double dx, double dy,
- double originX, double originY,
- CharCode c, int nBytes, Unicode *u, int uLen);
-+ virtual void incCharCount(int nChars);
-@@ -615,6 +645,7 @@
- GBool startAtTop, GBool stopAtBottom,
- GBool startAtLast, GBool stopAtLast,
- GBool caseSensitive, GBool backward,
-+ GBool wholeWord,
- double *xMin, double *yMin,
- double *xMax, double *yMax);
-
-@@ -653,6 +684,9 @@
- TextPage *text; // text for the current page
- GBool physLayout; // maintain original physical layout when
- // dumping text
-+ double fixedPitch; // if physLayout is true and this is non-zero,
-+ // assume fixed-pitch characters with this
-+ // width
- GBool rawOrder; // keep text in content stream order
- GBool doHTML; // extra processing for HTML conversion
- GBool ok; // set up ok?
-diff -ru xpdf-3.02/xpdf/XRef.cc xpdf-3.03/xpdf/XRef.cc
---- xpdf-3.02/xpdf/XRef.cc 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/XRef.cc 2011-08-15 23:08:53.000000000 +0200
-@@ -16,6 +16,7 @@
- #include <stddef.h>
- #include <string.h>
- #include <ctype.h>
-+#include <limits.h>
- #include "gmem.h"
- #include "Object.h"
- #include "Stream.h"
-@@ -190,13 +202,14 @@
- // XRef
- //------------------------------------------------------------------------
-
--XRef::XRef(BaseStream *strA) {
-+XRef::XRef(BaseStream *strA, GBool repair) {
- Guint pos;
- Object obj;
-
- ok = gTrue;
- errCode = errNone;
- size = 0;
-+ last = -1;
- entries = NULL;
- streamEnds = NULL;
- streamEndsLen = 0;
-@@ -206,30 +219,32 @@
- permFlags = defPermFlags;
- ownerPasswordOk = gFalse;
-
-- // read the trailer
- str = strA;
- start = str->getStart();
-- pos = getStartXref();
-
-- // if there was a problem with the 'startxref' position, try to
-- // reconstruct the xref table
-- if (pos == 0) {
-+ // if the 'repair' flag is set, try to reconstruct the xref table
-+ if (repair) {
- if (!(ok = constructXRef())) {
- errCode = errDamaged;
- return;
- }
-
-- // read the xref table
-+ // if the 'repair' flag is not set, read the xref table
- } else {
-- while (readXRef(&pos)) ;
-
-- // if there was a problem with the xref table,
-- // try to reconstruct it
-+ // read the trailer
-+ pos = getStartXref();
-+ if (pos == 0) {
-+ errCode = errDamaged;
-+ ok = gFalse;
-+ return;
-+ }
-+
-+ // read the xref table
-+ while (readXRef(&pos)) ;
- if (!ok) {
-- if (!(ok = constructXRef())) {
-- errCode = errDamaged;
-- return;
-- }
-+ errCode = errDamaged;
-+ return;
- }
- }
-
-@@ -288,7 +303,7 @@
- if (i < 0) {
- return 0;
- }
-- for (p = &buf[i+9]; isspace(*p); ++p) ;
-+ for (p = &buf[i+9]; isspace(*p & 0xff); ++p) ;
- lastXRefPos = strToUnsigned(p);
-
- return lastXRefPos;
-@@ -307,7 +322,7 @@
- new Lexer(NULL,
- str->makeSubStream(start + *pos, gFalse, 0, &obj)),
- gTrue);
-- parser->getObj(&obj);
-+ parser->getObj(&obj, gTrue);
-
- // parse an old-style xref table
- if (obj.isCmd("xref")) {
-@@ -317,11 +332,11 @@
- // parse an xref stream
- } else if (obj.isInt()) {
- obj.free();
-- if (!parser->getObj(&obj)->isInt()) {
-+ if (!parser->getObj(&obj, gTrue)->isInt()) {
- goto err1;
- }
- obj.free();
-- if (!parser->getObj(&obj)->isCmd("obj")) {
-+ if (!parser->getObj(&obj, gTrue)->isCmd("obj")) {
- goto err1;
- }
- obj.free();
-@@ -353,7 +368,7 @@
- int first, n, newSize, i;
-
- while (1) {
-- parser->getObj(&obj);
-+ parser->getObj(&obj, gTrue);
- if (obj.isCmd("trailer")) {
- obj.free();
- break;
-@@ -363,7 +378,7 @@
- }
- first = obj.getInt();
- obj.free();
-- if (!parser->getObj(&obj)->isInt()) {
-+ if (!parser->getObj(&obj, gTrue)->isInt()) {
- goto err1;
- }
- n = obj.getInt();
-@@ -386,17 +401,17 @@
- size = newSize;
- }
- for (i = first; i < first + n; ++i) {
-- if (!parser->getObj(&obj)->isInt()) {
-+ if (!parser->getObj(&obj, gTrue)->isInt()) {
- goto err1;
- }
- entry.offset = (Guint)obj.getInt();
- obj.free();
-- if (!parser->getObj(&obj)->isInt()) {
-+ if (!parser->getObj(&obj, gTrue)->isInt()) {
- goto err1;
- }
- entry.gen = obj.getInt();
- obj.free();
-- parser->getObj(&obj);
-+ parser->getObj(&obj, gTrue);
- if (obj.isCmd("n")) {
- entry.type = xrefEntryUncompressed;
- } else if (obj.isCmd("f")) {
-@@ -417,6 +432,9 @@
- entries[0] = entries[1];
- entries[1].offset = 0xffffffff;
- }
-+ if (i > last) {
-+ last = i;
-+ }
- }
- }
- }
-@@ -429,13 +447,25 @@
- // get the 'Prev' pointer
- obj.getDict()->lookupNF("Prev", &obj2);
- if (obj2.isInt()) {
-- *pos = (Guint)obj2.getInt();
-- more = gTrue;
-+ pos2 = (Guint)obj2.getInt();
-+ if (pos2 != *pos) {
-+ *pos = pos2;
-+ more = gTrue;
-+ } else {
-+ error(errSyntaxWarning, -1, "Infinite loop in xref table");
-+ more = gFalse;
-+ }
- } else if (obj2.isRef()) {
- // certain buggy PDF generators generate "/Prev NNN 0 R" instead
- // of "/Prev NNN"
-- *pos = (Guint)obj2.getRefNum();
-- more = gTrue;
-+ pos2 = (Guint)obj2.getRefNum();
-+ if (pos2 != *pos) {
-+ *pos = pos2;
-+ more = gTrue;
-+ } else {
-+ error(errSyntaxWarning, -1, "Infinite loop in xref table");
-+ more = gFalse;
-+ }
- } else {
- more = gFalse;
- }
-@@ -624,6 +654,9 @@
- default:
- return gFalse;
- }
-+ if (i > last) {
-+ last = i;
-+ }
- }
- }
-
-@@ -647,7 +680,6 @@
- size = 0;
- entries = NULL;
-
-- error(-1, "PDF file is damaged - attempting to reconstruct xref table...");
- gotRoot = gFalse;
- streamEndsLen = streamEndsSize = 0;
-
-@@ -687,30 +719,30 @@
- delete parser;
-
- // look for object
-- } else if (isdigit(*p)) {
-+ } else if (isdigit(*p & 0xff)) {
- num = atoi(p);
- if (num > 0) {
- do {
- ++p;
-- } while (*p && isdigit(*p));
-- if (isspace(*p)) {
-+ } while (*p && isdigit(*p & 0xff));
-+ if (isspace(*p & 0xff)) {
- do {
- ++p;
-- } while (*p && isspace(*p));
-- if (isdigit(*p)) {
-+ } while (*p && isspace(*p & 0xff));
-+ if (isdigit(*p & 0xff)) {
- gen = atoi(p);
- do {
- ++p;
-- } while (*p && isdigit(*p));
-- if (isspace(*p)) {
-+ } while (*p && isdigit(*p & 0xff));
-+ if (isspace(*p & 0xff)) {
- do {
- ++p;
-- } while (*p && isspace(*p));
-+ } while (*p && isspace(*p & 0xff));
- if (!strncmp(p, "obj", 3)) {
- if (num >= size) {
- newSize = (num + 1 + 255) & ~255;
- if (newSize < 0) {
-- error(-1, "Bad object number");
-+ error(errSyntaxError, -1, "Bad object number");
- return gFalse;
- }
- entries = (XRefEntry *)
-@@ -726,6 +758,9 @@
- entries[num].offset = pos - start;
- entries[num].gen = gen;
- entries[num].type = xrefEntryUncompressed;
-+ if (num > last) {
-+ last = num;
-+ }
- }
- }
- }
-diff -ru xpdf-3.02/xpdf/XRef.h xpdf-3.03/xpdf/XRef.h
---- xpdf-3.02/xpdf/XRef.h 2007-02-27 23:05:52.000000000 +0100
-+++ xpdf-3.03/xpdf/XRef.h 2011-08-15 23:08:53.000000000 +0200
-@@ -43,7 +43,7 @@
- public:
-
- // Constructor. Read xref table from stream.
-- XRef(BaseStream *strA);
-+ XRef(BaseStream *strA, GBool repair);
-
- // Destructor.
- ~XRef();
-@@ -67,19 +67,20 @@
- // Get catalog object.
- Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); }
-
- // Fetch an indirect reference.
-- Object *fetch(int num, int gen, Object *obj);
-+ Object *fetch(int num, int gen, Object *obj, int recursion = 0);
-
- // Return the document's Info dictionary (if any).
- Object *getDocInfo(Object *obj);
- Object *getDocInfoNF(Object *obj);
-
- // Return the number of objects in the xref table.
-- int getNumObjects() { return size; }
-+ int getNumObjects() { return last + 1; }
-
- // Return the offset of the last xref table.
- Guint getLastXRefPos() { return lastXRefPos; }
-@@ -104,6 +105,7 @@
- // at beginning of file)
- XRefEntry *entries; // xref entries
- int size; // size of <entries> array
-+ int last; // last used index in <entries>
- int rootNum, rootGen; // catalog dict
- GBool ok; // true if xref table is valid
- int errCode; // error code (if <ok> is false)
+diff -ru xpdf-3.02/doc/pdftotext.1 xpdf-3.03/doc/pdftotext.1
+--- xpdf-3.02/doc/pdftotext.1 2007-02-27 23:05:51.000000000 +0100
++++ xpdf-3.03/doc/pdftotext.1 2011-08-15 23:08:53.000000000 +0200
+@@ -49,6 +49,10 @@
+ text. The default is to \'undo' physical layout (columns,
+ hyphenation, etc.) and output the text in reading order.
+ .TP
++.BI \-fixed " number"
++Assume fixed-pitch (or tabular) text, with the specified character
++width (in points). This forces physical layout mode.
++.TP
+ .B \-raw
+ Keep the text in content stream order. This is a hack which often
+ "undoes" column formatting, etc. Use of raw mode is no longer
+diff -ru xpdf-3.02/xpdf/Gfx.cc xpdf-3.03/xpdf/Gfx.cc
+--- xpdf-3.02/xpdf/Gfx.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/Gfx.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -18,9 +18,12 @@
+ #include <string.h>
+ #include <math.h>
+ #include "gmem.h"
++#include "GString.h"
++#include "GList.h"
+ #include "GlobalParams.h"
+ #include "CharTypes.h"
+ #include "Object.h"
+ #include "PDFDoc.h"
+ #include "Array.h"
+ #include "Dict.h"
+ #include "Stream.h"
+@@ -31,7 +34,9 @@
+ #include "OutputDev.h"
+ #include "Page.h"
+ #include "Annot.h"
++#include "OptionalContent.h"
+ #include "Error.h"
++#include "PDFDocEncoding.h"
+ #include "Gfx.h"
+
+ // the MSVC math.h doesn't define this
+@@ -461,6 +487,10 @@
+ baseMatrix[i] = state->getCTM()[i];
+ }
+ formDepth = 0;
++ textClipBBoxEmpty = gTrue;
++ markedContentStack = new GList();
++ ocState = gTrue;
++ parser = NULL;
+ abortCheckCbk = abortCheckCbkA;
+ abortCheckCbkData = abortCheckCbkDataA;
+
+@@ -500,6 +531,10 @@
+ baseMatrix[i] = state->getCTM()[i];
+ }
+ formDepth = 0;
++ textClipBBoxEmpty = gTrue;
++ markedContentStack = new GList();
++ ocState = gTrue;
++ parser = NULL;
+ abortCheckCbk = abortCheckCbkA;
+ abortCheckCbkData = abortCheckCbkDataA;
+
+@@ -517,18 +552,17 @@
+ }
+
+ Gfx::~Gfx() {
+- while (state->hasSaves()) {
+- restoreState();
+- }
+ if (!subPage) {
+ out->endPage();
+ }
++ while (state->hasSaves()) {
++ restoreState();
++ }
++ delete state;
+ while (res) {
+ popResources();
+ }
+- if (state) {
+- delete state;
+- }
++ deleteGList(markedContentStack, GfxMarkedContent);
+ }
+
+ void Gfx::display(Object *obj, GBool topLevel) {
+@@ -562,7 +596,8 @@
+ int lastAbortCheck;
+
+ // scan a sequence of objects
+- updateLevel = lastAbortCheck = 0;
++ updateLevel = 1; // make sure even empty pages trigger a call to dump()
++ lastAbortCheck = 0;
+ numArgs = 0;
+ parser->getObj(&obj);
+ while (!obj.isEOF()) {
+@@ -695,6 +734,7 @@
+
+ a = -1;
+ b = numOps;
++ cmp = 0; // make gcc happy
+ // invariant: opTab[a] < name < opTab[b]
+ while (b - a > 1) {
+ m = (a + b) / 2;
+@@ -801,6 +841,7 @@
+
+ void Gfx::opSetExtGState(Object args[], int numArgs) {
+ Object obj1, obj2, obj3, obj4, obj5;
++ Object args2[2];
+ GfxBlendMode mode;
+ GBool haveFillOP;
+ Function *funcs[4];
+@@ -808,9 +849,10 @@
+ GBool haveBackdropColor;
+ GfxColorSpace *blendingColorSpace;
+ GBool alpha, isolated, knockout;
++ double opac;
+ int i;
+
+ if (!res->lookupGState(args[0].getName(), &obj1)) {
+ return;
+ }
+ if (!obj1.isDict()) {
+@@ -824,28 +867,77 @@
+ printf("\n");
+ }
+
++ // parameters that are also set by individual PDF operators
++ if (obj1.dictLookup("LW", &obj2)->isNum()) {
++ opSetLineWidth(&obj2, 1);
++ }
++ obj2.free();
++ if (obj1.dictLookup("LC", &obj2)->isInt()) {
++ opSetLineCap(&obj2, 1);
++ }
++ obj2.free();
++ if (obj1.dictLookup("LJ", &obj2)->isInt()) {
++ opSetLineJoin(&obj2, 1);
++ }
++ obj2.free();
++ if (obj1.dictLookup("ML", &obj2)->isNum()) {
++ opSetMiterLimit(&obj2, 1);
++ }
++ obj2.free();
++ if (obj1.dictLookup("D", &obj2)->isArray() &&
++ obj2.arrayGetLength() == 2) {
++ obj2.arrayGet(0, &args2[0]);
++ obj2.arrayGet(1, &args2[1]);
++ if (args2[0].isArray() && args2[1].isNum()) {
++ opSetDash(args2, 2);
++ }
++ args2[0].free();
++ 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("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);
++ }
++ args2[0].free();
++ args2[1].free();
++ }
++ obj2.free();
++#endif
++ if (obj1.dictLookup("FL", &obj2)->isNum()) {
++ opSetFlat(&obj2, 1);
++ }
++ obj2.free();
++
+ // transparency support: blend mode, fill/stroke opacity
+ if (!obj1.dictLookup("BM", &obj2)->isNull()) {
+ if (state->parseBlendMode(&obj2, &mode)) {
+ state->setBlendMode(mode);
+ out->updateBlendMode(state);
+ } else {
+ error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
+ }
+ }
+ obj2.free();
+ if (obj1.dictLookup("ca", &obj2)->isNum()) {
+- state->setFillOpacity(obj2.getNum());
++ opac = obj2.getNum();
++ state->setFillOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
+ out->updateFillOpacity(state);
+ }
+ obj2.free();
+ if (obj1.dictLookup("CA", &obj2)->isNum()) {
+- state->setStrokeOpacity(obj2.getNum());
++ opac = obj2.getNum();
++ state->setStrokeOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac);
+ out->updateStrokeOpacity(state);
+ }
+ obj2.free();
+
+- // fill/stroke overprint
++ // fill/stroke overprint, overprint mode
+ if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) {
+ state->setFillOverprint(obj2.getBool());
+ out->updateFillOverprint(state);
+@@ -860,6 +952,11 @@
+ }
+ }
+ obj2.free();
++ if (obj1.dictLookup("OPM", &obj2)->isInt()) {
++ state->setOverprintMode(obj2.getInt());
++ out->updateOverprintMode(state);
++ }
++ obj2.free();
+
+ // stroke adjust
+ if (obj1.dictLookup("SA", &obj2)->isBool()) {
+@@ -915,13 +1012,18 @@
+ obj3.free();
+ funcs[0] = NULL;
+ if (!obj2.dictLookup("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");
+- delete funcs[0];
++ if (obj3.isName("Default") ||
++ obj3.isName("Identity")) {
+ funcs[0] = NULL;
++ } else {
++ funcs[0] = Function::parse(&obj3);
++ if (funcs[0]->getInputSize() != 1 ||
++ funcs[0]->getOutputSize() != 1) {
++ error(errSyntaxError, getPos(),
++ "Invalid transfer function in soft mask in ExtGState");
++ delete funcs[0];
++ funcs[0] = NULL;
++ }
+ }
+ }
+ obj3.free();
+@@ -1045,9 +1149,9 @@
+
+ // draw it
+ ++formDepth;
+- doForm1(str, resDict, m, bbox, gTrue, gTrue,
+- blendingColorSpace, isolated, knockout,
+- alpha, transferFunc, backdropColor);
++ drawForm(str, resDict, m, bbox, gTrue, gTrue,
++ blendingColorSpace, isolated, knockout,
++ alpha, transferFunc, backdropColor);
+ --formDepth;
+
+ if (blendingColorSpace) {
+@@ -1402,14 +1512,16 @@
+
+ void Gfx::opStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+- //error(getPos(), "No path in stroke");
++ //error(errSyntaxError, getPos(), "No path in stroke");
+ return;
+ }
+ if (state->isPath()) {
+- if (state->getStrokeColorSpace()->getMode() == csPattern) {
+- doPatternStroke();
+- } else {
+- out->stroke(state);
++ if (ocState) {
++ if (state->getStrokeColorSpace()->getMode() == csPattern) {
++ doPatternStroke();
++ } else {
++ out->stroke(state);
++ }
+ }
+ }
+ doEndPath();
+@@ -1417,15 +1529,17 @@
+
+ void Gfx::opCloseStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+- //error(getPos(), "No path in closepath/stroke");
++ //error(errSyntaxError, getPos(), "No path in closepath/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+- if (state->getStrokeColorSpace()->getMode() == csPattern) {
+- doPatternStroke();
+- } else {
+- out->stroke(state);
++ if (ocState) {
++ if (state->getStrokeColorSpace()->getMode() == csPattern) {
++ doPatternStroke();
++ } else {
++ out->stroke(state);
++ }
+ }
+ }
+ doEndPath();
+@@ -1433,14 +1547,16 @@
+
+ void Gfx::opFill(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+- //error(getPos(), "No path in fill");
++ //error(errSyntaxError, getPos(), "No path in fill");
+ return;
+ }
+ if (state->isPath()) {
+- if (state->getFillColorSpace()->getMode() == csPattern) {
+- doPatternFill(gFalse);
+- } else {
+- out->fill(state);
++ if (ocState) {
++ if (state->getFillColorSpace()->getMode() == csPattern) {
++ doPatternFill(gFalse);
++ } else {
++ out->fill(state);
++ }
+ }
+ }
+ doEndPath();
+@@ -1448,14 +1564,16 @@
+
+ void Gfx::opEOFill(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+- //error(getPos(), "No path in eofill");
++ //error(errSyntaxError, getPos(), "No path in eofill");
+ return;
+ }
+ if (state->isPath()) {
+- if (state->getFillColorSpace()->getMode() == csPattern) {
+- doPatternFill(gTrue);
+- } else {
+- out->eoFill(state);
++ if (ocState) {
++ if (state->getFillColorSpace()->getMode() == csPattern) {
++ doPatternFill(gTrue);
++ } else {
++ out->eoFill(state);
++ }
+ }
+ }
+ doEndPath();
+@@ -1463,19 +1581,21 @@
+
+ void Gfx::opFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+- //error(getPos(), "No path in fill/stroke");
++ //error(errSyntaxError, getPos(), "No path in fill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+- if (state->getFillColorSpace()->getMode() == csPattern) {
+- doPatternFill(gFalse);
+- } else {
+- out->fill(state);
+- }
+- if (state->getStrokeColorSpace()->getMode() == csPattern) {
+- doPatternStroke();
+- } else {
+- out->stroke(state);
++ if (ocState) {
++ if (state->getFillColorSpace()->getMode() == csPattern) {
++ doPatternFill(gFalse);
++ } else {
++ out->fill(state);
++ }
++ if (state->getStrokeColorSpace()->getMode() == csPattern) {
++ doPatternStroke();
++ } else {
++ out->stroke(state);
++ }
+ }
+ }
+ doEndPath();
+@@ -1483,20 +1603,22 @@
+
+ void Gfx::opCloseFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+- //error(getPos(), "No path in closepath/fill/stroke");
++ //error(errSyntaxError, getPos(), "No path in closepath/fill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+- if (state->getFillColorSpace()->getMode() == csPattern) {
+- doPatternFill(gFalse);
+- } else {
+- out->fill(state);
+- }
+- if (state->getStrokeColorSpace()->getMode() == csPattern) {
+- doPatternStroke();
+- } else {
+- out->stroke(state);
++ if (ocState) {
++ if (state->getFillColorSpace()->getMode() == csPattern) {
++ doPatternFill(gFalse);
++ } else {
++ out->fill(state);
++ }
++ if (state->getStrokeColorSpace()->getMode() == csPattern) {
++ doPatternStroke();
++ } else {
++ out->stroke(state);
++ }
+ }
+ }
+ doEndPath();
+@@ -1504,19 +1626,21 @@
+
+ void Gfx::opEOFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+- //error(getPos(), "No path in eofill/stroke");
++ //error(errSyntaxError, getPos(), "No path in eofill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+- if (state->getFillColorSpace()->getMode() == csPattern) {
+- doPatternFill(gTrue);
+- } else {
+- out->eoFill(state);
+- }
+- if (state->getStrokeColorSpace()->getMode() == csPattern) {
+- doPatternStroke();
+- } else {
+- out->stroke(state);
++ if (ocState) {
++ if (state->getFillColorSpace()->getMode() == csPattern) {
++ doPatternFill(gTrue);
++ } else {
++ out->eoFill(state);
++ }
++ if (state->getStrokeColorSpace()->getMode() == csPattern) {
++ doPatternStroke();
++ } else {
++ out->stroke(state);
++ }
+ }
+ }
+ doEndPath();
+@@ -1524,20 +1648,22 @@
+
+ void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+- //error(getPos(), "No path in closepath/eofill/stroke");
++ //error(errSyntaxError, getPos(), "No path in closepath/eofill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+- if (state->getFillColorSpace()->getMode() == csPattern) {
+- doPatternFill(gTrue);
+- } else {
+- out->eoFill(state);
+- }
+- if (state->getStrokeColorSpace()->getMode() == csPattern) {
+- doPatternStroke();
+- } else {
+- out->stroke(state);
++ if (ocState) {
++ if (state->getFillColorSpace()->getMode() == csPattern) {
++ doPatternFill(gTrue);
++ } else {
++ out->eoFill(state);
++ }
++ if (state->getStrokeColorSpace()->getMode() == csPattern) {
++ doPatternStroke();
++ } else {
++ out->stroke(state);
++ }
+ }
+ }
+ doEndPath();
+@@ -1558,13 +1684,13 @@
+ }
+ switch (pattern->getType()) {
+ case 1:
+- doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, eoFill);
++ doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, eoFill, gFalse);
+ break;
+ case 2:
+- doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, eoFill);
++ doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, eoFill, gFalse);
+ break;
+ default:
+- error(getPos(), "Unimplemented pattern type (%d) in fill",
++ error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in fill",
+ pattern->getType());
+ break;
+ }
+@@ -1585,23 +1711,68 @@
+ }
+ switch (pattern->getType()) {
+ case 1:
+- doTilingPatternFill((GfxTilingPattern *)pattern, gTrue, gFalse);
++ doTilingPatternFill((GfxTilingPattern *)pattern, gTrue, gFalse, gFalse);
++ break;
++ case 2:
++ doShadingPatternFill((GfxShadingPattern *)pattern, gTrue, gFalse, gFalse);
++ break;
++ default:
++ error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in stroke",
++ pattern->getType());
++ break;
++ }
++}
++
++void Gfx::doPatternText() {
++ GfxPattern *pattern;
++
++ // this is a bit of a kludge -- patterns can be really slow, so we
++ // skip them if we're only doing text extraction, since they almost
++ // certainly don't contain any text
++ if (!out->needNonText()) {
++ return;
++ }
++
++ if (!(pattern = state->getFillPattern())) {
++ return;
++ }
++ switch (pattern->getType()) {
++ case 1:
++ doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, gFalse, gTrue);
+ break;
+ case 2:
+- doShadingPatternFill((GfxShadingPattern *)pattern, gTrue, gFalse);
++ doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, gFalse, gTrue);
+ break;
+ default:
+- error(getPos(), "Unimplemented pattern type (%d) in stroke",
++ error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in fill",
+ pattern->getType());
+ break;
+ }
+ }
+
++void Gfx::doPatternImageMask(Object *ref, Stream *str, int width, int height,
++ GBool invert, GBool inlineImg) {
++ saveState();
++
++ out->setSoftMaskFromImageMask(state, ref, str,
++ width, height, invert, inlineImg);
++
++ state->clearPath();
++ state->moveTo(0, 0);
++ state->lineTo(1, 0);
++ state->lineTo(1, 1);
++ state->lineTo(0, 1);
++ state->closePath();
++ doPatternFill(gTrue);
++
++ restoreState();
++}
++
+ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
+- GBool stroke, GBool eoFill) {
++ GBool stroke, GBool eoFill, GBool text) {
+ GfxPatternColorSpace *patCS;
+ GfxColorSpace *cs;
+- GfxPath *savedPath;
++ GfxState *savedState;
+ double xMin, yMin, xMax, yMax, x, y, x1, y1;
+ double cxMin, cyMin, cxMax, cyMax;
+ int xi0, yi0, xi1, yi1, xi, yi;
+@@ -1652,28 +1823,27 @@
+ imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det;
+
+ // save current graphics state
+- savedPath = state->getPath()->copy();
+- saveState();
++ savedState = saveStateStack();
+
+ // set underlying color space (for uncolored tiling patterns); set
+ // various other parameters (stroke color, line width) to match
+ // Adobe's behavior
++ state->setFillPattern(NULL);
++ state->setStrokePattern(NULL);
+ if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) {
+ state->setFillColorSpace(cs->copy());
+ out->updateFillColorSpace(state);
+ state->setStrokeColorSpace(cs->copy());
+ out->updateStrokeColorSpace(state);
+ state->setStrokeColor(state->getFillColor());
++ out->updateFillColor(state);
++ out->updateStrokeColor(state);
+ } else {
+ state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+ out->updateFillColorSpace(state);
+ state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
+ out->updateStrokeColorSpace(state);
+ }
+- state->setFillPattern(NULL);
+- out->updateFillColor(state);
+- state->setStrokePattern(NULL);
+- out->updateStrokeColor(state);
+ if (!stroke) {
+ state->setLineWidth(0);
+ out->updateLineWidth(state);
+@@ -1683,7 +1853,7 @@
+ if (stroke) {
+ state->clipToStrokePath();
+ out->clipToStrokePath(state);
+- } else {
++ } else if (!text) {
+ state->clip();
+ if (eoFill) {
+ out->eoClip(state);
+@@ -1754,7 +1924,7 @@
+ if (out->useTilingPatternFill()) {
+ m1[4] = m[4];
+ m1[5] = m[5];
+- out->tilingPatternFill(state, tPat->getContentStream(),
++ out->tilingPatternFill(state, this, tPat->getContentStream(),
+ tPat->getPaintType(), tPat->getResDict(),
+ m1, tPat->getBBox(),
+ xi0, yi0, xi1, yi1, xstep, ystep);
+@@ -1765,22 +1935,21 @@
+ y = yi * ystep;
+ m1[4] = x * m[0] + y * m[2] + m[4];
+ m1[5] = x * m[1] + y * m[3] + m[5];
+- doForm1(tPat->getContentStream(), tPat->getResDict(),
+- m1, tPat->getBBox());
++ drawForm(tPat->getContentStream(), tPat->getResDict(),
++ m1, tPat->getBBox());
+ }
+ }
+ }
+
+ // restore graphics state
+ err:
+- restoreState();
+- state->setPath(savedPath);
++ restoreStateStack(savedState);
+ }
+
+ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat,
+- GBool stroke, GBool eoFill) {
++ GBool stroke, GBool eoFill, GBool text) {
+ GfxShading *shading;
+- GfxPath *savedPath;
++ GfxState *savedState;
+ double *ctm, *btm, *ptm;
+ double m[6], ictm[6], m1[6];
+ double xMin, yMin, xMax, yMax;
+@@ -1789,27 +1958,13 @@
+ shading = sPat->getShading();
+
+ // save current graphics state
+- savedPath = state->getPath()->copy();
+- saveState();
+-
+- // clip to bbox
+- if (shading->getHasBBox()) {
+- shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+- state->moveTo(xMin, yMin);
+- state->lineTo(xMax, yMin);
+- state->lineTo(xMax, yMax);
+- state->lineTo(xMin, yMax);
+- state->closePath();
+- state->clip();
+- out->clip(state);
+- state->setPath(savedPath->copy());
+- }
++ savedState = saveStateStack();
+
+ // clip to current path
+ if (stroke) {
+ state->clipToStrokePath();
+ out->clipToStrokePath(state);
+- } else {
++ } else if (!text) {
+ state->clip();
+ if (eoFill) {
+ out->eoClip(state);
+@@ -1817,17 +1972,6 @@
+ out->clip(state);
+ }
+ }
+-
+- // set the color space
+- state->setFillColorSpace(shading->getColorSpace()->copy());
+- out->updateFillColorSpace(state);
+-
+- // background color fill
+- if (shading->getHasBackground()) {
+- state->setFillColor(shading->getBackground());
+- out->updateFillColor(state);
+- out->fill(state);
+- }
+ state->clearPath();
+
+ // construct a (pattern space) -> (current space) transform matrix
+@@ -1861,11 +2005,39 @@
+ state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
+ out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]);
+
+-#if 1 //~tmp: turn off anti-aliasing temporarily
+- GBool vaa = out->getVectorAntialias();
+- if (vaa) {
+- out->setVectorAntialias(gFalse);
++ // clip to bbox
++ if (shading->getHasBBox()) {
++ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
++ state->moveTo(xMin, yMin);
++ state->lineTo(xMax, yMin);
++ state->lineTo(xMax, yMax);
++ state->lineTo(xMin, yMax);
++ state->closePath();
++ state->clip();
++ out->clip(state);
++ state->clearPath();
++ }
++
++ // set the color space
++ state->setFillColorSpace(shading->getColorSpace()->copy());
++ out->updateFillColorSpace(state);
++
++ // background color fill
++ if (shading->getHasBackground()) {
++ state->setFillColor(shading->getBackground());
++ out->updateFillColor(state);
++ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
++ state->moveTo(xMin, yMin);
++ state->lineTo(xMax, yMin);
++ state->lineTo(xMax, yMax);
++ state->lineTo(xMin, yMax);
++ state->closePath();
++ out->fill(state);
++ state->clearPath();
+ }
++
++#if 1 //~tmp: turn off anti-aliasing temporarily
++ out->setInShading(gTrue);
+ #endif
+
+ // do shading type-specific operations
+@@ -1890,28 +2062,28 @@
+ }
+
+ #if 1 //~tmp: turn off anti-aliasing temporarily
+- if (vaa) {
+- out->setVectorAntialias(gTrue);
+- }
++ out->setInShading(gFalse);
+ #endif
+
+ // restore graphics state
+- restoreState();
+- state->setPath(savedPath);
++ restoreStateStack(savedState);
+ }
+
+ void Gfx::opShFill(Object args[], int numArgs) {
+ GfxShading *shading;
+- GfxPath *savedPath;
++ GfxState *savedState;
+ double xMin, yMin, xMax, yMax;
+
++ if (!ocState) {
++ return;
++ }
++
+ if (!(shading = res->lookupShading(args[0].getName()))) {
+ return;
+ }
+
+ // save current graphics state
+- savedPath = state->getPath()->copy();
+- saveState();
++ savedState = saveStateStack();
+
+ // clip to bbox
+ if (shading->getHasBBox()) {
+@@ -1931,10 +2103,7 @@
+ out->updateFillColorSpace(state);
+
+ #if 1 //~tmp: turn off anti-aliasing temporarily
+- GBool vaa = out->getVectorAntialias();
+- if (vaa) {
+- out->setVectorAntialias(gFalse);
+- }
++ out->setInShading(gTrue);
+ #endif
+
+ // do shading type-specific operations
+@@ -1959,14 +2128,11 @@
+ }
+
+ #if 1 //~tmp: turn off anti-aliasing temporarily
+- if (vaa) {
+- out->setVectorAntialias(gTrue);
+- }
++ out->setInShading(gFalse);
+ #endif
+
+ // restore graphics state
+- restoreState();
+- state->setPath(savedPath);
++ restoreStateStack(savedState);
+
+ delete shading;
+ }
+@@ -2100,16 +2266,16 @@
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, x1, y1;
+ double dx, dy, mul;
+- GBool dxZero, dyZero;
++ GBool dxdyZero, horiz;
+ double tMin, tMax, t, tx, ty;
+- double s[4], sMin, sMax, tmp;
++ double sMin, sMax, tmp;
+ double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1;
+ double t0, t1, tt;
+ double ta[axialMaxSplits + 1];
+ int next[axialMaxSplits + 1];
+ GfxColor color0, color1;
+ int nComps;
+- int i, j, k, kk;
++ int i, j, k;
+
+ if (out->useShadedFills() &&
+ out->axialShadedFill(state, shading)) {
+@@ -2124,9 +2290,9 @@
+ shading->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+- dxZero = fabs(dx) < 0.01;
+- dyZero = fabs(dy) < 0.01;
+- if (dxZero && dyZero) {
++ dxdyZero = fabs(dx) < 0.01 && fabs(dy) < 0.01;
++ horiz = fabs(dy) < fabs(dx);
++ if (dxdyZero) {
+ tMin = tMax = 0;
+ } else {
+ mul = 1 / (dx * dx + dy * dy);
+@@ -2170,18 +2336,16 @@
+ // y(s) = ty + s * dx --> s = (y - ty) / dx
+ //
+ // Then look at the intersection of this line with the bounding box
+- // (xMin, yMin, xMax, yMax). In the general case, there are four
+- // intersection points:
++ // (xMin, yMin, xMax, yMax). For -1 < |dy/dx| < 1, look at the
++ // intersection with yMin, yMax:
+ //
+- // s0 = (xMin - tx) / -dy
+- // s1 = (xMax - tx) / -dy
+- // s2 = (yMin - ty) / dx
+- // s3 = (yMax - ty) / dx
++ // s0 = (yMin - ty) / dx
++ // s1 = (yMax - ty) / dx
+ //
+- // and we want the middle two s values.
++ // else look at the intersection with xMin, xMax:
+ //
+- // In the case where dx = 0, take s0 and s1; in the case where dy =
+- // 0, take s2 and s3.
++ // s0 = (xMin - tx) / -dy
++ // s1 = (xMax - tx) / -dy
+ //
+ // Each filled polygon is bounded by two of these line segments
+ // perpdendicular to the t axis.
+@@ -2190,13 +2354,10 @@
+ // difference across a region is small enough, and then the region
+ // is painted with a single color.
+
+- // set up: require at least one split to avoid problems when the two
+- // ends of the t axis have the same color
++ // set up
+ nComps = shading->getColorSpace()->getNComps();
+ ta[0] = tMin;
+- next[0] = axialMaxSplits / 2;
+- ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax);
+- next[axialMaxSplits / 2] = axialMaxSplits;
++ next[0] = axialMaxSplits;
+ ta[axialMaxSplits] = tMax;
+
+ // compute the color at t = tMin
+@@ -2214,32 +2375,19 @@
+ // bounding box
+ tx = x0 + tMin * dx;
+ ty = y0 + tMin * dy;
+- if (dxZero && dyZero) {
++ if (dxdyZero) {
+ sMin = sMax = 0;
+- } else if (dxZero) {
+- sMin = (xMin - tx) / -dy;
+- sMax = (xMax - tx) / -dy;
+- if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+- } else if (dyZero) {
+- sMin = (yMin - ty) / dx;
+- sMax = (yMax - ty) / dx;
+- if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+- s[0] = (yMin - ty) / dx;
+- s[1] = (yMax - ty) / dx;
+- s[2] = (xMin - tx) / -dy;
+- s[3] = (xMax - tx) / -dy;
+- for (j = 0; j < 3; ++j) {
+- kk = j;
+- for (k = j + 1; k < 4; ++k) {
+- if (s[k] < s[kk]) {
+- kk = k;
+- }
+- }
+- tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
++ if (horiz) {
++ sMin = (yMin - ty) / dx;
++ sMax = (yMax - ty) / dx;
++ } else {
++ sMin = (xMin - tx) / -dy;
++ sMax = (xMax - tx) / -dy;
++ }
++ if (sMin > sMax) {
++ tmp = sMin; sMin = sMax; sMax = tmp;
+ }
+- sMin = s[1];
+- sMax = s[2];
+ }
+ ux0 = tx - sMin * dy;
+ uy0 = ty + sMin * dx;
+@@ -2260,15 +2408,19 @@
+ } else {
+ tt = t0 + (t1 - t0) * ta[j];
+ }
+- shading->getColor(tt, &color1);
+- for (k = 0; k < nComps; ++k) {
+- if (abs(color1.c[k] - color0.c[k]) > axialColorDelta) {
++ // require at least two splits (to avoid problems where the
++ // color doesn't change smoothly along the t axis)
++ if (j - i <= axialMaxSplits / 4) {
++ shading->getColor(tt, &color1);
++ for (k = 0; k < nComps; ++k) {
++ if (abs(color1.c[k] - color0.c[k]) > axialColorDelta) {
++ break;
++ }
++ }
++ if (k == nComps) {
+ break;
+ }
+ }
+- if (k == nComps) {
+- break;
+- }
+ k = (i + j) / 2;
+ ta[k] = 0.5 * (ta[i] + ta[j]);
+ next[i] = k;
+@@ -2286,32 +2438,19 @@
+ // bounding box
+ tx = x0 + ta[j] * dx;
+ ty = y0 + ta[j] * dy;
+- if (dxZero && dyZero) {
++ if (dxdyZero) {
+ sMin = sMax = 0;
+- } else if (dxZero) {
+- sMin = (xMin - tx) / -dy;
+- sMax = (xMax - tx) / -dy;
+- if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+- } else if (dyZero) {
+- sMin = (yMin - ty) / dx;
+- sMax = (yMax - ty) / dx;
+- if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+- s[0] = (yMin - ty) / dx;
+- s[1] = (yMax - ty) / dx;
+- s[2] = (xMin - tx) / -dy;
+- s[3] = (xMax - tx) / -dy;
+- for (j = 0; j < 3; ++j) {
+- kk = j;
+- for (k = j + 1; k < 4; ++k) {
+- if (s[k] < s[kk]) {
+- kk = k;
+- }
+- }
+- tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
++ if (horiz) {
++ sMin = (yMin - ty) / dx;
++ sMax = (yMax - ty) / dx;
++ } else {
++ sMin = (xMin - tx) / -dy;
++ sMax = (xMax - tx) / -dy;
++ }
++ if (sMin > sMax) {
++ tmp = sMin; sMin = sMax; sMax = tmp;
+ }
+- sMin = s[1];
+- sMax = s[2];
+ }
+ ux1 = tx - sMin * dy;
+ uy1 = ty + sMin * dx;
+@@ -2348,7 +2487,10 @@
+ GfxColor colorA, colorB;
+ double xa, ya, xb, yb, ra, rb;
+ double ta, tb, sa, sb;
+- double sz, xz, yz, sMin, sMax;
++ double sz, sMin, sMax, h;
++ double sLeft, sRight, sTop, sBottom, sZero, sDiag;
++ GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero;
++ GBool haveSMin, haveSMax;
+ GBool enclosed;
+ int ia, ib, k, n;
+ double *ctm;
+@@ -2367,23 +2509,23 @@
+
+ // Compute the point at which r(s) = 0; check for the enclosed
+ // circles case; and compute the angles for the tangent lines.
+- if (x0 == x1 && y0 == y1) {
++ h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
++ if (h == 0) {
+ enclosed = gTrue;
+ theta = 0; // make gcc happy
+ sz = 0; // make gcc happy
+- } else if (r0 == r1) {
++ } else if (r1 - r0 == 0) {
+ enclosed = gFalse;
+ theta = 0;
+ sz = 0; // make gcc happy
++ } else if (fabs(r1 - r0) >= h) {
++ enclosed = gTrue;
++ theta = 0; // make gcc happy
++ sz = 0; // make gcc happy
+ } else {
++ enclosed = gFalse;
+ sz = -r0 / (r1 - r0);
+- xz = x0 + sz * (x1 - x0);
+- yz = y0 + sz * (y1 - y0);
+- enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
+- theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
+- if (r0 > r1) {
+- theta = -theta;
+- }
++ theta = asin((r1 - r0) / h);
+ }
+ if (enclosed) {
+ alpha = 0;
+@@ -2397,59 +2539,101 @@
+ sMin = 0;
+ sMax = 1;
+ } else {
+- sMin = 1;
+- sMax = 0;
+- // solve for x(s) + r(s) = xMin
+- if ((x1 + r1) - (x0 + r0) != 0) {
+- sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
+- if (sa < sMin) {
+- sMin = sa;
+- } else if (sa > sMax) {
+- sMax = sa;
+- }
+- }
+- // solve for x(s) - r(s) = xMax
+- if ((x1 - r1) - (x0 - r0) != 0) {
+- sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
+- if (sa < sMin) {
+- sMin = sa;
+- } else if (sa > sMax) {
+- sMax = sa;
+- }
+- }
+- // solve for y(s) + r(s) = yMin
+- if ((y1 + r1) - (y0 + r0) != 0) {
+- sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
+- if (sa < sMin) {
+- sMin = sa;
+- } else if (sa > sMax) {
+- sMax = sa;
+- }
+- }
+- // solve for y(s) - r(s) = yMax
+- if ((y1 - r1) - (y0 - r0) != 0) {
+- sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
+- if (sa < sMin) {
+- sMin = sa;
+- } else if (sa > sMax) {
+- sMax = sa;
+- }
+- }
+- // check against sz
+- if (r0 < r1) {
+- if (sMin < sz) {
+- sMin = sz;
+- }
+- } else if (r0 > r1) {
+- if (sMax > sz) {
+- sMax = sz;
+- }
++ // solve x(sLeft) + r(sLeft) = xMin
++ if ((haveSLeft = fabs((x1 + r1) - (x0 + r0)) > 0.000001)) {
++ sLeft = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
++ } else {
++ sLeft = 0; // make gcc happy
+ }
+- // check the 'extend' flags
+- if (!shading->getExtend0() && sMin < 0) {
++ // solve x(sRight) - r(sRight) = xMax
++ if ((haveSRight = fabs((x1 - r1) - (x0 - r0)) > 0.000001)) {
++ sRight = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
++ } else {
++ sRight = 0; // make gcc happy
++ }
++ // solve y(sBottom) + r(sBottom) = yMin
++ if ((haveSBottom = fabs((y1 + r1) - (y0 + r0)) > 0.000001)) {
++ sBottom = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
++ } else {
++ sBottom = 0; // make gcc happy
++ }
++ // solve y(sTop) - r(sTop) = yMax
++ if ((haveSTop = fabs((y1 - r1) - (y0 - r0)) > 0.000001)) {
++ sTop = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
++ } else {
++ sTop = 0; // make gcc happy
++ }
++ // solve r(sZero) = 0
++ if ((haveSZero = fabs(r1 - r0) > 0.000001)) {
++ sZero = -r0 / (r1 - r0);
++ } else {
++ sZero = 0; // make gcc happy
++ }
++ // solve r(sDiag) = sqrt((xMax-xMin)^2 + (yMax-yMin)^2)
++ if (haveSZero) {
++ sDiag = (sqrt((xMax - xMin) * (xMax - xMin) +
++ (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
++ } else {
++ sDiag = 0; // make gcc happy
++ }
++ // compute sMin
++ if (shading->getExtend0()) {
++ sMin = 0;
++ haveSMin = gFalse;
++ if (x0 < x1 && haveSLeft && sLeft < 0) {
++ sMin = sLeft;
++ haveSMin = gTrue;
++ } else if (x0 > x1 && haveSRight && sRight < 0) {
++ sMin = sRight;
++ haveSMin = gTrue;
++ }
++ if (y0 < y1 && haveSBottom && sBottom < 0) {
++ if (!haveSMin || sBottom > sMin) {
++ sMin = sBottom;
++ haveSMin = gTrue;
++ }
++ } else if (y0 > y1 && haveSTop && sTop < 0) {
++ if (!haveSMin || sTop > sMin) {
++ sMin = sTop;
++ haveSMin = gTrue;
++ }
++ }
++ if (haveSZero && sZero < 0) {
++ if (!haveSMin || sZero > sMin) {
++ sMin = sZero;
++ }
++ }
++ } else {
+ sMin = 0;
+ }
+- if (!shading->getExtend1() && sMax > 1) {
++ // compute sMax
++ if (shading->getExtend1()) {
++ sMax = 1;
++ haveSMax = gFalse;
++ if (x1 < x0 && haveSLeft && sLeft > 1) {
++ sMax = sLeft;
++ haveSMax = gTrue;
++ } else if (x1 > x0 && haveSRight && sRight > 1) {
++ sMax = sRight;
++ haveSMax = gTrue;
++ }
++ if (y1 < y0 && haveSBottom && sBottom > 1) {
++ if (!haveSMax || sBottom < sMax) {
++ sMax = sBottom;
++ haveSMax = gTrue;
++ }
++ } else if (y1 > y0 && haveSTop && sTop > 1) {
++ if (!haveSMax || sTop < sMax) {
++ sMax = sTop;
++ haveSMax = gTrue;
++ }
++ }
++ if (haveSZero && sDiag > 1) {
++ if (!haveSMax || sDiag < sMax) {
++ sMax = sDiag;
++ }
++ }
++ } else {
+ sMax = 1;
+ }
+ }
+@@ -2922,6 +3106,7 @@
+ out->updateTextMat(state);
+ out->updateTextPos(state);
+ fontChanged = gTrue;
++ textClipBBoxEmpty = gTrue;
+ }
+
+ void Gfx::opEndText(Object args[], int numArgs) {
+@@ -3028,19 +3213,23 @@
+
+ void Gfx::opShowText(Object args[], int numArgs) {
+ if (!state->getFont()) {
+- error(getPos(), "No font in show");
++ error(errSyntaxError, getPos(), "No font in show");
+ return;
+ }
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+- out->beginStringOp(state);
+- doShowText(args[0].getString());
+- out->endStringOp(state);
++ if (ocState) {
++ out->beginStringOp(state);
++ doShowText(args[0].getString());
++ out->endStringOp(state);
++ } else {
++ doIncCharCount(args[0].getString());
++ }
+ }
+
+ void Gfx::opMoveShowText(Object args[], int numArgs) {
+ double tx, ty;
+
+ if (!state->getFont()) {
+@@ -3055,12 +3244,16 @@
+ ty = state->getLineY() - state->getLeading();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+- out->beginStringOp(state);
+- doShowText(args[0].getString());
+- out->endStringOp(state);
++ if (ocState) {
++ out->beginStringOp(state);
++ doShowText(args[0].getString());
++ out->endStringOp(state);
++ } else {
++ doIncCharCount(args[0].getString());
++ }
+ }
+
+ void Gfx::opMoveSetShowText(Object args[], int numArgs) {
+ double tx, ty;
+
+ if (!state->getFont()) {
+@@ -3079,9 +3272,13 @@
+ out->updateWordSpace(state);
+ out->updateCharSpace(state);
+ out->updateTextPos(state);
+- out->beginStringOp(state);
+- doShowText(args[2].getString());
+- out->endStringOp(state);
++ if (ocState) {
++ out->beginStringOp(state);
++ doShowText(args[2].getString());
++ out->endStringOp(state);
++ } else {
++ doIncCharCount(args[2].getString());
++ }
+ }
+
+ void Gfx::opShowSpaceText(Object args[], int numArgs) {
+@@ -3091,37 +3288,48 @@
+ int i;
+
+ if (!state->getFont()) {
+- error(getPos(), "No font in show/space");
++ error(errSyntaxError, getPos(), "No font in show/space");
+ return;
+ }
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+- out->beginStringOp(state);
+- wMode = state->getFont()->getWMode();
+- a = args[0].getArray();
+- for (i = 0; i < a->getLength(); ++i) {
+- a->get(i, &obj);
+- if (obj.isNum()) {
+- // this uses the absolute value of the font size to match
+- // Acrobat's behavior
+- if (wMode) {
+- state->textShift(0, -obj.getNum() * 0.001 *
+- fabs(state->getFontSize()));
++ if (ocState) {
++ out->beginStringOp(state);
++ wMode = state->getFont()->getWMode();
++ a = args[0].getArray();
++ for (i = 0; i < a->getLength(); ++i) {
++ a->get(i, &obj);
++ if (obj.isNum()) {
++ if (wMode) {
++ state->textShift(0, -obj.getNum() * 0.001 *
++ state->getFontSize());
++ } else {
++ state->textShift(-obj.getNum() * 0.001 *
++ state->getFontSize() *
++ state->getHorizScaling(), 0);
++ }
++ out->updateTextShift(state, obj.getNum());
++ } else if (obj.isString()) {
++ doShowText(obj.getString());
+ } else {
+- state->textShift(-obj.getNum() * 0.001 *
+- fabs(state->getFontSize()), 0);
++ error(errSyntaxError, getPos(),
++ "Element of show/space array must be number or string");
+ }
+- out->updateTextShift(state, obj.getNum());
+- } else if (obj.isString()) {
+- doShowText(obj.getString());
+- } else {
+- error(getPos(), "Element of show/space array must be number or string");
++ obj.free();
++ }
++ out->endStringOp(state);
++ } else {
++ a = args[0].getArray();
++ for (i = 0; i < a->getLength(); ++i) {
++ a->get(i, &obj);
++ if (obj.isString()) {
++ doIncCharCount(obj.getString());
++ }
++ obj.free();
+ }
+- obj.free();
+ }
+- out->endStringOp(state);
+ }
+
+ void Gfx::doShowText(GString *s) {
+@@ -3130,14 +3338,18 @@
+ double riseX, riseY;
+ CharCode code;
+ Unicode u[8];
+- double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, lineX, lineY;
++ double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, ddx, ddy;
+ double originX, originY, tOriginX, tOriginY;
++ double x0, y0, x1, y1;
+ double oldCTM[6], newCTM[6];
+ double *mat;
+ Object charProc;
+ Dict *resDict;
+ Parser *oldParser;
++ GfxState *savedState;
+ char *p;
++ int render;
++ GBool patternFill;
+ int len, n, uLen, nChars, nSpaces, i;
+
+ font = state->getFont();
+@@ -3147,6 +3359,28 @@
+ out->beginString(state, s);
+ }
+
++ // if we're doing a pattern fill, set up clipping
++ render = state->getRender();
++ if (!(render & 1) &&
++ state->getFillColorSpace()->getMode() == csPattern) {
++ patternFill = gTrue;
++ saveState();
++ // disable fill, enable clipping, leave stroke unchanged
++ if ((render ^ (render >> 1)) & 1) {
++ render = 5;
++ } else {
++ render = 7;
++ }
++ state->setRender(render);
++ out->updateRender(state);
++ } else {
++ patternFill = gFalse;
++ }
++
++ state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
++ x0 = state->getCurX() + riseX;
++ y0 = state->getCurY() + riseY;
++
+ // handle a Type 3 char
+ if (font->getType() == fontType3 && out->interpretType3Chars()) {
+ mat = state->getCTM();
+@@ -3169,11 +3403,8 @@
+ newCTM[3] *= state->getFontSize();
+ newCTM[0] *= state->getHorizScaling();
+ newCTM[2] *= state->getHorizScaling();
+- state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
+ curX = state->getCurX();
+ curY = state->getCurY();
+- lineX = state->getLineX();
+- lineY = state->getLineY();
+ oldParser = parser;
+ p = s->getCString();
+ len = s->getLength();
+@@ -3189,11 +3420,12 @@
+ dy *= state->getFontSize();
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
+ state->transform(curX + riseX, curY + riseY, &x, &y);
+- saveState();
++ savedState = saveStateStack();
+ state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
+ //~ the CTM concat values here are wrong (but never used)
+ out->updateCTM(state, 1, 0, 0, 1, 0, 0);
+- if (!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy,
++ state->transformDelta(dx, dy, &ddx, &ddy);
++ if (!out->beginType3Char(state, curX + riseX, curY + riseY, ddx, ddy,
+ code, u, uLen)) {
+ ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
+ if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
+@@ -3210,20 +3443,16 @@
+ }
+ charProc.free();
+ }
+- restoreState();
+- // GfxState::restore() does *not* restore the current position,
+- // so we deal with it here using (curX, curY) and (lineX, lineY)
++ restoreStateStack(savedState);
+ curX += tdx;
+ curY += tdy;
+ state->moveTo(curX, curY);
+- state->textSetPos(lineX, lineY);
+ p += n;
+ len -= n;
+ }
+ parser = oldParser;
+
+ } else if (out->useDrawChar()) {
+- state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
+ p = s->getCString();
+ len = s->getLength();
+ while (len > 0) {
+@@ -3294,9 +3523,52 @@
+ out->endString(state);
+ }
+
++ if (patternFill) {
++ out->saveTextPos(state);
++ // tell the OutputDev to do the clipping
++ out->endTextObject(state);
++ // set up a clipping bbox so doPatternText will work -- assume
++ // that the text bounding box does not extend past the baseline in
++ // any direction by more than twice the font size
++ x1 = state->getCurX() + riseX;
++ y1 = state->getCurY() + riseY;
++ if (x0 > x1) {
++ x = x0; x0 = x1; x1 = x;
++ }
++ if (y0 > y1) {
++ y = y0; y0 = y1; y1 = y;
++ }
++ state->textTransformDelta(0, state->getFontSize(), &dx, &dy);
++ state->textTransformDelta(state->getFontSize(), 0, &dx2, &dy2);
++ dx = fabs(dx);
++ dx2 = fabs(dx2);
++ if (dx2 > dx) {
++ dx = dx2;
++ }
++ dy = fabs(dy);
++ dy2 = fabs(dy2);
++ if (dy2 > dy) {
++ dy = dy2;
++ }
++ state->clipToRect(x0 - 2 * dx, y0 - 2 * dy, x1 + 2 * dx, y1 + 2 * dy);
++ // set render mode to fill-only
++ state->setRender(0);
++ out->updateRender(state);
++ doPatternText();
++ restoreState();
++ out->restoreTextPos(state);
++ }
++
+ updateLevel += 10 * s->getLength();
+ }
+
++// NB: this is only called when ocState is false.
++void Gfx::doIncCharCount(GString *s) {
++ if (out->needCharCount()) {
++ out->incCharCount(s->getLength());
++ }
++}
++
+ //------------------------------------------------------------------------
+ // XObject operators
+ //------------------------------------------------------------------------
+@@ -3308,8 +3580,11 @@
+ Object opiDict;
+ #endif
+
++ if (!ocState && !out->needCharCount()) {
++ return;
++ }
+ name = args[0].getName();
+ if (!res->lookupXObject(name, &obj1)) {
+ return;
+ }
+ if (!obj1.isStream()) {
+@@ -3373,7 +3650,7 @@
+ GBool maskInvert;
+ Stream *maskStr;
+ Object obj1, obj2;
+- int i;
++ int i, n;
+
+ // get info from the stream
+ bits = 0;
+@@ -3389,19 +3666,27 @@
+ obj1.free();
+ dict->lookup("W", &obj1);
+ }
+- if (!obj1.isInt())
++ if (!obj1.isInt()) {
+ goto err2;
++ }
+ width = obj1.getInt();
+ obj1.free();
++ if (width <= 0) {
++ goto err1;
++ }
+ dict->lookup("Height", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("H", &obj1);
+ }
+- if (!obj1.isInt())
++ if (!obj1.isInt()) {
+ goto err2;
++ }
+ height = obj1.getInt();
+ obj1.free();
++ if (height <= 0) {
++ goto err1;
++ }
+
+ // image or mask?
+ dict->lookup("ImageMask", &obj1);
+@@ -3447,16 +3732,30 @@
+ }
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+- if (obj2.isInt() && obj2.getInt() == 1)
+- invert = gTrue;
++ invert = obj2.isNum() && obj2.getNum() == 1;
+ obj2.free();
+ } else if (!obj1.isNull()) {
+ goto err2;
+ }
+ obj1.free();
+
++ // if drawing is disabled, skip over inline image data
++ if (!ocState) {
++ str->reset();
++ n = height * ((width + 7) / 8);
++ for (i = 0; i < n; ++i) {
++ str->getChar();
++ }
++ str->close();
++
+ // draw it
+- out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
++ } else {
++ if (state->getFillColorSpace()->getMode() == csPattern) {
++ doPatternImageMask(ref, str, width, height, invert, inlineImg);
++ } else {
++ out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
++ }
++ }
+
+ } else {
+
+@@ -3581,14 +3880,36 @@
+ haveSoftMask = gTrue;
+ } else if (maskObj.isArray()) {
+ // color key mask
++ haveColorKeyMask = gTrue;
+ for (i = 0;
+- i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
+- ++i) {
++ i+1 < maskObj.arrayGetLength() && i+1 < 2*gfxColorMaxComps;
++ i += 2) {
+ maskObj.arrayGet(i, &obj1);
++ if (!obj1.isInt()) {
++ obj1.free();
++ haveColorKeyMask = gFalse;
++ break;
++ }
+ maskColors[i] = obj1.getInt();
+ obj1.free();
++ if (maskColors[i] < 0 || maskColors[i] >= (1 << bits)) {
++ haveColorKeyMask = gFalse;
++ break;
++ }
++ maskObj.arrayGet(i+1, &obj1);
++ if (!obj1.isInt()) {
++ obj1.free();
++ haveColorKeyMask = gFalse;
++ break;
++ }
++ maskColors[i+1] = obj1.getInt();
++ obj1.free();
++ if (maskColors[i+1] < 0 || maskColors[i+1] >= (1 << bits) ||
++ maskColors[i] > maskColors[i+1]) {
++ haveColorKeyMask = gFalse;
++ break;
++ }
+ }
+- haveColorKeyMask = gTrue;
+ } else if (maskObj.isStream()) {
+ // explicit mask
+ if (inlineImg) {
+@@ -3633,9 +3954,7 @@
+ }
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+- if (obj2.isInt() && obj2.getInt() == 1) {
+- maskInvert = gTrue;
+- }
++ maskInvert = obj2.isNum() && obj2.getNum() == 1;
+ obj2.free();
+ } else if (!obj1.isNull()) {
+ goto err2;
+@@ -3644,20 +3963,32 @@
+ haveExplicitMask = gTrue;
+ }
+
++ // if drawing is disabled, skip over inline image data
++ if (!ocState) {
++ str->reset();
++ n = height * ((width * colorMap->getNumPixelComps() *
++ colorMap->getBits() + 7) / 8);
++ for (i = 0; i < n; ++i) {
++ str->getChar();
++ }
++ str->close();
++
+ // draw it
+- if (haveSoftMask) {
+- out->drawSoftMaskedImage(state, ref, 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);
+ } else {
+- out->drawImage(state, ref, str, width, height, colorMap,
+- haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
++ if (haveSoftMask) {
++ out->drawSoftMaskedImage(state, ref, 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);
++ } else {
++ out->drawImage(state, ref, str, width, height, colorMap,
++ haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
++ }
+ }
+- delete colorMap;
+
++ delete colorMap;
+ maskObj.free();
+ smaskObj.free();
+ }
+@@ -3683,11 +4014,12 @@
+ double m[6], bbox[4];
+ Object resObj;
+ Dict *resDict;
++ GBool oc, ocSaved;
+ Object obj1, obj2, obj3;
+ int i;
+
+ // check for excessive recursion
+ if (formDepth > 100) {
+ return;
+ }
+
+@@ -3697,7 +4029,20 @@
+ // check form type
+ dict->lookup("FormType", &obj1);
+ if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
+ error(errSyntaxError, getPos(), "Unknown form type");
++ }
++ obj1.free();
++
++ // check for optional content key
++ ocSaved = ocState;
++ dict->lookupNF("OC", &obj1);
++ if (doc->getOptionalContent()->evalOCObject(&obj1, &oc) && !oc) {
++ obj1.free();
++ if (out->needCharCount()) {
++ ocState = gFalse;
++ } else {
++ return;
++ }
+ }
+ obj1.free();
+
+@@ -3705,7 +4050,8 @@
+ dict->lookup("BBox", &bboxObj);
+ if (!bboxObj.isArray()) {
+ bboxObj.free();
+ error(errSyntaxError, getPos(), "Bad form bounding box");
++ ocState = ocSaved;
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+@@ -3759,23 +4105,26 @@
+
+ // draw it
+ ++formDepth;
+- doForm1(str, resDict, m, bbox,
+- transpGroup, gFalse, blendingColorSpace, isolated, knockout);
++ drawForm(str, resDict, m, bbox,
++ transpGroup, gFalse, blendingColorSpace, isolated, knockout);
+ --formDepth;
+
+ if (blendingColorSpace) {
+ delete blendingColorSpace;
+ }
+ resObj.free();
++
++ ocState = ocSaved;
+ }
+
+-void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
+- GBool transpGroup, GBool softMask,
+- GfxColorSpace *blendingColorSpace,
+- GBool isolated, GBool knockout,
+- GBool alpha, Function *transferFunc,
+- GfxColor *backdropColor) {
++void Gfx::drawForm(Object *str, Dict *resDict, double *matrix, double *bbox,
++ GBool transpGroup, GBool softMask,
++ GfxColorSpace *blendingColorSpace,
++ GBool isolated, GBool knockout,
++ GBool alpha, Function *transferFunc,
++ GfxColor *backdropColor) {
+ Parser *oldParser;
++ GfxState *savedState;
+ double oldBaseMatrix[6];
+ int i;
+
+@@ -3783,7 +4132,7 @@
+ pushResources(resDict);
+
+ // save current graphics state
+- saveState();
++ savedState = saveStateStack();
+
+ // kill any pre-existing path
+ state->clearPath();
+@@ -3847,7 +4196,7 @@
+ parser = oldParser;
+
+ // restore graphics state
+- restoreState();
++ restoreStateStack(savedState);
+
+ // pop resource stack
+ popResources();
+@@ -3869,6 +4218,9 @@
+ Stream *str;
+ int c1, c2;
+
++ // NB: this function is run even if ocState is false -- doImage() is
++ // responsible for skipping over the inline image data
++
+ // build dict/stream
+ str = buildImageStream();
+
+@@ -3921,18 +4274,23 @@
+ obj.free();
+
+ // make stream
+- str = new EmbedStream(parser->getStream(), &dict, gFalse, 0);
++ if (!(str = parser->getStream())) {
++ error(errSyntaxError, getPos(), "Invalid inline image data");
++ dict.free();
++ return NULL;
++ }
++ str = new EmbedStream(str, &dict, gFalse, 0);
+ str = str->addFilters(&dict);
+
+ return str;
+ }
+
+ void Gfx::opImageData(Object args[], int numArgs) {
+ error(errInternal, getPos(), "Got 'ID' operator");
+ }
+
+ void Gfx::opEndImage(Object args[], int numArgs) {
+ error(errInternal, getPos(), "Got 'EI' operator");
+ }
+
+ //------------------------------------------------------------------------
+@@ -3967,23 +4325,88 @@
+ //------------------------------------------------------------------------
+
+ void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
++ GfxMarkedContent *mc;
++ Object obj;
++ GBool ocStateNew;
++ GString *s;
++ Unicode *u;
++ int uLen, i;
++ GfxMarkedContentKind mcKind;
++
+ if (printCommands) {
+ printf(" marked content: %s ", args[0].getName());
+- if (numArgs == 2)
+- args[2].print(stdout);
++ if (numArgs == 2) {
++ args[1].print(stdout);
++ }
+ printf("\n");
+ fflush(stdout);
+ }
++ mcKind = gfxMCOther;
++ if (args[0].isName("OC") && numArgs == 2 && args[1].isName() &&
++ res->lookupPropertiesNF(args[1].getName(), &obj)) {
++ if (doc->getOptionalContent()->evalOCObject(&obj, &ocStateNew)) {
++ ocState = ocStateNew;
++ }
++ obj.free();
++ mcKind = gfxMCOptionalContent;
+ }
+
+ void Gfx::opEndMarkedContent(Object args[], int numArgs) {
++ GfxMarkedContent *mc;
++ GfxMarkedContentKind mcKind;
++
++ if (markedContentStack->getLength() > 0) {
++ mc = (GfxMarkedContent *)
++ markedContentStack->del(markedContentStack->getLength() - 1);
++ mcKind = mc->kind;
++ delete mc;
++ if (mcKind == gfxMCOptionalContent) {
++ if (markedContentStack->getLength() > 0) {
++ mc = (GfxMarkedContent *)
++ markedContentStack->get(markedContentStack->getLength() - 1);
++ ocState = mc->ocState;
++ } else {
++ ocState = gTrue;
++ }
+
+
+ void Gfx::opMarkPoint(Object args[], int numArgs) {
+ if (printCommands) {
+ printf(" mark point: %s ", args[0].getName());
+ if (numArgs == 2)
+- args[2].print(stdout);
++ args[1].print(stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+@@ -3996,45 +4419,23 @@
+ dict->lookup("Resources", &resObj);
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
+
+ // draw it
+- doForm1(str, resDict, m, bbox);
++ drawForm(str, resDict, m, bbox);
+
+ resObj.free();
+ }
+@@ -4168,6 +4598,27 @@
+ out->restoreState(state);
+ }
+
++// Create a new state stack, and initialize it with a copy of the
++// current state.
++GfxState *Gfx::saveStateStack() {
++ GfxState *oldState;
++
++ out->saveState(state);
++ oldState = state;
++ state = state->copy(gTrue);
++ return oldState;
++}
++
++// Switch back to the previous state stack.
++void Gfx::restoreStateStack(GfxState *oldState) {
++ while (state->hasSaves()) {
++ restoreState();
++ }
++ delete state;
++ state = oldState;
++ out->restoreState(state);
++}
++
+ void Gfx::pushResources(Dict *resDict) {
+ res = new GfxResources(xref, resDict, res);
+ }
+diff -ru xpdf-3.02/xpdf/GfxFont.cc xpdf-3.03/xpdf/GfxFont.cc
+--- xpdf-3.02/xpdf/GfxFont.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/GfxFont.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -16,6 +16,11 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <ctype.h>
++#include <math.h>
++#include <limits.h>
++#if HAVE_STD_SORT
++#include <algorithm>
++#endif
+ #include "gmem.h"
+ #include "Error.h"
+ #include "Object.h"
+@@ -25,6 +30,7 @@
+ #include "CharCodeToUnicode.h"
+ #include "FontEncodingTables.h"
+ #include "BuiltinFontTables.h"
++#include "FoFiIdentifier.h"
+ #include "FoFiType1.h"
+ #include "FoFiType1C.h"
+ #include "FoFiTrueType.h"
+@@ -93,15 +107,66 @@
+ GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) {
+ GString *nameA;
++ Ref embFontIDA;
++ GfxFontType typeA;
+ GfxFont *font;
+ Object obj1;
+
+@@ -113,53 +178,235 @@
+ }
+ obj1.free();
+
+- // get font type
++ // get embedded font ID and font type
++ typeA = getFontType(xref, fontDict, &embFontIDA);
++
++ // create the font object
+ font = NULL;
+- fontDict->lookup("Subtype", &obj1);
+- if (obj1.isName("Type1") || obj1.isName("MMType1")) {
+- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict);
+- } else if (obj1.isName("Type1C")) {
+- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict);
+- } else if (obj1.isName("Type3")) {
+- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict);
+- } else if (obj1.isName("TrueType")) {
+- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict);
+- } else if (obj1.isName("Type0")) {
+- font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict);
++ if (typeA < fontCIDType0) {
++ font = new Gfx8BitFont(xref, tagA, idA, nameA, typeA, embFontIDA,
++ fontDict);
+ } else {
+- error(-1, "Unknown font type: '%s'",
+- obj1.isName() ? obj1.getName() : "???");
+- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict);
++ font = new GfxCIDFont(xref, tagA, idA, nameA, typeA, embFontIDA,
++ fontDict);
+ }
+- obj1.free();
+
+ return font;
+ }
+
+-GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA) {
++GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA,
++ GfxFontType typeA, Ref embFontIDA) {
+ ok = gFalse;
+ tag = new GString(tagA);
+ id = idA;
+ name = nameA;
++ type = typeA;
++ embFontID = embFontIDA;
+ embFontName = NULL;
+- extFontFile = NULL;
+ }
+
+ GfxFont::~GfxFont() {
+ delete tag;
+ if (name) {
+ delete name;
+ }
+ if (embFontName) {
+ delete embFontName;
+ }
+- if (extFontFile) {
+- delete extFontFile;
++}
++
++// This function extracts three pieces of information:
++// 1. the "expected" font type, i.e., the font type implied by
++// Font.Subtype, DescendantFont.Subtype, and
++// FontDescriptor.FontFile3.Subtype
++// 2. the embedded font object ID
++// 3. the actual font type - determined by examining the embedded font
++// if there is one, otherwise equal to the expected font type
++// If the expected and actual font types don't match, a warning
++// message is printed. The expected font type is not used for
++// anything else.
++GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) {
++ GfxFontType t, expectedType;
++ FoFiIdentifierType fft;
++ Dict *fontDict2;
++ Object subtype, fontDesc, obj1, obj2, obj3, obj4;
++ GBool isType0, err;
++
++ t = fontUnknownType;
++ embID->num = embID->gen = -1;
++ err = gFalse;
++
++ fontDict->lookup("Subtype", &subtype);
++ expectedType = fontUnknownType;
++ isType0 = gFalse;
++ if (subtype.isName("Type1") || subtype.isName("MMType1")) {
++ expectedType = fontType1;
++ } else if (subtype.isName("Type1C")) {
++ expectedType = fontType1C;
++ } else if (subtype.isName("Type3")) {
++ expectedType = fontType3;
++ } else if (subtype.isName("TrueType")) {
++ expectedType = fontTrueType;
++ } else if (subtype.isName("Type0")) {
++ isType0 = gTrue;
++ } else {
++ error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'",
++ subtype.isName() ? subtype.getName() : "???");
++ }
++ subtype.free();
++
++ fontDict2 = fontDict;
++ if (fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
++ if (obj1.arrayGetLength() == 0) {
++ error(errSyntaxWarning, -1, "Empty DescendantFonts array in font");
++ obj2.initNull();
++ } else if (obj1.arrayGet(0, &obj2)->isDict()) {
++ if (!isType0) {
++ error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array");
++ }
++ fontDict2 = obj2.getDict();
++ fontDict2->lookup("Subtype", &subtype);
++ if (subtype.isName("CIDFontType0")) {
++ if (isType0) {
++ expectedType = fontCIDType0;
++ }
++ } else if (subtype.isName("CIDFontType2")) {
++ if (isType0) {
++ expectedType = fontCIDType2;
++ }
++ }
++ subtype.free();
++ }
++ } else {
++ obj2.initNull();
++ }
++
++ if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) {
++ if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) {
++ *embID = obj3.getRef();
++ if (expectedType != fontType1) {
++ err = gTrue;
++ }
++ }
++ obj3.free();
++ if (embID->num == -1 &&
++ fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) {
++ *embID = obj3.getRef();
++ if (isType0) {
++ expectedType = fontCIDType2;
++ } else if (expectedType != fontTrueType) {
++ err = gTrue;
++ }
++ }
++ obj3.free();
++ if (embID->num == -1 &&
++ fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) {
++ *embID = obj3.getRef();
++ if (obj3.fetch(xref, &obj4)->isStream()) {
++ obj4.streamGetDict()->lookup("Subtype", &subtype);
++ if (subtype.isName("Type1")) {
++ if (expectedType != fontType1) {
++ err = gTrue;
++ expectedType = isType0 ? fontCIDType0 : fontType1;
++ }
++ } else if (subtype.isName("Type1C")) {
++ if (expectedType == fontType1) {
++ expectedType = fontType1C;
++ } else if (expectedType != fontType1C) {
++ err = gTrue;
++ expectedType = isType0 ? fontCIDType0C : fontType1C;
++ }
++ } else if (subtype.isName("TrueType")) {
++ if (expectedType != fontTrueType) {
++ err = gTrue;
++ expectedType = isType0 ? fontCIDType2 : fontTrueType;
++ }
++ } else if (subtype.isName("CIDFontType0C")) {
++ if (expectedType == fontCIDType0) {
++ expectedType = fontCIDType0C;
++ } else {
++ err = gTrue;
++ expectedType = isType0 ? fontCIDType0C : fontType1C;
++ }
++ } else if (subtype.isName("OpenType")) {
++ if (expectedType == fontTrueType) {
++ expectedType = fontTrueTypeOT;
++ } else if (expectedType == fontType1) {
++ expectedType = fontType1COT;
++ } else if (expectedType == fontCIDType0) {
++ expectedType = fontCIDType0COT;
++ } else if (expectedType == fontCIDType2) {
++ expectedType = fontCIDType2OT;
++ } else {
++ err = gTrue;
++ }
++ } else {
++ error(errSyntaxError, -1, "Unknown font type '{0:s}'",
++ subtype.isName() ? subtype.getName() : "???");
++ }
++ subtype.free();
++ }
++ obj4.free();
++ }
++ obj3.free();
++ }
++ fontDesc.free();
++
++ t = fontUnknownType;
++ if (embID->num >= 0) {
++ obj3.initRef(embID->num, embID->gen);
++ obj3.fetch(xref, &obj4);
++ if (obj4.isStream()) {
++ obj4.streamReset();
++ fft = FoFiIdentifier::identifyStream(&readFromStream, obj4.getStream());
++ obj4.streamClose();
++ switch (fft) {
++ case fofiIdType1PFA:
++ case fofiIdType1PFB:
++ t = fontType1;
++ break;
++ case fofiIdCFF8Bit:
++ t = isType0 ? fontCIDType0C : fontType1C;
++ break;
++ case fofiIdCFFCID:
++ t = fontCIDType0C;
++ break;
++ case fofiIdTrueType:
++ case fofiIdTrueTypeCollection:
++ t = isType0 ? fontCIDType2 : fontTrueType;
++ break;
++ case fofiIdOpenTypeCFF8Bit:
++ t = isType0 ? fontCIDType0COT : fontType1COT;
++ break;
++ case fofiIdOpenTypeCFFCID:
++ t = fontCIDType0COT;
++ break;
++ default:
++ error(errSyntaxError, -1, "Embedded font file may be invalid");
++ break;
++ }
++ }
++ obj4.free();
++ obj3.free();
++ }
++
++ if (t == fontUnknownType) {
++ t = expectedType;
+ }
++
++ if (t != expectedType) {
++ err = gTrue;
++ }
++
++ if (err) {
++ error(errSyntaxWarning, -1,
++ "Mismatch between font type and embedded font file");
++ }
++
++ obj2.free();
++ obj1.free();
++
++ return t;
+ }
+
+ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
+@@ -170,8 +417,6 @@
+ // assume Times-Roman by default (for substitution purposes)
+ flags = fontSerif;
+
+- embFontID.num = -1;
+- embFontID.gen = -1;
+ missingWidth = 0;
+
+ if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
+@@ -189,75 +434,6 @@
+ }
+ obj2.free();
+
+- // look for embedded font file
+- if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) {
+- embFontID = obj2.getRef();
+- if (type != fontType1) {
+- error(-1, "Mismatch between font type and embedded font file");
+- type = fontType1;
+- }
+- }
+- obj2.free();
+- if (embFontID.num == -1 &&
+- obj1.dictLookupNF("FontFile2", &obj2)->isRef()) {
+- embFontID = obj2.getRef();
+- if (type != fontTrueType && type != fontCIDType2) {
+- error(-1, "Mismatch between font type and embedded font file");
+- type = type == fontCIDType0 ? fontCIDType2 : fontTrueType;
+- }
+- }
+- obj2.free();
+- if (embFontID.num == -1 &&
+- obj1.dictLookupNF("FontFile3", &obj2)->isRef()) {
+- if (obj2.fetch(xref, &obj3)->isStream()) {
+- obj3.streamGetDict()->lookup("Subtype", &obj4);
+- if (obj4.isName("Type1")) {
+- embFontID = obj2.getRef();
+- if (type != fontType1) {
+- error(-1, "Mismatch between font type and embedded font file");
+- type = fontType1;
+- }
+- } else if (obj4.isName("Type1C")) {
+- embFontID = obj2.getRef();
+- if (type != fontType1 && type != fontType1C) {
+- error(-1, "Mismatch between font type and embedded font file");
+- }
+- type = fontType1C;
+- } else if (obj4.isName("TrueType")) {
+- embFontID = obj2.getRef();
+- if (type != fontTrueType) {
+- error(-1, "Mismatch between font type and embedded font file");
+- type = fontTrueType;
+- }
+- } else if (obj4.isName("CIDFontType0C")) {
+- embFontID = obj2.getRef();
+- if (type != fontCIDType0) {
+- error(-1, "Mismatch between font type and embedded font file");
+- }
+- type = fontCIDType0C;
+- } else if (obj4.isName("OpenType")) {
+- embFontID = obj2.getRef();
+- if (type == fontTrueType) {
+- type = fontTrueTypeOT;
+- } else if (type == fontType1) {
+- type = fontType1COT;
+- } else if (type == fontCIDType0) {
+- type = fontCIDType0COT;
+- } else if (type == fontCIDType2) {
+- type = fontCIDType2OT;
+- } else {
+- error(-1, "Mismatch between font type and embedded font file");
+- }
+- } else {
+- error(-1, "Unknown embedded font type '%s'",
+- obj4.isName() ? obj4.getName() : "???");
+- }
+- obj4.free();
+- }
+- obj3.free();
+- }
+- obj2.free();
+-
+ // look for MissingWidth
+ obj1.dictLookup("MissingWidth", &obj2);
+ if (obj2.isNum()) {
+@@ -269,8 +445,13 @@
+ obj1.dictLookup("Ascent", &obj2);
+ if (obj2.isNum()) {
+ t = 0.001 * obj2.getNum();
+- // some broken font descriptors set ascent and descent to 0
+- if (t != 0) {
++ // some broken font descriptors specify a negative ascent
++ if (t < 0) {
++ t = -t;
++ }
++ // some broken font descriptors set ascent and descent to 0;
++ // others set it to ridiculous values (e.g., 32768)
++ if (t != 0 && t < 3) {
+ ascent = t;
+ }
+ }
+@@ -278,14 +459,14 @@
+ obj1.dictLookup("Descent", &obj2);
+ if (obj2.isNum()) {
+ t = 0.001 * obj2.getNum();
++ // some broken font descriptors specify a positive descent
++ if (t > 0) {
++ t = -t;
++ }
+ // some broken font descriptors set ascent and descent to 0
+- if (t != 0) {
++ if (t != 0 && t > -3) {
+ descent = t;
+ }
+- // some broken font descriptors specify a positive descent
+- if (descent > 0) {
+- descent = -descent;
+- }
+ }
+ obj2.free();
+
+@@ -330,37 +511,280 @@
+ return ctu;
+ }
+
+-void GfxFont::findExtFontFile() {
+- static char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL };
+- static char *ttExts[] = { ".ttf", NULL };
++GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) {
++ GfxFontLoc *fontLoc;
++ SysFontType sysFontType;
++ GString *path, *base14Name, *substName;
++ PSFontParam16 *psFont16;
++ Object refObj, embFontObj;
++ int substIdx, fontNum;
++ GBool embed;
+
+- if (name) {
+- if (type == fontType1) {
+- extFontFile = globalParams->findFontFile(name, type1Exts);
+- } else if (type == fontTrueType) {
+- extFontFile = globalParams->findFontFile(name, ttExts);
++ if (type == fontType3) {
++ return NULL;
++ }
++
++ //----- embedded font
++ if (embFontID.num >= 0) {
++ embed = gTrue;
++ refObj.initRef(embFontID.num, embFontID.gen);
++ refObj.fetch(xref, &embFontObj);
++ if (!embFontObj.isStream()) {
++ error(errSyntaxError, -1, "Embedded font object is wrong type");
++ embed = gFalse;
++ }
++ embFontObj.free();
++ refObj.free();
++ if (embed) {
++ if (ps) {
++ switch (type) {
++ case fontType1:
++ case fontType1C:
++ case fontType1COT:
++ embed = globalParams->getPSEmbedType1();
++ break;
++ case fontTrueType:
++ case fontTrueTypeOT:
++ embed = globalParams->getPSEmbedTrueType();
++ break;
++ case fontCIDType0C:
++ case fontCIDType0COT:
++ embed = globalParams->getPSEmbedCIDPostScript();
++ break;
++ case fontCIDType2:
++ case fontCIDType2OT:
++ embed = globalParams->getPSEmbedCIDTrueType();
++ break;
++ default:
++ break;
++ }
++ }
++ if (embed) {
++ fontLoc = new GfxFontLoc();
++ fontLoc->locType = gfxFontLocEmbedded;
++ fontLoc->fontType = type;
++ fontLoc->embFontID = embFontID;
++ return fontLoc;
++ }
++ }
++ }
++
++ //----- PS passthrough
++ if (ps && !isCIDFont() && globalParams->getPSFontPassthrough()) {
++ fontLoc = new GfxFontLoc();
++ fontLoc->locType = gfxFontLocResident;
++ fontLoc->fontType = fontType1;
++ fontLoc->path = name->copy();
++ return fontLoc;
++ }
++
++ //----- PS resident Base-14 font
++ if (ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
++ fontLoc = new GfxFontLoc();
++ fontLoc->locType = gfxFontLocResident;
++ fontLoc->fontType = fontType1;
++ fontLoc->path = new GString(((Gfx8BitFont *)this)->base14->base14Name);
++ return fontLoc;
++ }
++
++ //----- external font file (fontFile, fontDir)
++ if ((path = globalParams->findFontFile(name))) {
++ if ((fontLoc = getExternalFont(path, isCIDFont()))) {
++ return fontLoc;
++ }
++ }
++
++ //----- external font file for Base-14 font
++ if (!ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) {
++ base14Name = new GString(((Gfx8BitFont *)this)->base14->base14Name);
++ if ((path = globalParams->findFontFile(base14Name))) {
++ if ((fontLoc = getExternalFont(path, gFalse))) {
++ delete base14Name;
++ return fontLoc;
++ }
++ }
++ delete base14Name;
++ }
++
++ //----- system font
++ if ((path = globalParams->findSystemFontFile(name, &sysFontType,
++ &fontNum))) {
++ if (isCIDFont()) {
++ if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
++ fontLoc = new GfxFontLoc();
++ fontLoc->locType = gfxFontLocExternal;
++ fontLoc->fontType = fontCIDType2;
++ fontLoc->path = path;
++ fontLoc->fontNum = fontNum;
++ return fontLoc;
++ }
++ } else {
++ if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) {
++ fontLoc = new GfxFontLoc();
++ fontLoc->locType = gfxFontLocExternal;
++ fontLoc->fontType = fontTrueType;
++ fontLoc->path = path;
++ return fontLoc;
++ } else if (sysFontType == sysFontPFA || sysFontType == sysFontPFB) {
++ fontLoc = new GfxFontLoc();
++ fontLoc->locType = gfxFontLocExternal;
++ fontLoc->fontType = fontType1;
++ fontLoc->path = path;
++ fontLoc->fontNum = fontNum;
++ return fontLoc;
++ }
++ }
++ delete path;
++ }
++
++ if (!isCIDFont()) {
++
++ //----- 8-bit PS resident font
++ if (ps) {
++ if ((path = globalParams->getPSResidentFont(name))) {
++ fontLoc = new GfxFontLoc();
++ fontLoc->locType = gfxFontLocResident;
++ fontLoc->fontType = fontType1;
++ fontLoc->path = path;
++ return fontLoc;
++ }
++ }
++
++ //----- 8-bit font substitution
++ if (flags & fontFixedWidth) {
++ substIdx = 0;
++ } else if (flags & fontSerif) {
++ substIdx = 8;
++ } else {
++ substIdx = 4;
++ }
++ if (isBold()) {
++ substIdx += 2;
++ }
++ if (isItalic()) {
++ substIdx += 1;
++ }
++ substName = new GString(base14SubstFonts[substIdx]);
++ if (ps) {
++ error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'",
++ base14SubstFonts[substIdx], name);
++ fontLoc = new GfxFontLoc();
++ fontLoc->locType = gfxFontLocResident;
++ fontLoc->fontType = fontType1;
++ fontLoc->path = substName;
++ fontLoc->substIdx = substIdx;
++ return fontLoc;
++ } else {
++ path = globalParams->findFontFile(substName);
++ delete substName;
++ if (path) {
++ if ((fontLoc = getExternalFont(path, gFalse))) {
++ error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'",
++ base14SubstFonts[substIdx], name);
++ fontLoc->substIdx = substIdx;
++ return fontLoc;
++ }
++ }
++ }
++
++ // failed to find a substitute font
++ return NULL;
++ }
++
++ //----- 16-bit PS resident font
++ if (ps && ((psFont16 = globalParams->getPSResidentFont16(
++ name,
++ ((GfxCIDFont *)this)->getWMode())))) {
++ fontLoc = new GfxFontLoc();
++ fontLoc->locType = gfxFontLocResident;
++ fontLoc->fontType = fontCIDType0; // this is not used
++ fontLoc->path = psFont16->psFontName->copy();
++ fontLoc->encoding = psFont16->encoding->copy();
++ fontLoc->wMode = psFont16->wMode;
++ return fontLoc;
++ }
++ if (ps && ((psFont16 = globalParams->getPSResidentFontCC(
++ ((GfxCIDFont *)this)->getCollection(),
++ ((GfxCIDFont *)this)->getWMode())))) {
++ error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
++ psFont16->psFontName, name);
++ fontLoc = new GfxFontLoc();
++ fontLoc->locType = gfxFontLocResident;
++ fontLoc->fontType = fontCIDType0; // this is not used
++ fontLoc->path = psFont16->psFontName->copy();
++ fontLoc->encoding = psFont16->encoding->copy();
++ fontLoc->wMode = psFont16->wMode;
++ return fontLoc;
++ }
++
++ //----- CID font substitution
++ if ((path = globalParams->findCCFontFile(
++ ((GfxCIDFont *)this)->getCollection()))) {
++ if ((fontLoc = getExternalFont(path, gTrue))) {
++ error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'",
++ fontLoc->path, name);
++ return fontLoc;
+ }
+ }
++
++ // failed to find a substitute font
++ return NULL;
+ }
+
+-char *GfxFont::readExtFontFile(int *len) {
+- FILE *f;
+- char *buf;
++GfxFontLoc *GfxFont::locateBase14Font(GString *base14Name) {
++ GString *path;
+
+- if (!(f = fopen(extFontFile->getCString(), "rb"))) {
+- error(-1, "External font file '%s' vanished", extFontFile->getCString());
++ path = globalParams->findFontFile(base14Name);
++ if (!path) {
+ return NULL;
+ }
+- fseek(f, 0, SEEK_END);
+- *len = (int)ftell(f);
+- fseek(f, 0, SEEK_SET);
+- buf = (char *)gmalloc(*len);
+- if ((int)fread(buf, 1, *len, f) != *len) {
+- error(-1, "Error reading external font file '%s'",
+- extFontFile->getCString());
++ return getExternalFont(path, gFalse);
++}
++
++GfxFontLoc *GfxFont::getExternalFont(GString *path, GBool cid) {
++ FoFiIdentifierType fft;
++ GfxFontType fontType;
++ GfxFontLoc *fontLoc;
++
++ fft = FoFiIdentifier::identifyFile(path->getCString());
++ switch (fft) {
++ case fofiIdType1PFA:
++ case fofiIdType1PFB:
++ fontType = fontType1;
++ break;
++ case fofiIdCFF8Bit:
++ fontType = fontType1C;
++ break;
++ case fofiIdCFFCID:
++ fontType = fontCIDType0C;
++ break;
++ case fofiIdTrueType:
++ case fofiIdTrueTypeCollection:
++ fontType = cid ? fontCIDType2 : fontTrueType;
++ break;
++ case fofiIdOpenTypeCFF8Bit:
++ fontType = fontType1COT;
++ break;
++ case fofiIdOpenTypeCFFCID:
++ fontType = fontCIDType0COT;
++ break;
++ case fofiIdUnknown:
++ case fofiIdError:
++ default:
++ fontType = fontUnknownType;
++ break;
++ }
++ if (fontType == fontUnknownType ||
++ (cid ? (fontType < fontCIDType0)
++ : (fontType >= fontCIDType0))) {
++ delete path;
++ return NULL;
+ }
+- fclose(f);
+- return buf;
++ fontLoc = new GfxFontLoc();
++ fontLoc->locType = gfxFontLocExternal;
++ fontLoc->fontType = fontType;
++ fontLoc->path = path;
++ return fontLoc;
+ }
+
+ char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
+@@ -386,6 +810,10 @@
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ if (i == size) {
++ if (size > INT_MAX - 4096) {
++ error(errSyntaxError, -1, "Embedded font file is too large");
++ break;
++ }
+ size += 4096;
+ buf = (char *)grealloc(buf, size);
+ }
+@@ -405,8 +833,8 @@
+ //------------------------------------------------------------------------
+
+ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+- GfxFontType typeA, Dict *fontDict):
+- GfxFont(tagA, idA, nameA)
++ GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
++ GfxFont(tagA, idA, nameA, typeA, embFontIDA)
+ {
+ GString *name2;
+ BuiltinFont *builtinFont;
+@@ -428,11 +856,11 @@
+ Object obj1, obj2, obj3;
+ int n, i, a, b, m;
+
+- type = typeA;
+ ctu = NULL;
+
+ // do font name substitution for various aliases of the Base 14 font
+ // names
+ base14 = NULL;
+ if (name) {
+ name2 = name->copy();
+ i = 0;
+@@ -499,9 +927,6 @@
+ fontBBox[3] = 0.001 * builtinFont->bbox[3];
+ }
+
+- // look for an external font file
+- findExtFontFile();
+-
+ // get font matrix
+ fontMat[0] = fontMat[3] = 1;
+ fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
+@@ -581,54 +1007,45 @@
+ baseEnc = winAnsiEncoding;
+ }
+
+- // check embedded or external font file for base encoding
++ // check embedded font file for base encoding
+ // (only for Type 1 fonts - trying to get an encoding out of a
+ // TrueType font is a losing proposition)
+ ffT1 = NULL;
+ ffT1C = NULL;
+ buf = NULL;
+- if (type == fontType1 && (extFontFile || embFontID.num >= 0)) {
+- if (extFontFile) {
+- ffT1 = FoFiType1::load(extFontFile->getCString());
+- } else {
+- buf = readEmbFontFile(xref, &len);
+- ffT1 = FoFiType1::make(buf, len);
+- }
+- if (ffT1) {
+- if (ffT1->getName()) {
+- if (embFontName) {
+- delete embFontName;
++ if (type == fontType1 && embFontID.num >= 0) {
++ if ((buf = readEmbFontFile(xref, &len))) {
++ if ((ffT1 = FoFiType1::make(buf, len))) {
++ if (ffT1->getName()) {
++ if (embFontName) {
++ delete embFontName;
++ }
++ embFontName = new GString(ffT1->getName());
++ }
++ if (!baseEnc) {
++ baseEnc = (const char **)ffT1->getEncoding();
++ baseEncFromFontFile = gTrue;
+ }
+- embFontName = new GString(ffT1->getName());
+- }
+- if (!baseEnc) {
+- baseEnc = (const char **)ffT1->getEncoding();
+- baseEncFromFontFile = gTrue;
+ }
++ gfree(buf);
+ }
+- } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) {
+- if (extFontFile) {
+- ffT1C = FoFiType1C::load(extFontFile->getCString());
+- } else {
+- buf = readEmbFontFile(xref, &len);
+- ffT1C = FoFiType1C::make(buf, len);
+- }
+- if (ffT1C) {
+- if (ffT1C->getName()) {
+- if (embFontName) {
+- delete embFontName;
++ } else if (type == fontType1C && embFontID.num >= 0) {
++ if ((buf = readEmbFontFile(xref, &len))) {
++ if ((ffT1C = FoFiType1C::make(buf, len))) {
++ if (ffT1C->getName()) {
++ if (embFontName) {
++ delete embFontName;
++ }
++ embFontName = new GString(ffT1C->getName());
++ }
++ if (!baseEnc) {
++ baseEnc = (const char **)ffT1C->getEncoding();
++ baseEncFromFontFile = gTrue;
+ }
+- embFontName = new GString(ffT1C->getName());
+- }
+- if (!baseEnc) {
+- baseEnc = (const char **)ffT1C->getEncoding();
+- baseEncFromFontFile = gTrue;
+ }
++ gfree(buf);
+ }
+ }
+- if (buf) {
+- gfree(buf);
+- }
+
+ // get default base encoding
+ if (!baseEnc) {
+@@ -644,7 +1061,7 @@
+
+ // copy the base encoding
+ for (i = 0; i < 256; ++i) {
+- enc[i] = baseEnc[i];
++ enc[i] = (char *)baseEnc[i];
+ if ((encFree[i] = baseEncFromFontFile) && enc[i]) {
+ enc[i] = copyString(baseEnc[i]);
+ }
+@@ -654,11 +1071,10 @@
+ // T1C->T1 conversion (since the 'seac' operator depends on having
+ // the accents in the encoding), so we fill in any gaps from
+ // StandardEncoding
+- if (type == fontType1C && (extFontFile || embFontID.num >= 0) &&
+- baseEncFromFontFile) {
++ if (type == fontType1C && embFontID.num >= 0 && baseEncFromFontFile) {
+ for (i = 0; i < 256; ++i) {
+ if (!enc[i] && standardEncoding[i]) {
+ enc[i] = (char *)standardEncoding[i];
+ encFree[i] = gFalse;
+ }
+ }
+@@ -734,14 +1151,21 @@
+ }
+
+ // pass 2: try to fill in the missing chars, looking for names of
+- // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B'
+- // are any letters, 'xx' is two hex digits, and 'nn' is 2-4
+- // decimal digits
++ // any of the following forms:
++ // - 'xx'
++ // - 'Axx'
++ // - 'nn'
++ // - 'Ann'
++ // - 'ABnn'
++ // - 'unixxxx' (possibly followed by garbage - some Arabic files
++ // use 'uni0628.medi', etc.)
++ // where 'A' and 'B' are any letters, 'xx' is two hex digits, 'xxxx'
++ // is four hex digits, and 'nn' is 2-4 decimal digits
+ if (missing && globalParams->getMapNumericCharNames()) {
+ for (code = 0; code < 256; ++code) {
+ if ((charName = enc[code]) && !toUnicode[code] &&
+ strcmp(charName, ".notdef")) {
+ n = strlen(charName);
+ code2 = -1;
+ if (hex && n == 3 && isalpha(charName[0]) &&
+ isxdigit(charName[1]) && isxdigit(charName[2])) {
+@@ -758,8 +1182,13 @@
+ } else if (n >= 4 && n <= 6 &&
+ isdigit(charName[2]) && isdigit(charName[3])) {
+ code2 = atoi(charName+2);
++ } else if (n >= 7 && charName[0] == 'u' && charName[1] == 'n' &&
++ charName[2] == 'i' &&
++ isxdigit(charName[3]) && isxdigit(charName[4]) &&
++ isxdigit(charName[5]) && isxdigit(charName[6])) {
++ sscanf(charName + 3, "%x", &code2);
+ }
+- if (code2 >= 0 && code2 <= 0xff) {
++ if (code2 >= 0 && code2 <= 0xffff) {
+ toUnicode[code] = (Unicode)code2;
+ }
+ }
+@@ -835,7 +1264,7 @@
+ obj1.arrayGet(code - firstChar, &obj2);
+ if (obj2.isNum()) {
+ widths[code] = obj2.getNum() * mul;
+- if (widths[code] != widths[firstChar]) {
++ if (fabs(widths[code] - widths[firstChar]) > 0.00001) {
+ flags &= ~fontFixedWidth;
+ }
+ }
+@@ -945,9 +1374,10 @@
+ // TrueType font has a Macintosh Roman cmap, use it, and
+ // reverse map the char names through MacRomanEncoding to
+ // get char codes.
+- // 1b. If the TrueType font has a Microsoft Unicode cmap or a
+- // non-Microsoft Unicode cmap, use it, and use the Unicode
+- // indexes, not the char codes.
++ // 1b. If the PDF font is not symbolic or the PDF font is not
++ // embedded, and the TrueType font has a Microsoft Unicode
++ // cmap or a non-Microsoft Unicode cmap, use it, and use the
++ // Unicode indexes, not the char codes.
+ // 1c. If the PDF font is symbolic and the TrueType font has a
+ // Microsoft Symbol cmap, use it, and use char codes
+ // directly (possibly with an offset of 0xf000).
+@@ -983,7 +1413,8 @@
+ if (usesMacRomanEnc && macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ useMacRoman = gTrue;
+- } else if (unicodeCmap >= 0) {
++ } else if ((!(flags & fontSymbolic) || embFontID.num < 0) &&
++ unicodeCmap >= 0) {
+ cmap = unicodeCmap;
+ useUnicode = gTrue;
+ } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) {
+@@ -1010,6 +1441,8 @@
+ if ((code = globalParams->getMacRomanCharCode(charName))) {
+ map[i] = ff->mapCodeToGID(cmap, code);
+ }
++ } else {
++ map[i] = -1;
+ }
+ }
+
+@@ -1020,6 +1453,8 @@
+ (u = globalParams->mapNameToUnicode(charName))) ||
+ (n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
+ map[i] = ff->mapCodeToGID(cmap, u);
++ } else {
++ map[i] = -1;
+ }
+ }
+
+@@ -1035,8 +1470,8 @@
+
+ // try the TrueType 'post' table to handle any unmapped characters
+ for (i = 0; i < 256; ++i) {
+- if (!map[i] && (charName = enc[i])) {
++ if (map[i] <= 0 && (charName = enc[i])) {
+ map[i] = ff->mapNameToGID(charName);
+ }
+ }
+
+@@ -1077,12 +1530,11 @@
+ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+- Dict *fontDict):
+- GfxFont(tagA, idA, nameA)
++ GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
++ GfxFont(tagA, idA, nameA, typeA, embFontIDA)
+ {
+ Dict *desFontDict;
+- GString *collection, *cMapName;
+ Object desFontDictObj;
+ Object obj1, obj2, obj3, obj4, obj5, obj6;
+ CharCodeToUnicode *utu;
+@@ -1091,8 +1545,10 @@
+ ascent = 0.95;
+ descent = -0.35;
+ fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
++ collection = NULL;
+ cMap = NULL;
+ ctu = NULL;
++ ctuUsesCharCode = gTrue;
+ widths.defWidth = 1.0;
+ widths.defHeight = -1.0;
+ widths.defVY = 0.880;
+@@ -1104,52 +1560,38 @@
+ cidToGIDLen = 0;
+
+ // get the descendant font
+- if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
+- error(-1, "Missing DescendantFonts entry in Type 0 font");
++ if (!fontDict->lookup("DescendantFonts", &obj1)->isArray() ||
++ obj1.arrayGetLength() == 0) {
++ error(errSyntaxError, -1,
++ "Missing or empty DescendantFonts entry in Type 0 font");
+ obj1.free();
++
+ goto err1;
+ }
+ if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) {
+- error(-1, "Bad descendant font in Type 0 font");
+- goto err3;
++ error(errSyntaxError, -1, "Bad descendant font in Type 0 font");
++ goto err2;
+ }
+ obj1.free();
+ desFontDict = desFontDictObj.getDict();
+
+- // font type
+- if (!desFontDict->lookup("Subtype", &obj1)) {
+- error(-1, "Missing Subtype entry in Type 0 descendant font");
+- goto err3;
+- }
+- if (obj1.isName("CIDFontType0")) {
+- type = fontCIDType0;
+- } else if (obj1.isName("CIDFontType2")) {
+- type = fontCIDType2;
+- } else {
+- error(-1, "Unknown Type 0 descendant font type '%s'",
+- obj1.isName() ? obj1.getName() : "???");
+- goto err3;
+- }
+- obj1.free();
+-
+ // get info from font descriptor
+ readFontDescriptor(xref, desFontDict);
+
+- // look for an external font file
+- findExtFontFile();
+-
+ //----- encoding info -----
+
+ // char collection
+ if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) {
+- error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font");
+- goto err3;
++ error(errSyntaxError, -1,
++ "Missing CIDSystemInfo dictionary in Type 0 descendant font");
++ goto err2;
+ }
+ obj1.dictLookup("Registry", &obj2);
+ obj1.dictLookup("Ordering", &obj3);
+ if (!obj2.isString() || !obj3.isString()) {
+- error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
+- goto err4;
++ error(errSyntaxError, -1,
++ "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
++ goto err3;
+ }
+ collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
+ obj3.free();
+@@ -1158,19 +1600,18 @@
+
+ // look for a ToUnicode CMap
+ if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) {
++ ctuUsesCharCode = gFalse;
+
+- // the "Adobe-Identity" and "Adobe-UCS" collections don't have
+- // cidToUnicode files
+- if (collection->cmp("Adobe-Identity") &&
+- collection->cmp("Adobe-UCS")) {
+-
+- // look for a user-supplied .cidToUnicode file
+- if (!(ctu = globalParams->getCIDToUnicode(collection))) {
+- error(-1, "Unknown character collection '%s'",
+- collection->getCString());
+- // fall-through, assuming the Identity mapping -- this appears
+- // to match Adobe's behavior
+- }
++ // use an identity mapping for the "Adobe-Identity" and
++ // "Adobe-UCS" collections
++ if (!collection->cmp("Adobe-Identity") ||
++ !collection->cmp("Adobe-UCS")) {
++ ctu = CharCodeToUnicode::makeIdentityMapping();
++
++ // look for a user-supplied .cidToUnicode file
++ } else if (!(ctu = globalParams->getCIDToUnicode(collection))) {
++ error(errSyntaxError, -1,
++ "Unknown character collection '{0:t}'", collection);
+ }
+ }
+
+@@ -1193,43 +1634,35 @@
+ }
+
+ // encoding (i.e., CMap)
+- //~ need to handle a CMap stream here
+- //~ also need to deal with the UseCMap entry in the stream dict
+- if (!fontDict->lookup("Encoding", &obj1)->isName()) {
+- error(-1, "Missing or invalid Encoding entry in Type 0 font");
+- delete collection;
+- goto err3;
++ if (fontDict->lookup("Encoding", &obj1)->isNull()) {
++ error(errSyntaxError, -1, "Missing Encoding entry in Type 0 font");
++ goto err2;
+ }
+- cMapName = new GString(obj1.getName());
+- obj1.free();
+- if (!(cMap = globalParams->getCMap(collection, cMapName))) {
+- error(-1, "Unknown CMap '%s' for character collection '%s'",
+- cMapName->getCString(), collection->getCString());
+- delete collection;
+- delete cMapName;
++ if (!(cMap = CMap::parse(NULL, collection, &obj1))) {
+ goto err2;
+ }
+- delete collection;
+- delete cMapName;
++ obj1.free();
+
+- // CIDToGIDMap (for embedded TrueType fonts)
+- if (type == fontCIDType2) {
++ // CIDToGIDMap
++ // (the PDF spec only allows these for TrueType fonts, but Acrobat
++ // apparently also allows them for OpenType CFF fonts)
++ if (type == fontCIDType2 || type == fontCIDType0COT) {
+ desFontDict->lookup("CIDToGIDMap", &obj1);
+ if (obj1.isStream()) {
+ cidToGIDLen = 0;
+ i = 64;
+@@ -1387,17 +1830,19 @@
+ ok = gTrue;
+ return;
+
+- err4:
++ err3:
+ obj3.free();
+ obj2.free();
+- err3:
+- obj1.free();
+ err2:
++ obj1.free();
+ desFontDictObj.free();
+ err1:;
+ }
+
+ GfxCIDFont::~GfxCIDFont() {
++ if (collection) {
++ delete collection;
++ }
+ if (cMap) {
+ cMap->decRefCnt();
+ }
+@@ -1425,12 +1871,16 @@
+ return 1;
+ }
+
+ *code = (CharCode)(cid = cMap->getCID(s, len, &c, &n));
+ if (ctu) {
+- *uLen = ctu->mapToUnicode(cid, u, uSize);
++ *uLen = ctu->mapToUnicode(ctuUsesCharCode ? c : cid, u, uSize);
+ } else {
+ *uLen = 0;
+ }
++ if (!*uLen && uSize >= 1 && globalParams->getMapUnknownCharNames()) {
++ u[0] = *code;
++ *uLen = 1;
++ }
+
+ // horizontal
+ if (cMap->getWMode() == 0) {
+diff -ru xpdf-3.02/xpdf/GfxFont.h xpdf-3.03/xpdf/GfxFont.h
+--- xpdf-3.02/xpdf/GfxFont.h 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/GfxFont.h 2011-08-15 23:08:53.000000000 +0200
+@@ -91,7 +127,8 @@
+ // Build a GfxFont object.
+ static GfxFont *makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict);
+
+- GfxFont(char *tagA, Ref idA, GString *nameA);
++ GfxFont(char *tagA, Ref idA, GString *nameA,
++ GfxFontType typeA, Ref embFontIDA);
+
+ virtual ~GfxFont();
+
+@@ -126,10 +160,6 @@
+ // NULL if there is no embedded font.
+ GString *getEmbeddedFontName() { return embFontName; }
+
+- // Get the name of the external font file. Returns NULL if there
+- // is no external font file.
+- GString *getExtFontFile() { return extFontFile; }
+-
+ // Get font descriptor flags.
+ int getFlags() { return flags; }
+ GBool isFixedWidth() { return flags & fontFixedWidth; }
+@@ -151,8 +181,14 @@
+ // Return the writing mode (0=horizontal, 1=vertical).
+ virtual int getWMode() { return 0; }
+
+- // Read an external or embedded font file into a buffer.
+- char *readExtFontFile(int *len);
++ // Locate the font file for this font. If <ps> is true, includes PS
++ // printer-resident fonts. Returns NULL on failure.
++ GfxFontLoc *locateFont(XRef *xref, GBool ps);
++
++ // Locate a Base-14 font file for a specified font name.
++ static GfxFontLoc *locateBase14Font(GString *base14Name);
++
++ // Read an embedded font file into a buffer.
+ char *readEmbFontFile(XRef *xref, int *len);
+
+ // Get the next char from a string <s> of <len> bytes, returning the
+@@ -167,22 +203,21 @@
+
+ protected:
+
++ static GfxFontType getFontType(XRef *xref, Dict *fontDict, Ref *embID);
+ void readFontDescriptor(XRef *xref, Dict *fontDict);
+ CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits,
+ CharCodeToUnicode *ctu);
+- void findExtFontFile();
++ static GfxFontLoc *getExternalFont(GString *path, GBool cid);
+
+ GString *tag; // PDF font tag
+ Ref id; // reference (used as unique ID)
+ GString *name; // font name
+ GfxFontType type; // type of font
+ int flags; // font descriptor flags
+ GString *embFontName; // name of embedded font
+ Ref embFontID; // ref to embedded font file stream
+- GString *extFontFile; // external font file name
+- double fontMat[6]; // font matrix (Type 3 only)
+- double fontBBox[4]; // font bounding box (Type 3 only)
++ double fontMat[6]; // font matrix
++ double fontBBox[4]; // font bounding box
+ double missingWidth; // "default" width
+ double ascent; // max height above baseline
+ double descent; // max depth below baseline
+@@ -197,7 +232,7 @@
+ public:
+
+ Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+- GfxFontType typeA, Dict *fontDict);
++ GfxFontType typeA, Ref embFontIDA, Dict *fontDict);
+
+ virtual ~Gfx8BitFont();
+
+@@ -247,6 +283,8 @@
+ double widths[256]; // character widths
+ Object charProcs; // Type 3 CharProcs dictionary
+ Object resources; // Type 3 Resources dictionary
++
++ friend class GfxFont;
+ };
+
+ //------------------------------------------------------------------------
+@@ -257,7 +295,7 @@
+ public:
+
+ GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+- Dict *fontDict);
++ GfxFontType typeA, Ref embFontIDA, Dict *fontDict);
+
+ virtual ~GfxCIDFont();
+
+@@ -278,15 +316,18 @@
+
+ private:
+
++ GString *collection; // collection name
+ CMap *cMap; // char code --> CID
+- CharCodeToUnicode *ctu; // CID --> Unicode
++ CharCodeToUnicode *ctu; // CID/char code --> Unicode
++ GBool ctuUsesCharCode; // true: ctu maps char code to Unicode;
++ // false: ctu maps CID to Unicode
+ GfxFontCIDWidths widths; // character widths
+diff -ru xpdf-3.02/xpdf/Gfx.h xpdf-3.03/xpdf/Gfx.h
+--- xpdf-3.02/xpdf/Gfx.h 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/Gfx.h 2011-08-15 23:08:53.000000000 +0200
+@@ -18,6 +18,8 @@
+ #include "gtypes.h"
+
+ class GString;
++class GList;
+ class PDFDoc;
+ class XRef;
+ class Array;
+ class Stream;
+@@ -141,8 +169,16 @@
+ // Get the current graphics state object.
+ GfxState *getState() { return state; }
+
++ void drawForm(Object *str, Dict *resDict, double *matrix, double *bbox,
++ GBool transpGroup = gFalse, GBool softMask = gFalse,
++ GfxColorSpace *blendingColorSpace = NULL,
++ GBool isolated = gFalse, GBool knockout = gFalse,
++ GBool alpha = gFalse, Function *transferFunc = NULL,
++ GfxColor *backdropColor = NULL);
++
+ private:
+
+ PDFDoc *doc;
+ XRef *xref; // the xref table for this PDF file
+ OutputDev *out; // output device
+ GBool subPage; // is this a sub-page object?
+@@ -157,6 +193,12 @@
+ double baseMatrix[6]; // default matrix for most recent
+ // page/form/pattern
+ int formDepth;
++ double textClipBBox[4]; // text clipping bounding box
++ GBool textClipBBoxEmpty; // true if textClipBBox has not been
++ // initialized yet
++ GBool ocState; // true if drawing is enabled, false if
++ // disabled
++ GList *markedContentStack; // BMC/BDC/EMC stack [GfxMarkedContent]
+
+ Parser *parser; // parser for page content stream(s)
+
+@@ -224,10 +266,13 @@
+ void opCloseEOFillStroke(Object args[], int numArgs);
+ void doPatternFill(GBool eoFill);
+ void doPatternStroke();
++ void doPatternText();
++ void doPatternImageMask(Object *ref, Stream *str, int width, int height,
++ GBool invert, GBool inlineImg);
+ void doTilingPatternFill(GfxTilingPattern *tPat,
+- GBool stroke, GBool eoFill);
++ GBool stroke, GBool eoFill, GBool text);
+ void doShadingPatternFill(GfxShadingPattern *sPat,
+- GBool stroke, GBool eoFill);
++ GBool stroke, GBool eoFill, GBool text);
+ void opShFill(Object args[], int numArgs);
+ void doFunctionShFill(GfxFunctionShading *shading);
+ void doFunctionShFill1(GfxFunctionShading *shading,
+@@ -274,17 +319,12 @@
+ void opMoveSetShowText(Object args[], int numArgs);
+ void opShowSpaceText(Object args[], int numArgs);
+ void doShowText(GString *s);
++ void doIncCharCount(GString *s);
+
+ // XObject operators
+ void opXObject(Object args[], int numArgs);
+ void doImage(Object *ref, Stream *str, GBool inlineImg);
+ void doForm(Object *str);
+- void doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
+- GBool transpGroup = gFalse, GBool softMask = gFalse,
+- GfxColorSpace *blendingColorSpace = NULL,
+- GBool isolated = gFalse, GBool knockout = gFalse,
+- GBool alpha = gFalse, Function *transferFunc = NULL,
+- GfxColor *backdropColor = NULL);
+
+ // in-line image operators
+ void opBeginImage(Object args[], int numArgs);
+@@ -305,6 +345,8 @@
+ void opEndMarkedContent(Object args[], int numArgs);
+ void opMarkPoint(Object args[], int numArgs);
+
++ GfxState *saveStateStack();
++ void restoreStateStack(GfxState *oldState);
+ void pushResources(Dict *resDict);
+ void popResources();
+ };
+diff -ru xpdf-3.02/xpdf/GfxState.cc xpdf-3.03/xpdf/GfxState.cc
+--- xpdf-3.02/xpdf/GfxState.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/GfxState.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -819,26 +854,27 @@
+ obj1.free();
+ arr->get(1, &obj1);
+ if (!obj1.isStream()) {
+ error(errSyntaxError, -1, "Bad ICCBased color space (stream)");
+ obj1.free();
+ return NULL;
+ }
+ dict = obj1.streamGetDict();
+ if (!dict->lookup("N", &obj2)->isInt()) {
+ error(errSyntaxError, -1, "Bad ICCBased color space (N)");
+ obj2.free();
+ obj1.free();
+ return NULL;
+ }
+ nCompsA = obj2.getInt();
+ obj2.free();
+- if (nCompsA > gfxColorMaxComps) {
+- error(-1, "ICCBased color space with too many (%d > %d) components",
+- nCompsA, gfxColorMaxComps);
+- nCompsA = gfxColorMaxComps;
++ if (nCompsA > 4) {
++ error(errSyntaxError, -1,
++ "ICCBased color space with too many ({0:d} > 4) components",
++ nCompsA);
++ nCompsA = 4;
+ }
+ if (dict->lookup("Alternate", &obj2)->isNull() ||
+@@ -986,8 +1025,9 @@
+ for (i = 0; i <= indexHighA; ++i) {
+ for (j = 0; j < n; ++j) {
+ if ((x = obj1.streamGetChar()) == EOF) {
+- error(-1, "Bad Indexed color space (lookup table stream too short)");
+- goto err3;
++ error(errSyntaxError, -1,
++ "Bad Indexed color space (lookup table stream too short)");
++ cs->indexHigh = indexHighA = i - 1;
+ }
+ cs->lookup[i*n + j] = (Guchar)x;
+ }
+@@ -995,8 +1035,9 @@
+ obj1.streamClose();
+ } else if (obj1.isString()) {
+ if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
+- error(-1, "Bad Indexed color space (lookup table string too short)");
+- goto err3;
++ error(errSyntaxError, -1,
++ "Bad Indexed color space (lookup table string too short)");
++ cs->indexHigh = indexHighA = obj1.getString()->getLength() / n - 1;
+ }
+ s = obj1.getString()->getCString();
+ for (i = 0; i <= indexHighA; ++i) {
+@@ -1254,14 +1354,7 @@
+ goto err4;
+ }
+ obj1.free();
+- cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
+- cs->nonMarking = gTrue;
+- for (i = 0; i < nCompsA; ++i) {
+- cs->names[i] = namesA[i];
+- if (namesA[i]->cmp("None")) {
+- cs->nonMarking = gFalse;
+- }
+- }
++ cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA);
+ return cs;
+
+ err4:
+@@ -3187,7 +3299,7 @@
+ GfxIndexedColorSpace *indexedCS;
+ GfxSeparationColorSpace *sepCS;
+ int maxPixel, indexHigh;
+- Guchar *lookup2;
++ Guchar *indexedLookup;
+ Function *sepFunc;
+ Object obj;
+ double x[gfxColorMaxComps];
+@@ -3204,6 +3316,7 @@
+ // initialize
+ for (k = 0; k < gfxColorMaxComps; ++k) {
+ lookup[k] = NULL;
++ lookup2[k] = NULL;
+ }
+
+ // get decode map
+@@ -3236,10 +3353,18 @@
+ // Construct a lookup table -- this stores pre-computed decoded
+ // values for each component, i.e., the result of applying the
+ // decode mapping to each possible image pixel component value.
+- //
++ for (k = 0; k < nComps; ++k) {
++ lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
++ sizeof(GfxColorComp));
++ for (i = 0; i <= maxPixel; ++i) {
++ lookup[k][i] = dblToCol(decodeLow[k] +
++ (i * decodeRange[k]) / maxPixel);
++ }
++ }
++
+ // Optimization: for Indexed and Separation color spaces (which have
+- // only one component), we store color values in the lookup table
+- // rather than component values.
++ // only one component), we pre-compute a second lookup table with
++ // color values
+ colorSpace2 = NULL;
+ nComps2 = 0;
+ if (colorSpace->getMode() == csIndexed) {
+@@ -3250,20 +3375,22 @@
+ colorSpace2 = indexedCS->getBase();
+ indexHigh = indexedCS->getIndexHigh();
+ nComps2 = colorSpace2->getNComps();
+- lookup2 = indexedCS->getLookup();
++ indexedLookup = indexedCS->getLookup();
+ colorSpace2->getDefaultRanges(x, y, indexHigh);
+ for (k = 0; k < nComps2; ++k) {
+- lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+- sizeof(GfxColorComp));
+- for (i = 0; i <= maxPixel; ++i) {
+- j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
+- if (j < 0) {
+- j = 0;
+- } else if (j > indexHigh) {
+- j = indexHigh;
+- }
+- lookup[k][i] =
+- dblToCol(x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]);
++ lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
++ sizeof(GfxColorComp));
++ }
++ for (i = 0; i <= maxPixel; ++i) {
++ j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
++ if (j < 0) {
++ j = 0;
++ } else if (j > indexHigh) {
++ j = indexHigh;
++ }
++ for (k = 0; k < nComps2; ++k) {
++ lookup2[k][i] =
++ dblToCol(x[k] + (indexedLookup[j*nComps2 + k] / 255.0) * y[k]);
+ }
+ }
+ } else if (colorSpace->getMode() == csSeparation) {
+@@ -3272,21 +3399,14 @@
+ nComps2 = colorSpace2->getNComps();
+ sepFunc = sepCS->getFunc();
+ for (k = 0; k < nComps2; ++k) {
+- lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+- sizeof(GfxColorComp));
+- for (i = 0; i <= maxPixel; ++i) {
+- x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
+- sepFunc->transform(x, y);
+- lookup[k][i] = dblToCol(y[k]);
+- }
++ lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
++ sizeof(GfxColorComp));
+ }
+- } else {
+- for (k = 0; k < nComps; ++k) {
+- lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+- sizeof(GfxColorComp));
+- for (i = 0; i <= maxPixel; ++i) {
+- lookup[k][i] = dblToCol(decodeLow[k] +
+- (i * decodeRange[k]) / maxPixel);
++ for (i = 0; i <= maxPixel; ++i) {
++ x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
++ sepFunc->transform(x, y);
++ for (k = 0; k < nComps2; ++k) {
++ lookup2[k][i] = dblToCol(y[k]);
+ }
+ }
+ }
+@@ -3309,24 +3429,24 @@
+ colorSpace2 = NULL;
+ for (k = 0; k < gfxColorMaxComps; ++k) {
+ lookup[k] = NULL;
++ lookup2[k] = NULL;
+ }
+ n = 1 << bits;
++ for (k = 0; k < nComps; ++k) {
++ lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
++ memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
++ }
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ for (k = 0; k < nComps2; ++k) {
+- lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+- memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
++ lookup2[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
++ memcpy(lookup2[k], colorMap->lookup2[k], n * sizeof(GfxColorComp));
+ }
+ } else if (colorSpace->getMode() == csSeparation) {
+ colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
+ for (k = 0; k < nComps2; ++k) {
+- lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+- memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+- }
+- } else {
+- for (k = 0; k < nComps; ++k) {
+- lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+- memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
++ lookup2[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
++ memcpy(lookup2[k], colorMap->lookup2[k], n * sizeof(GfxColorComp));
+ }
+ }
+ for (i = 0; i < nComps; ++i) {
+@@ -3342,6 +3462,7 @@
+ delete colorSpace;
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ gfree(lookup[i]);
++ gfree(lookup2[i]);
+ }
+ }
+
+@@ -3351,7 +3472,7 @@
+
+ if (colorSpace2) {
+ for (i = 0; i < nComps2; ++i) {
+- color.c[i] = lookup[i][x[0]];
++ color.c[i] = lookup2[i][x[0]];
+ }
+ colorSpace2->getGray(&color, gray);
+ } else {
+@@ -3368,7 +3489,7 @@
+
+ if (colorSpace2) {
+ for (i = 0; i < nComps2; ++i) {
+- color.c[i] = lookup[i][x[0]];
++ color.c[i] = lookup2[i][x[0]];
+ }
+ colorSpace2->getRGB(&color, rgb);
+ } else {
+@@ -3385,7 +3506,7 @@
+
+ if (colorSpace2) {
+ for (i = 0; i < nComps2; ++i) {
+- color.c[i] = lookup[i][x[0]];
++ color.c[i] = lookup2[i][x[0]];
+ }
+ colorSpace2->getCMYK(&color, cmyk);
+ } else {
+@@ -3405,6 +3527,88 @@
+ }
+ }
+
++void GfxImageColorMap::getGrayByteLine(Guchar *in, Guchar *out, int n) {
++ GfxColor color;
++ GfxGray gray;
++ int i, j;
++
++ if (colorSpace2) {
++ for (j = 0; j < n; ++j) {
++ for (i = 0; i < nComps2; ++i) {
++ color.c[i] = lookup2[i][in[j]];
++ }
++ colorSpace2->getGray(&color, &gray);
++ out[j] = colToByte(gray);
++ }
++ } else {
++ for (j = 0; j < n; ++j) {
++ for (i = 0; i < nComps; ++i) {
++ color.c[i] = lookup[i][in[j * nComps + i]];
++ }
++ colorSpace->getGray(&color, &gray);
++ out[j] = colToByte(gray);
++ }
++ }
++}
++
++void GfxImageColorMap::getRGBByteLine(Guchar *in, Guchar *out, int n) {
++ GfxColor color;
++ GfxRGB rgb;
++ int i, j;
++
++ if (colorSpace2) {
++ for (j = 0; j < n; ++j) {
++ for (i = 0; i < nComps2; ++i) {
++ color.c[i] = lookup2[i][in[j]];
++ }
++ colorSpace2->getRGB(&color, &rgb);
++ out[j*3] = colToByte(rgb.r);
++ out[j*3 + 1] = colToByte(rgb.g);
++ out[j*3 + 2] = colToByte(rgb.b);
++ }
++ } else {
++ for (j = 0; j < n; ++j) {
++ for (i = 0; i < nComps; ++i) {
++ color.c[i] = lookup[i][in[j * nComps + i]];
++ }
++ colorSpace->getRGB(&color, &rgb);
++ out[j*3] = colToByte(rgb.r);
++ out[j*3 + 1] = colToByte(rgb.g);
++ out[j*3 + 2] = colToByte(rgb.b);
++ }
++ }
++}
++
++void GfxImageColorMap::getCMYKByteLine(Guchar *in, Guchar *out, int n) {
++ GfxColor color;
++ GfxCMYK cmyk;
++ int i, j;
++
++ if (colorSpace2) {
++ for (j = 0; j < n; ++j) {
++ for (i = 0; i < nComps2; ++i) {
++ color.c[i] = lookup2[i][in[j]];
++ }
++ colorSpace2->getCMYK(&color, &cmyk);
++ out[j*4] = colToByte(cmyk.c);
++ out[j*4 + 1] = colToByte(cmyk.m);
++ out[j*4 + 2] = colToByte(cmyk.y);
++ out[j*4 + 3] = colToByte(cmyk.k);
++ }
++ } else {
++ for (j = 0; j < n; ++j) {
++ for (i = 0; i < nComps; ++i) {
++ color.c[i] = lookup[i][in[j * nComps + i]];
++ }
++ colorSpace->getCMYK(&color, &cmyk);
++ out[j*4] = colToByte(cmyk.c);
++ out[j*4 + 1] = colToByte(cmyk.m);
++ out[j*4 + 2] = colToByte(cmyk.y);
++ out[j*4 + 3] = colToByte(cmyk.k);
++ }
++ }
++}
++
+ //------------------------------------------------------------------------
+ // GfxSubpath and GfxPath
+ //------------------------------------------------------------------------
+@@ -3526,13 +3730,18 @@
+ }
+
+ void GfxPath::lineTo(double x, double y) {
+- if (justMoved) {
++ if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
+ if (n >= size) {
+ size *= 2;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+- subpaths[n] = new GfxSubpath(firstX, firstY);
++ if (justMoved) {
++ subpaths[n] = new GfxSubpath(firstX, firstY);
++ } else {
++ subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
++ subpaths[n-1]->getLastY());
++ }
+ ++n;
+ justMoved = gFalse;
+ }
+@@ -3541,13 +3750,18 @@
+
+ void GfxPath::curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3) {
+- if (justMoved) {
++ if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
+ if (n >= size) {
+ size *= 2;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+- subpaths[n] = new GfxSubpath(firstX, firstY);
++ if (justMoved) {
++ subpaths[n] = new GfxSubpath(firstX, firstY);
++ } else {
++ subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
++ subpaths[n-1]->getLastY());
++ }
+ ++n;
+ justMoved = gFalse;
+ }
+@@ -3658,6 +3872,7 @@
+ strokeOpacity = 1;
+ fillOverprint = gFalse;
+ strokeOverprint = gFalse;
++ overprintMode = 0;
+ transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL;
+
+ lineWidth = 1;
+@@ -3719,13 +3934,10 @@
+ // this gets set to NULL by restore()
+ delete path;
+ }
+- if (saved) {
+- delete saved;
+- }
+ }
+
+ // Used for copy();
+-GfxState::GfxState(GfxState *state) {
++GfxState::GfxState(GfxState *state, GBool copyPath) {
+ int i;
+
+ memcpy(this, state, sizeof(GfxState));
+@@ -3750,6 +3962,9 @@
+ lineDash = (double *)gmallocn(lineDashLength, sizeof(double));
+ memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
+ }
++ if (copyPath) {
++ path = state->path->copy();
++ }
+ saved = NULL;
+ }
+
+@@ -4056,6 +4271,60 @@
+ }
+ }
+
++void GfxState::clipToRect(double xMin, double yMin, double xMax, double yMax) {
++ double x, y, xMin1, yMin1, xMax1, yMax1;
++
++ transform(xMin, yMin, &x, &y);
++ xMin1 = xMax1 = x;
++ yMin1 = yMax1 = y;
++ transform(xMax, yMin, &x, &y);
++ if (x < xMin1) {
++ xMin1 = x;
++ } else if (x > xMax1) {
++ xMax1 = x;
++ }
++ if (y < yMin1) {
++ yMin1 = y;
++ } else if (y > yMax1) {
++ yMax1 = y;
++ }
++ transform(xMax, yMax, &x, &y);
++ if (x < xMin1) {
++ xMin1 = x;
++ } else if (x > xMax1) {
++ xMax1 = x;
++ }
++ if (y < yMin1) {
++ yMin1 = y;
++ } else if (y > yMax1) {
++ yMax1 = y;
++ }
++ transform(xMin, yMax, &x, &y);
++ if (x < xMin1) {
++ xMin1 = x;
++ } else if (x > xMax1) {
++ xMax1 = x;
++ }
++ if (y < yMin1) {
++ yMin1 = y;
++ } else if (y > yMax1) {
++ yMax1 = y;
++ }
++
++ if (xMin1 > clipXMin) {
++ clipXMin = xMin1;
++ }
++ if (yMin1 > clipYMin) {
++ clipYMin = yMin1;
++ }
++ if (xMax1 < clipXMax) {
++ clipXMax = xMax1;
++ }
++ if (yMax1 < clipYMax) {
++ clipYMax = yMax1;
++ }
++}
++
+ void GfxState::textShift(double tx, double ty) {
+ double dx, dy;
+
+diff -ru xpdf-3.02/xpdf/GfxState.h xpdf-3.03/xpdf/GfxState.h
+--- xpdf-3.02/xpdf/GfxState.h 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/GfxState.h 2011-08-15 23:08:53.000000000 +0200
+@@ -878,6 +894,11 @@
+ void getCMYK(Guchar *x, GfxCMYK *cmyk);
+ void getColor(Guchar *x, GfxColor *color);
+
++ // Convert a line of <n> pixels to 8-bit colors.
++ void getGrayByteLine(Guchar *in, Guchar *out, int n);
++ void getRGBByteLine(Guchar *in, Guchar *out, int n);
++ void getCMYKByteLine(Guchar *in, Guchar *out, int n);
++
+ private:
+
+ GfxImageColorMap(GfxImageColorMap *colorMap);
+@@ -889,6 +910,8 @@
+ int nComps2; // number of components in colorSpace2
+ GfxColorComp * // lookup table
+ lookup[gfxColorMaxComps];
++ GfxColorComp * // optimized case lookup table
++ lookup2[gfxColorMaxComps];
+ double // minimum values for each component
+ decodeLow[gfxColorMaxComps];
+ double // max - min value for each component
+@@ -1023,7 +1046,8 @@
+ ~GfxState();
+
+ // Copy.
+- GfxState *copy() { return new GfxState(this); }
++ GfxState *copy(GBool copyPath = gFalse)
++ { return new GfxState(this, copyPath); }
+
+ // Accessors.
+ double getHDPI() { return hDPI; }
+@@ -1059,6 +1083,7 @@
+ double getStrokeOpacity() { return strokeOpacity; }
+ GBool getFillOverprint() { return fillOverprint; }
+ GBool getStrokeOverprint() { return strokeOverprint; }
++ int getOverprintMode() { return overprintMode; }
+ Function **getTransfer() { return transfer; }
+ double getLineWidth() { return lineWidth; }
+ void getLineDash(double **dash, int *length, double *start)
+@@ -1127,6 +1152,7 @@
+ void setStrokeOpacity(double opac) { strokeOpacity = opac; }
+ void setFillOverprint(GBool op) { fillOverprint = op; }
+ void setStrokeOverprint(GBool op) { strokeOverprint = op; }
++ void setOverprintMode(int opm) { overprintMode = opm; }
+ void setTransfer(Function **funcs);
+ void setLineWidth(double width) { lineWidth = width; }
+ void setLineDash(double *dash, int length, double start);
+@@ -1169,6 +1195,7 @@
+ // Update clip region.
+ void clip();
+ void clipToStrokePath();
++ void clipToRect(double xMin, double yMin, double xMax, double yMax);
+
+ // Text position.
+ void textSetPos(double tx, double ty) { lineX = tx; lineY = ty; }
+@@ -1204,6 +1231,7 @@
+ double strokeOpacity; // stroke opacity
+ GBool fillOverprint; // fill overprint
+ GBool strokeOverprint; // stroke overprint
++ int overprintMode; // overprint mode ("OPM")
+ Function *transfer[4]; // transfer function (entries may be: all
+ // NULL = identity; last three NULL =
+ // single function; all four non-NULL =
+@@ -1238,7 +1266,7 @@
+
+ GfxState *saved; // next GfxState on stack
+
+- GfxState(GfxState *state);
++ GfxState(GfxState *state, GBool copyPath);
+ };
+
+ #endif
+diff -ru xpdf-3.02/xpdf/GlobalParams.cc xpdf-3.03/xpdf/GlobalParams.cc
+--- xpdf-3.02/xpdf/GlobalParams.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/GlobalParams.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -124,215 +124,138 @@
+ GlobalParams *globalParams = NULL;
+
+ //------------------------------------------------------------------------
+-// DisplayFontParam
++// PSFontParam16
+ //------------------------------------------------------------------------
+
+-DisplayFontParam::DisplayFontParam(GString *nameA,
+- DisplayFontParamKind kindA) {
++PSFontParam16::PSFontParam16(GString *nameA, int wModeA,
++ GString *psFontNameA, GString *encodingA) {
+ name = nameA;
+- kind = kindA;
+- switch (kind) {
+- case displayFontT1:
+- t1.fileName = NULL;
+- break;
+- case displayFontTT:
+- tt.fileName = NULL;
+- break;
+- }
++ wMode = wModeA;
++ psFontName = psFontNameA;
++ encoding = encodingA;
+ }
+
+-DisplayFontParam::~DisplayFontParam() {
++PSFontParam16::~PSFontParam16() {
+ delete name;
+- switch (kind) {
+- case displayFontT1:
+- if (t1.fileName) {
+- delete t1.fileName;
+- }
+- break;
+- case displayFontTT:
+- if (tt.fileName) {
+- delete tt.fileName;
+- }
+- break;
+- }
++ delete psFontName;
++ delete encoding;
+ }
+
+-#ifdef WIN32
+-
+ //------------------------------------------------------------------------
+-// WinFontInfo
++// SysFontInfo
+ //------------------------------------------------------------------------
+
+-class WinFontInfo: public DisplayFontParam {
++class SysFontInfo {
+ public:
+
+- GBool bold, italic;
++ GString *name;
++ GBool bold;
++ GBool italic;
++ GString *path;
++ SysFontType type;
++ int fontNum; // for TrueType collections
+
+- static WinFontInfo *make(GString *nameA, GBool boldA, GBool italicA,
+- HKEY regKey, char *winFontDir);
+- WinFontInfo(GString *nameA, GBool boldA, GBool italicA,
+- GString *fileNameA);
+- virtual ~WinFontInfo();
+- GBool equals(WinFontInfo *fi);
++ SysFontInfo(GString *nameA, GBool boldA, GBool italicA,
++ GString *pathA, SysFontType typeA, int fontNumA);
++ ~SysFontInfo();
++ GBool match(SysFontInfo *fi);
++ GBool match(GString *nameA, GBool boldA, GBool italicA);
+ };
+
+-WinFontInfo *WinFontInfo::make(GString *nameA, GBool boldA, GBool italicA,
+- HKEY regKey, char *winFontDir) {
+- GString *regName;
+- GString *fileNameA;
+- char buf[MAX_PATH];
+- DWORD n;
+- char c;
+- int i;
+-
+- //----- find the font file
+- fileNameA = NULL;
+- regName = nameA->copy();
+- if (boldA) {
+- regName->append(" Bold");
+- }
+- if (italicA) {
+- regName->append(" Italic");
+- }
+- regName->append(" (TrueType)");
+- n = sizeof(buf);
+- if (RegQueryValueEx(regKey, regName->getCString(), NULL, NULL,
+- (LPBYTE)buf, &n) == ERROR_SUCCESS) {
+- fileNameA = new GString(winFontDir);
+- fileNameA->append('\\')->append(buf);
+- }
+- delete regName;
+- if (!fileNameA) {
+- delete nameA;
+- return NULL;
+- }
+-
+- //----- normalize the font name
+- i = 0;
+- while (i < nameA->getLength()) {
+- c = nameA->getChar(i);
+- if (c == ' ' || c == ',' || c == '-') {
+- nameA->del(i);
+- } else {
+- ++i;
+- }
+- }
+-
+- return new WinFontInfo(nameA, boldA, italicA, fileNameA);
+-}
+-
+-WinFontInfo::WinFontInfo(GString *nameA, GBool boldA, GBool italicA,
+- GString *fileNameA):
+- DisplayFontParam(nameA, displayFontTT)
+-{
++SysFontInfo::SysFontInfo(GString *nameA, GBool boldA, GBool italicA,
++ GString *pathA, SysFontType typeA, int fontNumA) {
++ name = nameA;
+ bold = boldA;
+ italic = italicA;
+- tt.fileName = fileNameA;
++ path = pathA;
++ type = typeA;
++ fontNum = fontNumA;
++}
++
++SysFontInfo::~SysFontInfo() {
++ delete name;
++ delete path;
+ }
+
+-WinFontInfo::~WinFontInfo() {
++GBool SysFontInfo::match(SysFontInfo *fi) {
++ return !strcasecmp(name->getCString(), fi->name->getCString()) &&
++ bold == fi->bold && italic == fi->italic;
+ }
+
+-GBool WinFontInfo::equals(WinFontInfo *fi) {
+- return !name->cmp(fi->name) && bold == fi->bold && italic == fi->italic;
++GBool SysFontInfo::match(GString *nameA, GBool boldA, GBool italicA) {
++ return !strcasecmp(name->getCString(), nameA->getCString()) &&
++ bold == boldA && italic == italicA;
+ }
+
+ //------------------------------------------------------------------------
+-// WinFontList
++// SysFontList
+ //------------------------------------------------------------------------
+
+-class WinFontList {
++class SysFontList {
+ public:
+
+- WinFontList(char *winFontDirA);
+- ~WinFontList();
+- WinFontInfo *find(GString *font);
++ SysFontList();
++ ~SysFontList();
++ SysFontInfo *find(GString *name);
++
++#ifdef WIN32
++ void scanWindowsFonts(char *winFontDir);
++#endif
+
+ private:
+
+- void add(WinFontInfo *fi);
+- static int CALLBACK enumFunc1(CONST LOGFONT *font,
+- CONST TEXTMETRIC *metrics,
+- DWORD type, LPARAM data);
+- static int CALLBACK enumFunc2(CONST LOGFONT *font,
+- CONST TEXTMETRIC *metrics,
+- DWORD type, LPARAM data);
+-
+- GList *fonts; // [WinFontInfo]
+- HDC dc; // (only used during enumeration)
+- HKEY regKey; // (only used during enumeration)
+- char *winFontDir; // (only used during enumeration)
+-};
++#ifdef WIN32
++ SysFontInfo *makeWindowsFont(char *name, int fontNum,
++ char *path);
++#endif
+
+-WinFontList::WinFontList(char *winFontDirA) {
+- OSVERSIONINFO version;
+- char *path;
++ GList *fonts; // [SysFontInfo]
++};
+
++SysFontList::SysFontList() {
+ fonts = new GList();
+- dc = GetDC(NULL);
+- winFontDir = winFontDirA;
+- version.dwOSVersionInfoSize = sizeof(version);
+- GetVersionEx(&version);
+- if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+- path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
+- } else {
+- path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
+- }
+- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0,
+- KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+- &regKey) == ERROR_SUCCESS) {
+- EnumFonts(dc, NULL, &WinFontList::enumFunc1, (LPARAM)this);
+- RegCloseKey(regKey);
+- }
+- ReleaseDC(NULL, dc);
+ }
+
+-WinFontList::~WinFontList() {
+- deleteGList(fonts, WinFontInfo);
++SysFontList::~SysFontList() {
++ deleteGList(fonts, SysFontInfo);
+ }
+
+-void WinFontList::add(WinFontInfo *fi) {
+- int i;
+-
+- for (i = 0; i < fonts->getLength(); ++i) {
+- if (((WinFontInfo *)fonts->get(i))->equals(fi)) {
+- delete fi;
+- return;
+- }
+- }
+- fonts->append(fi);
+-}
+-
+-WinFontInfo *WinFontList::find(GString *font) {
+- GString *name;
++SysFontInfo *SysFontList::find(GString *name) {
++ GString *name2;
+ GBool bold, italic;
+- WinFontInfo *fi;
++ SysFontInfo *fi;
+ char c;
+ int n, i;
+
+- name = font->copy();
++ name2 = name->copy();
+
+ // remove space, comma, dash chars
+ i = 0;
+- while (i < name->getLength()) {
+- c = name->getChar(i);
++ while (i < name2->getLength()) {
++ c = name2->getChar(i);
+ if (c == ' ' || c == ',' || c == '-') {
+- name->del(i);
++ name2->del(i);
+ } else {
+ ++i;
+ }
+ }
+- n = name->getLength();
++ n = name2->getLength();
+
+ // remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.)
+- if (!strcmp(name->getCString() + n - 2, "MT")) {
+- name->del(n - 2, 2);
++ if (n > 2 && !strcmp(name2->getCString() + n - 2, "MT")) {
++ name2->del(n - 2, 2);
+ n -= 2;
+ }
+
++ // look for "Regular"
++ if (n > 7 && !strcmp(name2->getCString() + n - 7, "Regular")) {
++ name2->del(n - 7, 7);
++ n -= 7;
++ }
++
+ // look for "Italic"
+- if (!strcmp(name->getCString() + n - 6, "Italic")) {
+- name->del(n - 6, 6);
++ if (n > 6 && !strcmp(name2->getCString() + n - 6, "Italic")) {
++ name2->del(n - 6, 6);
+ italic = gTrue;
+ n -= 6;
+ } else {
+@@ -340,8 +263,8 @@
+ }
+
+ // look for "Bold"
+- if (!strcmp(name->getCString() + n - 4, "Bold")) {
+- name->del(n - 4, 4);
++ if (n > 4 && !strcmp(name2->getCString() + n - 4, "Bold")) {
++ name2->del(n - 4, 4);
+ bold = gTrue;
+ n -= 4;
+ } else {
+@@ -349,84 +272,183 @@
+ }
+
+ // remove trailing "MT" (FooMT-Bold, etc.)
+- if (!strcmp(name->getCString() + n - 2, "MT")) {
+- name->del(n - 2, 2);
++ if (n > 2 && !strcmp(name2->getCString() + n - 2, "MT")) {
++ name2->del(n - 2, 2);
+ n -= 2;
+ }
+
+ // remove trailing "PS"
+- if (!strcmp(name->getCString() + n - 2, "PS")) {
+- name->del(n - 2, 2);
++ if (n > 2 && !strcmp(name2->getCString() + n - 2, "PS")) {
++ name2->del(n - 2, 2);
+ n -= 2;
+ }
+
++ // remove trailing "IdentityH"
++ if (n > 9 && !strcmp(name2->getCString() + n - 9, "IdentityH")) {
++ name2->del(n - 9, 9);
++ n -= 9;
++ }
++
+ // search for the font
+ fi = NULL;
+ for (i = 0; i < fonts->getLength(); ++i) {
+- fi = (WinFontInfo *)fonts->get(i);
+- if (!fi->name->cmp(name) && fi->bold == bold && fi->italic == italic) {
++ fi = (SysFontInfo *)fonts->get(i);
++ if (fi->match(name2, bold, italic)) {
+ break;
+ }
+ fi = NULL;
+ }
++ if (!fi && bold) {
++ // try ignoring the bold flag
++ for (i = 0; i < fonts->getLength(); ++i) {
++ fi = (SysFontInfo *)fonts->get(i);
++ if (fi->match(name2, gFalse, italic)) {
++ break;
++ }
++ fi = NULL;
++ }
++ }
++ if (!fi && (bold || italic)) {
++ // try ignoring the bold and italic flags
++ for (i = 0; i < fonts->getLength(); ++i) {
++ fi = (SysFontInfo *)fonts->get(i);
++ if (fi->match(name2, gFalse, gFalse)) {
++ break;
++ }
++ fi = NULL;
++ }
++ }
+
+- delete name;
++ delete name2;
+ return fi;
+ }
+
+-int CALLBACK WinFontList::enumFunc1(CONST LOGFONT *font,
+- CONST TEXTMETRIC *metrics,
+- DWORD type, LPARAM data) {
+- WinFontList *fl = (WinFontList *)data;
+-
+- EnumFonts(fl->dc, font->lfFaceName, &WinFontList::enumFunc2, (LPARAM)fl);
+- return 1;
+-}
+-
+-int CALLBACK WinFontList::enumFunc2(CONST LOGFONT *font,
+- CONST TEXTMETRIC *metrics,
+- DWORD type, LPARAM data) {
+- WinFontList *fl = (WinFontList *)data;
+- WinFontInfo *fi;
+-
+- if (type & TRUETYPE_FONTTYPE) {
+- if ((fi = WinFontInfo::make(new GString(font->lfFaceName),
+- font->lfWeight >= 600,
+- font->lfItalic ? gTrue : gFalse,
+- fl->regKey, fl->winFontDir))) {
+- fl->add(fi);
++#ifdef WIN32
++void SysFontList::scanWindowsFonts(char *winFontDir) {
++ OSVERSIONINFO version;
++ char *path;
++ DWORD idx, valNameLen, dataLen, type;
++ HKEY regKey;
++ char valName[1024], data[1024];
++ int n, fontNum;
++ char *p0, *p1;
++ GString *fontPath;
++
++ version.dwOSVersionInfoSize = sizeof(version);
++ GetVersionEx(&version);
++ if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
++ path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
++ } else {
++ path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
++ }
++ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0,
++ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
++ &regKey) == ERROR_SUCCESS) {
++ idx = 0;
++ while (1) {
++ valNameLen = sizeof(valName) - 1;
++ dataLen = sizeof(data) - 1;
++ if (RegEnumValue(regKey, idx, valName, &valNameLen, NULL,
++ &type, (LPBYTE)data, &dataLen) != ERROR_SUCCESS) {
++ break;
++ }
++ if (type == REG_SZ &&
++ valNameLen > 0 && valNameLen < sizeof(valName) &&
++ dataLen > 0 && dataLen < sizeof(data)) {
++ valName[valNameLen] = '\0';
++ data[dataLen] = '\0';
++ n = strlen(data);
++ if (!strcasecmp(data + n - 4, ".ttf") ||
++ !strcasecmp(data + n - 4, ".ttc")) {
++ fontPath = new GString(data);
++ if (!(dataLen >= 3 && data[1] == ':' && data[2] == '\\')) {
++ fontPath->insert(0, '\\');
++ fontPath->insert(0, winFontDir);
++ }
++ p0 = valName;
++ fontNum = 0;
++ while (*p0) {
++ p1 = strstr(p0, " & ");
++ if (p1) {
++ *p1 = '\0';
++ p1 = p1 + 3;
++ } else {
++ p1 = p0 + strlen(p0);
++ }
++ fonts->append(makeWindowsFont(p0, fontNum,
++ fontPath->getCString()));
++ p0 = p1;
++ ++fontNum;
++ }
++ delete fontPath;
++ }
++ }
++ ++idx;
+ }
++ RegCloseKey(regKey);
+ }
+- return 1;
+ }
+
+-#endif // WIN32
++SysFontInfo *SysFontList::makeWindowsFont(char *name, int fontNum,
++ char *path) {
++ int n;
++ GBool bold, italic;
++ GString *s;
++ char c;
++ int i;
++ SysFontType type;
+
+-//------------------------------------------------------------------------
+-// PSFontParam
+-//------------------------------------------------------------------------
++ n = strlen(name);
++ bold = italic = gFalse;
+
+-PSFontParam::PSFontParam(GString *pdfFontNameA, int wModeA,
+- GString *psFontNameA, GString *encodingA) {
+- pdfFontName = pdfFontNameA;
+- wMode = wModeA;
+- psFontName = psFontNameA;
+- encoding = encodingA;
+-}
++ // remove trailing ' (TrueType)'
++ if (n > 11 && !strncmp(name + n - 11, " (TrueType)", 11)) {
++ n -= 11;
++ }
+
+-PSFontParam::~PSFontParam() {
+- delete pdfFontName;
+- delete psFontName;
+- if (encoding) {
+- delete encoding;
++ // remove trailing ' Italic'
++ if (n > 7 && !strncmp(name + n - 7, " Italic", 7)) {
++ n -= 7;
++ italic = gTrue;
++ }
++
++ // remove trailing ' Bold'
++ if (n > 5 && !strncmp(name + n - 5, " Bold", 5)) {
++ n -= 5;
++ bold = gTrue;
+ }
++
++ // remove trailing ' Regular'
++ if (n > 5 && !strncmp(name + n - 8, " Regular", 8)) {
++ n -= 8;
++ }
++
++ //----- normalize the font name
++ s = new GString(name, n);
++ i = 0;
++ while (i < s->getLength()) {
++ c = s->getChar(i);
++ if (c == ' ' || c == ',' || c == '-') {
++ s->del(i);
++ } else {
++ ++i;
++ }
++ }
++
++ if (!strcasecmp(path + strlen(path) - 4, ".ttc")) {
++ type = sysFontTTC;
++ } else {
++ type = sysFontTTF;
++ }
++ return new SysFontInfo(s, bold, italic, new GString(path), type, fontNum);
+ }
++#endif
+
+ //------------------------------------------------------------------------
+ // KeyBinding
+ //------------------------------------------------------------------------
+
+-KeyBinding::KeyBinding(int codeA, int modsA, int contextA, char *cmd0) {
++KeyBinding::KeyBinding(int codeA, int modsA, int contextA, const char *cmd0) {
+ code = codeA;
+ mods = modsA;
+ context = contextA;
+@@ -637,9 +657,10 @@
+ unicodeMaps = new GHash(gTrue);
+ cMapDirs = new GHash(gTrue);
+ toUnicodeDirs = new GList();
+- displayFonts = new GHash();
+- displayCIDFonts = new GHash();
+- displayNamedCIDFonts = new GHash();
++ fontFiles = new GHash(gTrue);
++ fontDirs = new GList();
++ ccFontFiles = new GHash(gTrue);
++ sysFonts = new SysFontList();
+ #if HAVE_PAPER_H
+ char *paperName;
+ const struct paper *paperType;
+@@ -668,16 +689,21 @@
+ psDuplex = gFalse;
+ psLevel = psLevel2;
+ psFile = NULL;
+- psFonts = new GHash();
+- psNamedFonts16 = new GList();
+- psFonts16 = new GList();
++ psResidentFonts = new GHash(gTrue);
++ psResidentFonts16 = new GList();
++ psResidentFontsCC = new GList();
+ psEmbedType1 = gTrue;
+ psEmbedTrueType = gTrue;
+ psEmbedCIDPostScript = gTrue;
+ psEmbedCIDTrueType = gTrue;
++ psFontPassthrough = gFalse;
+ psPreload = gFalse;
+ psOPI = gFalse;
+ psASCIIHex = gFalse;
++ psUncompressPreloadedImages = gFalse;
++ psRasterResolution = 300;
++ psRasterMono = gFalse;
++ psAlwaysRasterize = gFalse;
+ textEncoding = new GString("Latin1");
+ #if defined(WIN32)
+ textEOL = eolDOS;
+@@ -688,13 +714,14 @@
+ #endif
+ textPageBreaks = gTrue;
+ textKeepTinyChars = gFalse;
+- fontDirs = new GList();
+ initialZoom = new GString("125");
+ continuousView = gFalse;
+ enableT1lib = gTrue;
+ enableFreeType = gTrue;
++ disableFreeTypeHinting = gFalse;
+ antialias = gTrue;
+ vectorAntialias = gTrue;
++ antialiasPrinting = gFalse;
+ strokeAdjust = gTrue;
+ screenType = screenUnset;
+ screenSize = -1;
+@@ -702,6 +729,10 @@
+ screenGamma = 1.0;
+ screenBlackThreshold = 0.0;
+ screenWhiteThreshold = 1.0;
++ minLineWidth = 0.0;
++ overprintPreview = gFalse;
+ urlCommand = NULL;
+ movieCommand = NULL;
+ mapNumericCharNames = gTrue;
+@@ -716,10 +747,6 @@
+ unicodeMapCache = new UnicodeMapCache();
+ cMapCache = new CMapCache();
+
+-#ifdef WIN32
+- winFontList = NULL;
+-#endif
+-
+ #ifdef ENABLE_PLUGINS
+ plugins = new GList();
+ securityHandlers = new GList();
+@@ -764,7 +791,7 @@
+ }
+ }
+ if (!f) {
+-#if defined(WIN32) && !defined(__CYGWIN32__)
++#ifdef WIN32
+ char buf[512];
+ i = GetModuleFileName(NULL, buf, sizeof(buf));
+ if (i <= 0 || i >= sizeof(buf)) {
+@@ -1762,23 +1833,21 @@
+ deleteGHash(residentUnicodeMaps, UnicodeMap);
+ deleteGHash(unicodeMaps, GString);
+ deleteGList(toUnicodeDirs, GString);
+- deleteGHash(displayFonts, DisplayFontParam);
+- deleteGHash(displayCIDFonts, DisplayFontParam);
+- deleteGHash(displayNamedCIDFonts, DisplayFontParam);
+-#ifdef WIN32
+- if (winFontList) {
+- delete winFontList;
+- }
+-#endif
++ deleteGHash(fontFiles, GString);
++ deleteGList(fontDirs, GString);
++ deleteGHash(ccFontFiles, GString);
++ delete sysFonts;
+ if (psFile) {
+ delete psFile;
+ }
+- deleteGHash(psFonts, PSFontParam);
+- deleteGList(psNamedFonts16, PSFontParam);
+- deleteGList(psFonts16, PSFontParam);
++ deleteGHash(psResidentFonts, GString);
++ deleteGList(psResidentFonts16, PSFontParam16);
++ deleteGList(psResidentFontsCC, PSFontParam16);
+ delete textEncoding;
+- deleteGList(fontDirs, GString);
+ delete initialZoom;
+@@ -1829,8 +1898,6 @@
+ char winFontDir[MAX_PATH];
+ #endif
+ FILE *f;
+- DisplayFontParamKind kind;
+- DisplayFontParam *dfp;
+ int i, j;
+
+ #ifdef WIN32
+@@ -1850,16 +1917,13 @@
+ }
+ #endif
+ for (i = 0; displayFontTab[i].name; ++i) {
+- fontName = new GString(displayFontTab[i].name);
+- if (getDisplayFont(fontName)) {
+- delete fontName;
++ if (fontFiles->lookup(displayFontTab[i].name)) {
+ continue;
+ }
++ fontName = new GString(displayFontTab[i].name);
+ fileName = NULL;
+- kind = displayFontT1; // make gcc happy
+ if (dir) {
+ fileName = appendToPath(new GString(dir), displayFontTab[i].t1FileName);
+- kind = displayFontT1;
+ if ((f = fopen(fileName->getCString(), "rb"))) {
+ fclose(f);
+ } else {
+@@ -1871,7 +1935,6 @@
+ if (!fileName && winFontDir[0] && displayFontTab[i].ttFileName) {
+ fileName = appendToPath(new GString(winFontDir),
+ displayFontTab[i].ttFileName);
+- kind = displayFontTT;
+ if ((f = fopen(fileName->getCString(), "rb"))) {
+ fclose(f);
+ } else {
+@@ -1886,7 +1949,6 @@
+ for (j = 0; !fileName && displayFontDirs[j]; ++j) {
+ fileName = appendToPath(new GString(displayFontDirs[j]),
+ displayFontTab[i].ttFileName);
+- kind = displayFontTT;
+ if ((f = fopen(fileName->getCString(), "rb"))) {
+ fclose(f);
+ } else {
+@@ -1895,11 +1957,10 @@
+ }
+ }
+ }
+-#else
++#else // WIN32
+ for (j = 0; !fileName && displayFontDirs[j]; ++j) {
+ fileName = appendToPath(new GString(displayFontDirs[j]),
+ displayFontTab[i].t1FileName);
+- kind = displayFontT1;
+ if ((f = fopen(fileName->getCString(), "rb"))) {
+ fclose(f);
+ } else {
+@@ -1907,20 +1968,19 @@
+ fileName = NULL;
+ }
+ }
+-#endif
++#endif // WIN32
+ if (!fileName) {
+- error(-1, "No display font for '%s'", displayFontTab[i].name);
++ error(errConfig, -1, "No display font for '{0:s}'",
++ displayFontTab[i].name);
+ delete fontName;
+ continue;
+ }
+- dfp = new DisplayFontParam(fontName, kind);
+- dfp->t1.fileName = fileName;
+- globalParams->addDisplayFont(dfp);
++ addFontFile(fontName, fileName);
+ }
+
+ #ifdef WIN32
+ if (winFontDir[0]) {
+- winFontList = new WinFontList(winFontDir);
++ sysFonts->scanWindowsFonts(winFontDir);
+ }
+ #endif
+ }
+@@ -2020,31 +2080,72 @@
+ return NULL;
+ }
+
+-DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) {
+- DisplayFontParam *dfp;
++GString *GlobalParams::findFontFile(GString *fontName) {
++ static const char *exts[] = { ".pfa", ".pfb", ".ttf", ".ttc" };
++ GString *path, *dir;
++#ifdef WIN32
++ GString *fontNameU;
++#endif
++ const char *ext;
++ FILE *f;
++ int i, j;
+
+ lockGlobalParams;
+- dfp = (DisplayFontParam *)displayFonts->lookup(fontName);
+-#ifdef WIN32
+- if (!dfp && winFontList) {
+- dfp = winFontList->find(fontName);
++ if ((path = (GString *)fontFiles->lookup(fontName))) {
++ path = path->copy();
++ unlockGlobalParams;
++ return path;
+ }
++ for (i = 0; i < fontDirs->getLength(); ++i) {
++ dir = (GString *)fontDirs->get(i);
++ for (j = 0; j < (int)(sizeof(exts) / sizeof(exts[0])); ++j) {
++ ext = exts[j];
++#ifdef WIN32
++ fontNameU = fileNameToUTF8(fontName->getCString());
++ path = appendToPath(dir->copy(), fontNameU->getCString());
++ delete fontNameU;
++#else
++ path = appendToPath(dir->copy(), fontName->getCString());
+ #endif
++ path->append(ext);
++ if ((f = openFile(path->getCString(), "rb"))) {
++ fclose(f);
++ unlockGlobalParams;
++ return path;
++ }
++ delete path;
++ }
++ }
++ unlockGlobalParams;
++ return NULL;
++}
++
++GString *GlobalParams::findSystemFontFile(GString *fontName,
++ SysFontType *type,
++ int *fontNum) {
++ SysFontInfo *fi;
++ GString *path;
++
++ path = NULL;
++ lockGlobalParams;
++ if ((fi = sysFonts->find(fontName))) {
++ path = fi->path->copy();
++ *type = fi->type;
++ *fontNum = fi->fontNum;
++ }
+ unlockGlobalParams;
+- return dfp;
++ return path;
+ }
+
+-DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *fontName,
+- GString *collection) {
+- DisplayFontParam *dfp;
++GString *GlobalParams::findCCFontFile(GString *collection) {
++ GString *path;
+
+ lockGlobalParams;
+- if (!fontName ||
+- !(dfp = (DisplayFontParam *)displayNamedCIDFonts->lookup(fontName))) {
+- dfp = (DisplayFontParam *)displayCIDFonts->lookup(collection);
++ if ((path = (GString *)ccFontFiles->lookup(collection))) {
++ path = path->copy();
+ }
+ unlockGlobalParams;
+- return dfp;
++ return path;
+ }
+
+ GString *GlobalParams::getPSFile() {
+@@ -2137,41 +2238,62 @@
+ return level;
+ }
+
+-PSFontParam *GlobalParams::getPSFont(GString *fontName) {
+- PSFontParam *p;
++GString *GlobalParams::getPSResidentFont(GString *fontName) {
++ GString *psName;
+
+ lockGlobalParams;
+- p = (PSFontParam *)psFonts->lookup(fontName);
++ psName = (GString *)psResidentFonts->lookup(fontName);
+ unlockGlobalParams;
+- return p;
++ return psName;
+ }
+
+-PSFontParam *GlobalParams::getPSFont16(GString *fontName,
+- GString *collection, int wMode) {
+- PSFontParam *p;
++GList *GlobalParams::getPSResidentFonts() {
++ GList *names;
++ GHashIter *iter;
++ GString *name;
++ GString *psName;
++
++ names = new GList();
++ lockGlobalParams;
++ psResidentFonts->startIter(&iter);
++ while (psResidentFonts->getNext(&iter, &name, (void **)&psName)) {
++ names->append(psName->copy());
++ }
++ unlockGlobalParams;
++ return names;
++}
++
++PSFontParam16 *GlobalParams::getPSResidentFont16(GString *fontName,
++ int wMode) {
++ PSFontParam16 *p;
+ int i;
+
+ lockGlobalParams;
+ p = NULL;
+- if (fontName) {
+- for (i = 0; i < psNamedFonts16->getLength(); ++i) {
+- p = (PSFontParam *)psNamedFonts16->get(i);
+- if (!p->pdfFontName->cmp(fontName) &&
+- p->wMode == wMode) {
+- break;
+- }
+- p = NULL;
++ for (i = 0; i < psResidentFonts16->getLength(); ++i) {
++ p = (PSFontParam16 *)psResidentFonts16->get(i);
++ if (!(p->name->cmp(fontName)) && p->wMode == wMode) {
++ break;
+ }
++ p = NULL;
+ }
+- if (!p && collection) {
+- for (i = 0; i < psFonts16->getLength(); ++i) {
+- p = (PSFontParam *)psFonts16->get(i);
+- if (!p->pdfFontName->cmp(collection) &&
+- p->wMode == wMode) {
+- break;
+- }
+- p = NULL;
++ unlockGlobalParams;
++ return p;
++}
++
++PSFontParam16 *GlobalParams::getPSResidentFontCC(GString *collection,
++ int wMode) {
++ PSFontParam16 *p;
++ int i;
++
++ lockGlobalParams;
++ p = NULL;
++ for (i = 0; i < psResidentFontsCC->getLength(); ++i) {
++ p = (PSFontParam16 *)psResidentFontsCC->get(i);
++ if (!(p->name->cmp(collection)) && p->wMode == wMode) {
++ break;
+ }
++ p = NULL;
+ }
+ unlockGlobalParams;
+ return p;
+@@ -2213,6 +2335,15 @@
+ return e;
+ }
+
++GBool GlobalParams::getPSFontPassthrough() {
++ GBool e;
++
++ lockGlobalParams;
++ e = psFontPassthrough;
++ unlockGlobalParams;
++ return e;
++}
++
+ GBool GlobalParams::getPSPreload() {
+ GBool preload;
+
+@@ -2240,6 +2371,42 @@
+ return ah;
+ }
+
++GBool GlobalParams::getPSUncompressPreloadedImages() {
++ GBool ah;
++
++ lockGlobalParams;
++ ah = psUncompressPreloadedImages;
++ unlockGlobalParams;
++ return ah;
++}
++
++double GlobalParams::getPSRasterResolution() {
++ double res;
++
++ lockGlobalParams;
++ res = psRasterResolution;
++ unlockGlobalParams;
++ return res;
++}
++
++GBool GlobalParams::getPSRasterMono() {
++ GBool mono;
++
++ lockGlobalParams;
++ mono = psRasterMono;
++ unlockGlobalParams;
++ return mono;
++}
++
++GBool GlobalParams::getPSAlwaysRasterize() {
++ GBool rast;
++
++ lockGlobalParams;
++ rast = psAlwaysRasterize;
++ unlockGlobalParams;
++ return rast;
++}
++
+ GString *GlobalParams::getTextEncodingName() {
+ GString *s;
+
+@@ -2276,30 +2443,6 @@
+ return tiny;
+ }
+
+-GString *GlobalParams::findFontFile(GString *fontName, char **exts) {
+- GString *dir, *fileName;
+- char **ext;
+- FILE *f;
+- int i;
+-
+- lockGlobalParams;
+- for (i = 0; i < fontDirs->getLength(); ++i) {
+- dir = (GString *)fontDirs->get(i);
+- for (ext = exts; *ext; ++ext) {
+- fileName = appendToPath(dir->copy(), fontName->getCString());
+- fileName->append(*ext);
+- if ((f = fopen(fileName->getCString(), "rb"))) {
+- fclose(f);
+- unlockGlobalParams;
+- return fileName;
+- }
+- delete fileName;
+- }
+- }
+- unlockGlobalParams;
+- return NULL;
+-}
+-
+ GString *GlobalParams::getInitialZoom() {
+ GString *s;
+
+@@ -2355,6 +2507,15 @@
+ return f;
+ }
+
++GBool GlobalParams::getAntialiasPrinting() {
++ GBool f;
++
++ lockGlobalParams;
++ f = antialiasPrinting;
++ unlockGlobalParams;
++ return f;
++}
++
+ GBool GlobalParams::getStrokeAdjust() {
+ GBool f;
+
+@@ -2418,6 +2579,24 @@
+ return thresh;
+ }
+
++double GlobalParams::getMinLineWidth() {
++ double w;
++
++ lockGlobalParams;
++ w = minLineWidth;
++ unlockGlobalParams;
++ return w;
++}
++
+ GBool GlobalParams::getMapNumericCharNames() {
+ GBool map;
+
+@@ -2552,14 +2731,9 @@
+ // functions to set parameters
+ //------------------------------------------------------------------------
+
+-void GlobalParams::addDisplayFont(DisplayFontParam *param) {
+- DisplayFontParam *old;
+-
++void GlobalParams::addFontFile(GString *fontName, GString *path) {
+ lockGlobalParams;
+- if ((old = (DisplayFontParam *)displayFonts->remove(param->name))) {
+- delete old;
+- }
+- displayFonts->add(param->name, param);
++ fontFiles->add(fontName, path);
+ unlockGlobalParams;
+ }
+
+@@ -2684,6 +2858,12 @@
+ unlockGlobalParams;
+ }
+
++void GlobalParams::setPSFontPassthrough(GBool passthrough) {
++ lockGlobalParams;
++ psFontPassthrough = passthrough;
++ unlockGlobalParams;
++}
++
+ void GlobalParams::setPSPreload(GBool preload) {
+ lockGlobalParams;
+ psPreload = preload;
+diff -ru xpdf-3.02/xpdf/GlobalParams.h xpdf-3.03/xpdf/GlobalParams.h
+--- xpdf-3.02/xpdf/GlobalParams.h 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/GlobalParams.h 2011-08-15 23:08:53.000000000 +0200
+@@ -35,9 +35,7 @@
+ class CMapCache;
+ struct XpdfSecurityHandler;
+ class GlobalParams;
+-#ifdef WIN32
+-class WinFontList;
+-#endif
++class SysFontList;
+
+ //------------------------------------------------------------------------
+
+@@ -46,51 +44,27 @@
+
+ //------------------------------------------------------------------------
+
+-enum DisplayFontParamKind {
+- displayFontT1,
+- displayFontTT
+-};
+-
+-struct DisplayFontParamT1 {
+- GString *fileName;
+-};
+-
+-struct DisplayFontParamTT {
+- GString *fileName;
+-};
+-
+-class DisplayFontParam {
+-public:
+-
+- GString *name; // font name for 8-bit fonts and named
+- // CID fonts; collection name for
+- // generic CID fonts
+- DisplayFontParamKind kind;
+- union {
+- DisplayFontParamT1 t1;
+- DisplayFontParamTT tt;
+- };
+-
+- DisplayFontParam(GString *nameA, DisplayFontParamKind kindA);
+- virtual ~DisplayFontParam();
++enum SysFontType {
++ sysFontPFA,
++ sysFontPFB,
++ sysFontTTF,
++ sysFontTTC
+ };
+
+ //------------------------------------------------------------------------
+
+-class PSFontParam {
++class PSFontParam16 {
+ public:
+
+- GString *pdfFontName; // PDF font name for 8-bit fonts and
+- // named 16-bit fonts; char collection
+- // name for generic 16-bit fonts
+- int wMode; // writing mode (0=horiz, 1=vert) for
+- // 16-bit fonts
++ GString *name; // PDF font name for psResidentFont16;
++ // char collection name for psResidentFontCC
++ int wMode; // writing mode (0=horiz, 1=vert)
+ GString *psFontName; // PostScript font name
+- GString *encoding; // encoding, for 16-bit fonts only
++ GString *encoding; // encoding
+
+- PSFontParam(GString *pdfFontNameA, int wModeA,
+- GString *psFontNameA, GString *encodingA);
+- ~PSFontParam();
++ PSFontParam16(GString *nameA, int wModeA,
++ GString *psFontNameA, GString *encodingA);
++ ~PSFontParam16();
+ };
+
+ //------------------------------------------------------------------------
+@@ -212,9 +191,11 @@
+ UnicodeMap *getResidentUnicodeMap(GString *encodingName);
+ FILE *getUnicodeMapFile(GString *encodingName);
+ FILE *findCMapFile(GString *collection, GString *cMapName);
+ FILE *findToUnicodeFile(GString *name);
+- DisplayFontParam *getDisplayFont(GString *fontName);
+- DisplayFontParam *getDisplayCIDFont(GString *fontName, GString *collection);
++ GString *findFontFile(GString *fontName);
++ GString *findSystemFontFile(GString *fontName, SysFontType *type,
++ int *fontNum);
++ GString *findCCFontFile(GString *collection);
+ GString *getPSFile();
+ int getPSPaperWidth();
+ int getPSPaperHeight();
+@@ -225,26 +206,34 @@
+ GBool getPSShrinkLarger();
+ GBool getPSCenter();
+ PSLevel getPSLevel();
+- PSFontParam *getPSFont(GString *fontName);
+- PSFontParam *getPSFont16(GString *fontName, GString *collection, int wMode);
++ GString *getPSResidentFont(GString *fontName);
++ GList *getPSResidentFonts();
++ PSFontParam16 *getPSResidentFont16(GString *fontName, int wMode);
++ PSFontParam16 *getPSResidentFontCC(GString *collection, int wMode);
+ GBool getPSEmbedType1();
+ GBool getPSEmbedTrueType();
+ GBool getPSEmbedCIDPostScript();
+ GBool getPSEmbedCIDTrueType();
++ GBool getPSFontPassthrough();
+ GBool getPSPreload();
+ GBool getPSOPI();
+ GBool getPSASCIIHex();
++ GBool getPSUncompressPreloadedImages();
++ double getPSRasterResolution();
++ GBool getPSRasterMono();
++ GBool getPSAlwaysRasterize();
+ GString *getTextEncodingName();
+ EndOfLineKind getTextEOL();
+ GBool getTextPageBreaks();
+ GBool getTextKeepTinyChars();
+- GString *findFontFile(GString *fontName, char **exts);
+ GString *getInitialZoom();
+ GBool getContinuousView();
+ GBool getEnableT1lib();
+ GBool getEnableFreeType();
+ GBool getAntialias();
+ GBool getVectorAntialias();
++ GBool getAntialiasPrinting();
+ GBool getStrokeAdjust();
+ ScreenType getScreenType();
+ int getScreenSize();
+@@ -252,6 +241,10 @@
+ double getScreenGamma();
+ double getScreenBlackThreshold();
+ double getScreenWhiteThreshold();
++ double getMinLineWidth();
++ GBool getDrawAnnotations();
++ GBool getOverprintPreview() { return overprintPreview; }
+ GString *getURLCommand() { return urlCommand; }
+ GString *getMovieCommand() { return movieCommand; }
+ GBool getMapNumericCharNames();
+@@ -268,7 +261,7 @@
+
+ //----- functions to set parameters
+
+- void addDisplayFont(DisplayFontParam *param);
++ void addFontFile(GString *fontName, GString *path);
+ void setPSFile(char *file);
+ GBool setPSPaperSize(char *size);
+ void setPSPaperWidth(int width);
+@@ -284,6 +277,7 @@
+ void setPSEmbedTrueType(GBool embed);
+ void setPSEmbedCIDPostScript(GBool embed);
+ void setPSEmbedCIDTrueType(GBool embed);
++ void setPSFontPassthrough(GBool passthrough);
+ void setPSPreload(GBool preload);
+ void setPSOPI(GBool opi);
+ void setPSASCIIHex(GBool hex);
+@@ -380,15 +374,12 @@
+ GHash *cMapDirs; // list of CMap dirs, indexed by collection
+ // name [GList[GString]]
+ GList *toUnicodeDirs; // list of ToUnicode CMap dirs [GString]
+- GHash *displayFonts; // display font info, indexed by font name
+- // [DisplayFontParam]
+-#ifdef WIN32
+- WinFontList *winFontList; // system TrueType fonts
+-#endif
+- GHash *displayCIDFonts; // display CID font info, indexed by
+- // collection [DisplayFontParam]
+- GHash *displayNamedCIDFonts; // display CID font info, indexed by
+- // font name [DisplayFontParam]
++ GHash *fontFiles; // font files: font name mapped to path
++ // [GString]
++ GList *fontDirs; // list of font dirs [GString]
++ GHash *ccFontFiles; // character collection font files:
++ // collection name mapped to path [GString]
++ SysFontList *sysFonts; // system fonts
+ GString *psFile; // PostScript file or command (for xpdf)
+ int psPaperWidth; // paper size, in PostScript points, for
+ int psPaperHeight; // PostScript output
+@@ -402,31 +393,44 @@
+ GBool psCenter; // center pages on the paper
+ GBool psDuplex; // enable duplexing in PostScript?
+ PSLevel psLevel; // PostScript level to generate
+- GHash *psFonts; // PostScript font info, indexed by PDF
+- // font name [PSFontParam]
+- GList *psNamedFonts16; // named 16-bit fonts [PSFontParam]
+- GList *psFonts16; // generic 16-bit fonts [PSFontParam]
++ GHash *psResidentFonts; // 8-bit fonts resident in printer:
++ // PDF font name mapped to PS font name
++ // [GString]
++ GList *psResidentFonts16; // 16-bit fonts resident in printer:
++ // PDF font name mapped to font info
++ // [PSFontParam16]
++ GList *psResidentFontsCC; // 16-bit character collection fonts
++ // resident in printer: collection name
++ // mapped to font info [PSFontParam16]
+ GBool psEmbedType1; // embed Type 1 fonts?
+ GBool psEmbedTrueType; // embed TrueType fonts?
+ GBool psEmbedCIDPostScript; // embed CID PostScript fonts?
+ GBool psEmbedCIDTrueType; // embed CID TrueType fonts?
++ GBool psFontPassthrough; // pass all fonts through as-is?
+ GBool psPreload; // preload PostScript images and forms into
+ // memory
+ GBool psOPI; // generate PostScript OPI comments?
+ GBool psASCIIHex; // use ASCIIHex instead of ASCII85?
++ GBool psUncompressPreloadedImages; // uncompress all preloaded images
++ double psRasterResolution; // PostScript rasterization resolution (dpi)
++ GBool psRasterMono; // true to do PostScript rasterization
++ // in monochrome (gray); false to do it
++ // in color (RGB/CMYK)
++ GBool psAlwaysRasterize; // force PostScript rasterization
+ GString *textEncoding; // encoding (unicodeMap) to use for text
+ // output
+ EndOfLineKind textEOL; // type of EOL marker to use for text
+ // output
+ GBool textPageBreaks; // insert end-of-page markers?
+ GBool textKeepTinyChars; // keep all characters in text output
+- GList *fontDirs; // list of font dirs [GString]
+ GString *initialZoom; // initial zoom level
+ GBool continuousView; // continuous view mode
+ GBool enableT1lib; // t1lib enable flag
+ GBool enableFreeType; // FreeType enable flag
+ GBool antialias; // font anti-aliasing enable flag
+ GBool vectorAntialias; // vector anti-aliasing enable flag
++ GBool antialiasPrinting; // allow anti-aliasing when printing
+ GBool strokeAdjust; // stroke adjustment enable flag
+ ScreenType screenType; // halftone screen type
+ int screenSize; // screen matrix size
+@@ -434,6 +438,10 @@
+ double screenGamma; // screen gamma correction
+ double screenBlackThreshold; // screen black clamping threshold
+ double screenWhiteThreshold; // screen white clamping threshold
++ double minLineWidth; // minimum line width
++ GBool overprintPreview; // enable overprint preview
+ GString *urlCommand; // command executed for URL links
+ GString *movieCommand; // command executed for movie annotations
+ GBool mapNumericCharNames; // map numeric char names (from font subsets)?
+Només a xpdf-3.03/xpdf: OptionalContent.cc
+Només a xpdf-3.03/xpdf: OptionalContent.h
+diff -ru xpdf-3.02/xpdf/OutputDev.cc xpdf-3.03/xpdf/OutputDev.cc
+--- xpdf-3.02/xpdf/OutputDev.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/OutputDev.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -65,6 +65,7 @@
+ updateStrokeOpacity(state);
+ updateFillOverprint(state);
+ updateStrokeOverprint(state);
++ updateOverprintMode(state);
+ updateTransfer(state);
+ updateFont(state);
+ }
+@@ -89,6 +90,13 @@
+ }
+ }
+
++void OutputDev::setSoftMaskFromImageMask(GfxState *state,
++ Object *ref, Stream *str,
++ int width, int height, GBool invert,
++ GBool inlineImg) {
++ drawImageMask(state, ref, str, width, height, invert, inlineImg);
++}
++
+ void OutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg) {
+diff -ru xpdf-3.02/xpdf/OutputDev.h xpdf-3.03/xpdf/OutputDev.h
+--- xpdf-3.02/xpdf/OutputDev.h 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/OutputDev.h 2011-08-15 23:08:53.000000000 +0200
+@@ -19,6 +19,7 @@
+ #include "CharTypes.h"
+
+ class GString;
++class Gfx;
+ class GfxState;
+ struct GfxColor;
+ class GfxColorSpace;
+@@ -76,6 +77,11 @@
+ // Does this device need non-text content?
+ virtual GBool needNonText() { return gTrue; }
+
++ // Does this device require incCharCount to be called for text on
++ // non-shown layers?
++ virtual GBool needCharCount() { return gFalse; }
++
++
+ //----- initialization and control
+
+ // Set default transform matrix.
+@@ -135,6 +141,7 @@
+ virtual void updateStrokeOpacity(GfxState *state) {}
+ virtual void updateFillOverprint(GfxState *state) {}
+ virtual void updateStrokeOverprint(GfxState *state) {}
++ virtual void updateOverprintMode(GfxState *state) {}
+ virtual void updateTransfer(GfxState *state) {}
+
+ //----- update text state
+@@ -147,12 +154,14 @@
+ virtual void updateHorizScaling(GfxState *state) {}
+ virtual void updateTextPos(GfxState *state) {}
+ virtual void updateTextShift(GfxState *state, double shift) {}
++ virtual void saveTextPos(GfxState *state) {}
++ virtual void restoreTextPos(GfxState *state) {}
+
+ //----- path painting
+ virtual void stroke(GfxState *state) {}
+ virtual void fill(GfxState *state) {}
+ virtual void eoFill(GfxState *state) {}
+@@ -185,11 +194,18 @@
+ CharCode code, Unicode *u, int uLen);
+ virtual void endType3Char(GfxState *state) {}
+ virtual void endTextObject(GfxState *state) {}
++ virtual void incCharCount(int nChars) {}
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg);
++ virtual void setSoftMaskFromImageMask(GfxState *state,
++ Object *ref, Stream *str,
++ int width, int height, GBool invert,
++ GBool inlineImg);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg);
+@@ -234,11 +250,10 @@
+ virtual void clearSoftMask(GfxState *state) {}
+
+ //----- links
+ virtual void processLink(Link *link) {}
+
+ #if 1 //~tmp: turn off anti-aliasing temporarily
+- virtual GBool getVectorAntialias() { return gFalse; }
+- virtual void setVectorAntialias(GBool vaa) {}
++ virtual void setInShading(GBool sh) {}
+ #endif
+
+ private:
+diff -ru xpdf-3.02/xpdf/PDFDoc.cc xpdf-3.03/xpdf/PDFDoc.cc
+--- xpdf-3.02/xpdf/PDFDoc.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/PDFDoc.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -36,6 +36,7 @@
+ #ifndef DISABLE_OUTLINE
+ #include "Outline.h"
+ #endif
++#include "OptionalContent.h"
+ #include "PDFDoc.h"
+
+ //------------------------------------------------------------------------
+@@ -174,6 +199,7 @@
+ #ifndef DISABLE_OUTLINE
+ outline = NULL;
+ #endif
++ optContent = NULL;
+ ok = setup(ownerPassword, userPassword);
+ }
+
+@@ -183,38 +209,71 @@
+ // check header
+ checkHeader();
+
++ // read the xref and catalog
++ if (!PDFDoc::setup2(ownerPassword, userPassword, gFalse)) {
++ if (errCode == errDamaged || errCode == errBadCatalog) {
++ // try repairing the xref table
++ error(errSyntaxWarning, -1,
++ "PDF file is damaged - attempting to reconstruct xref table...");
++ if (!PDFDoc::setup2(ownerPassword, userPassword, gTrue)) {
++ return gFalse;
++ }
++ } else {
++ return gFalse;
++ }
++ }
++
++#ifndef DISABLE_OUTLINE
++ // read outline
++ outline = new Outline(catalog->getOutline(), xref);
++#endif
++
++ // read the optional content info
++ optContent = new OptionalContent(this);
++
++ // done
++ return gTrue;
++}
++
++GBool PDFDoc::setup2(GString *ownerPassword, GString *userPassword,
++ GBool repairXRef) {
+ // read xref table
+- xref = new XRef(str);
++ xref = new XRef(str, repairXRef);
+ if (!xref->isOk()) {
+- error(-1, "Couldn't read xref table");
++ error(errSyntaxError, -1, "Couldn't read xref table");
+ errCode = xref->getErrorCode();
++ delete xref;
++ xref = NULL;
+ return gFalse;
+ }
+
+ // check for encryption
+ if (!checkEncryption(ownerPassword, userPassword)) {
+ errCode = errEncrypted;
++ delete xref;
++ xref = NULL;
+ return gFalse;
+ }
+
+ // read catalog
+ catalog = new Catalog(this);
+ if (!catalog->isOk()) {
+- error(-1, "Couldn't read page catalog");
++ error(errSyntaxError, -1, "Couldn't read page catalog");
+ errCode = errBadCatalog;
++ delete catalog;
++ catalog = NULL;
++ delete xref;
++ xref = NULL;
+ return gFalse;
+ }
+
+-#ifndef DISABLE_OUTLINE
+- // read outline
+- outline = new Outline(catalog->getOutline(), xref);
+-#endif
+-
+- // done
+ return gTrue;
+ }
+
+ PDFDoc::~PDFDoc() {
++ if (optContent) {
++ delete optContent;
++ }
+ #ifndef DISABLE_OUTLINE
+ if (outline) {
+ delete outline;
+@@ -280,7 +345,10 @@
+ xref->getTrailerDict()->dictLookup("Encrypt", &encrypt);
+ if ((encrypted = encrypt.isDict())) {
+ if ((secHdlr = SecurityHandler::make(this, &encrypt))) {
+- if (secHdlr->checkEncryption(ownerPassword, userPassword)) {
++ if (secHdlr->isUnencrypted()) {
++ // no encryption
++ ret = gTrue;
++ } else if (secHdlr->checkEncryption(ownerPassword, userPassword)) {
+ // authorization succeeded
+ xref->setEncryption(secHdlr->getPermissionFlags(),
+ secHdlr->getOwnerPasswordOk(),
+@@ -315,7 +383,7 @@
+ printf("***** page %d *****\n", page);
+ }
+ catalog->getPage(page)->display(out, hDPI, vDPI,
+- rotate, useMediaBox, crop, printing, catalog,
++ rotate, useMediaBox, crop, printing,
+ abortCheckCbk, abortCheckCbkData);
+ }
+
+@@ -329,6 +397,7 @@
+ for (page = firstPage; page <= lastPage; ++page) {
+ displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing,
+ abortCheckCbk, abortCheckCbkData);
++ catalog->doneWithPage(page);
+ }
+ }
+
+diff -ru xpdf-3.02/xpdf/PDFDoc.h xpdf-3.03/xpdf/PDFDoc.h
+--- xpdf-3.02/xpdf/PDFDoc.h 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/PDFDoc.h 2011-08-15 23:08:53.000000000 +0200
+@@ -27,6 +27,8 @@
+ class LinkAction;
+ class LinkDest;
+ class Outline;
++class OptionalContent;
+
+ //------------------------------------------------------------------------
+ // PDFDoc
+@@ -128,6 +133,9 @@
+ Outline *getOutline() { return outline; }
+ #endif
+
++ // Return the OptionalContent object.
++ OptionalContent *getOptionalContent() { return optContent; }
++
+ // Is the file encrypted?
+ GBool isEncrypted() { return xref->isEncrypted(); }
+
+@@ -154,27 +162,44 @@
+ private:
+
+ GBool setup(GString *ownerPassword, GString *userPassword);
++ GBool setup2(GString *ownerPassword, GString *userPassword,
++ GBool repairXRef);
+ void checkHeader();
+ GBool checkEncryption(GString *ownerPassword, GString *userPassword);
+
+ GString *fileName;
+ #ifdef WIN32
+ wchar_t *fileNameU;
+ #endif
+ FILE *file;
+ BaseStream *str;
+ void *guiData;
+ double pdfVersion;
+ XRef *xref;
+ Catalog *catalog;
+ #ifndef DISABLE_OUTLINE
+ Outline *outline;
+ #endif
+-
++ OptionalContent *optContent;
+
+ GBool ok;
+ int errCode;
+diff -ru xpdf-3.02/xpdf/pdftotext.cc xpdf-3.03/xpdf/pdftotext.cc
+--- xpdf-3.02/xpdf/pdftotext.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/pdftotext.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -35,7 +35,8 @@
+
+ static int firstPage = 1;
+ static int lastPage = 0;
+ static GBool physLayout = gFalse;
++static double fixedPitch = 0;
+ static GBool rawOrder = gFalse;
+ static GBool htmlMeta = gFalse;
+ static char textEncName[128] = "";
+@@ -55,6 +58,8 @@
+ "last page to convert"},
+ {"-layout", argFlag, &physLayout, 0,
+ "maintain original physical layout"},
++ {"-fixed", argFP, &fixedPitch, 0,
++ "assume fixed-pitch (or tabular) text"},
+ {"-raw", argFlag, &rawOrder, 0,
+ "keep strings in content stream order"},
+ {"-htmlmeta", argFlag, &htmlMeta, 0,
+@@ -112,6 +117,9 @@
+ goto err0;
+ }
+ fileName = new GString(argv[1]);
++ if (fixedPitch) {
++ physLayout = gTrue;
++ }
+
+ // read config file
+ globalParams = new GlobalParams(cfgFileName);
+@@ -232,7 +241,7 @@
+
+ // write text file
+ textOut = new TextOutputDev(textFileName->getCString(),
+- physLayout, rawOrder, htmlMeta);
++ physLayout, fixedPitch, rawOrder, htmlMeta);
+ if (textOut->isOk()) {
+ doc->displayPages(textOut, firstPage, lastPage, 72, 72, 0,
+ gFalse, gTrue, gFalse);
+diff -ru xpdf-3.02/xpdf/PreScanOutputDev.cc xpdf-3.03/xpdf/PreScanOutputDev.cc
+--- xpdf-3.02/xpdf/PreScanOutputDev.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/PreScanOutputDev.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -14,6 +14,8 @@
+
+ #include <math.h>
+ #include "GlobalParams.h"
++#include "Page.h"
++#include "Gfx.h"
+ #include "GfxFont.h"
+ #include "Link.h"
+ #include "PreScanOutputDev.h"
+@@ -58,6 +60,62 @@
+ state->getFillOpacity(), state->getBlendMode());
+ }
+
++GBool PreScanOutputDev::functionShadedFill(GfxState *state,
++ GfxFunctionShading *shading) {
++ if (shading->getColorSpace()->getMode() != csDeviceGray &&
++ shading->getColorSpace()->getMode() != csCalGray) {
++ gray = gFalse;
++ }
++ mono = gFalse;
++ if (state->getFillOpacity() != 1 ||
++ state->getBlendMode() != gfxBlendNormal) {
++ transparency = gTrue;
++ }
++ return gTrue;
++}
++
++GBool PreScanOutputDev::axialShadedFill(GfxState *state,
++ GfxAxialShading *shading) {
++ if (shading->getColorSpace()->getMode() != csDeviceGray &&
++ shading->getColorSpace()->getMode() != csCalGray) {
++ gray = gFalse;
++ }
++ mono = gFalse;
++ if (state->getFillOpacity() != 1 ||
++ state->getBlendMode() != gfxBlendNormal) {
++ transparency = gTrue;
++ }
++ return gTrue;
++}
++
++GBool PreScanOutputDev::radialShadedFill(GfxState *state,
++ GfxRadialShading *shading) {
++ if (shading->getColorSpace()->getMode() != csDeviceGray &&
++ shading->getColorSpace()->getMode() != csCalGray) {
++ gray = gFalse;
++ }
++ mono = gFalse;
++ if (state->getFillOpacity() != 1 ||
++ state->getBlendMode() != gfxBlendNormal) {
++ transparency = gTrue;
++ }
++ return gTrue;
++}
++
+ void PreScanOutputDev::clip(GfxState *state) {
+ //~ check for a rectangle "near" the edge of the page;
+ //~ else set gdi to false
+@@ -71,8 +129,6 @@
+ int render;
+ GfxFont *font;
+ double m11, m12, m21, m22;
+- Ref embRef;
+- DisplayFontParam *dfp;
+ GBool simpleTTF;
+
+ render = state->getRender();
+@@ -87,18 +143,14 @@
+
+ font = state->getFont();
+ state->getFontTransMat(&m11, &m12, &m21, &m22);
++ //~ this should check for external fonts that are non-TrueType
+ simpleTTF = fabs(m11 + m22) < 0.01 &&
+ m11 > 0 &&
+ fabs(m12) < 0.01 &&
+ fabs(m21) < 0.01 &&
+ fabs(state->getHorizScaling() - 1) < 0.001 &&
+ (font->getType() == fontTrueType ||
+- font->getType() == fontTrueTypeOT) &&
+- (font->getEmbeddedFontID(&embRef) ||
+- font->getExtFontFile() ||
+- (font->getName() &&
+- (dfp = globalParams->getDisplayFont(font->getName())) &&
+- dfp->kind == displayFontTT));
++ font->getType() == fontTrueTypeOT);
+ if (simpleTTF) {
+ //~ need to create a FoFiTrueType object, and check for a Unicode cmap
+ }
+@@ -127,6 +179,9 @@
+
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
++ if (state->getFillColorSpace()->getMode() == csPattern) {
++ patternImgMask = gTrue;
++ }
+ gdi = gFalse;
+
+ if (inlineImg) {
+@@ -149,12 +204,17 @@
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ }
+- if (colorSpace->getMode() != csDeviceGray &&
+- colorSpace->getMode() != csCalGray) {
++ if (colorSpace->getMode() == csDeviceGray ||
++ colorSpace->getMode() == csCalGray) {
++ if (colorMap->getBits() > 1) {
++ mono = gFalse;
++ }
++ } else {
+ gray = gFalse;
++ mono = gFalse;
+ }
+- mono = gFalse;
+- if (state->getBlendMode() != gfxBlendNormal) {
++ if (state->getFillOpacity() != 1 ||
++ state->getBlendMode() != gfxBlendNormal) {
+ transparency = gTrue;
+ }
+ gdi = gFalse;
+@@ -182,12 +242,17 @@
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ }
+- if (colorSpace->getMode() != csDeviceGray &&
+- colorSpace->getMode() != csCalGray) {
++ if (colorSpace->getMode() == csDeviceGray ||
++ colorSpace->getMode() == csCalGray) {
++ if (colorMap->getBits() > 1) {
++ mono = gFalse;
++ }
++ } else {
+ gray = gFalse;
++ mono = gFalse;
+ }
+- mono = gFalse;
+- if (state->getBlendMode() != gfxBlendNormal) {
++ if (state->getFillOpacity() != 1 ||
++ state->getBlendMode() != gfxBlendNormal) {
+ transparency = gTrue;
+ }
+ gdi = gFalse;
+@@ -253,5 +318,6 @@
+ mono = gTrue;
+ gray = gTrue;
+ transparency = gFalse;
++ patternImgMask = gFalse;
+ gdi = gTrue;
+ }
+diff -ru xpdf-3.02/xpdf/PreScanOutputDev.h xpdf-3.03/xpdf/PreScanOutputDev.h
+--- xpdf-3.02/xpdf/PreScanOutputDev.h 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/PreScanOutputDev.h 2011-08-15 23:08:53.000000000 +0200
+@@ -41,6 +41,16 @@
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gTrue; }
+
++ // Does this device use functionShadedFill(), axialShadedFill(), and
++ // radialShadedFill()? If this returns false, these shaded fills
++ // will be reduced to a series of other drawing operations.
++ virtual GBool useShadedFills() { return gTrue; }
++
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() { return gTrue; }
+@@ -57,6 +67,15 @@
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
++ virtual GBool functionShadedFill(GfxState *state,
++ GfxFunctionShading *shading);
++ virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading);
++ virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading);
+
+ //----- path clipping
+ virtual void clip(GfxState *state);
+@@ -110,6 +129,11 @@
+ GBool usesTransparency() { return transparency; }
+
+ // Returns true if the operations performed since the last call to
++ // clearStats() included any image mask fills with a pattern color
++ // space.
++ GBool usesPatternImageMask() { return patternImgMask; }
++
++ // Returns true if the operations performed since the last call to
+ // clearStats() are all rasterizable by GDI calls in GDIOutputDev.
+ GBool isAllGDI() { return gdi; }
+
+@@ -124,6 +148,7 @@
+ GBool mono;
+ GBool gray;
+ GBool transparency;
++ GBool patternImgMask;
+ GBool gdi;
+ };
+
+diff -ru xpdf-3.02/xpdf/PSOutputDev.cc xpdf-3.03/xpdf/PSOutputDev.cc
+--- xpdf-3.02/xpdf/PSOutputDev.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/PSOutputDev.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -19,6 +19,7 @@
+ #include <math.h>
+ #include "GString.h"
+ #include "GList.h"
++#include "GHash.h"
+ #include "config.h"
+ #include "GlobalParams.h"
+ #include "Object.h"
+@@ -34,8 +35,10 @@
+ #include "Page.h"
+ #include "Stream.h"
+ #include "Annot.h"
++#include "PDFDoc.h"
+ #include "XRef.h"
+ #include "PreScanOutputDev.h"
++#include "CharCodeToUnicode.h"
+ #if HAVE_SPLASH
+ # include "Splash.h"
+ # include "SplashBitmap.h"
+@@ -55,8 +58,8 @@
+
+ //------------------------------------------------------------------------
+
+-// Resolution at which pages with transparency will be rasterized.
+-#define splashDPI 300
++// Max size of a slice when rasterizing pages, in pixels.
++#define rasterizationSliceSize 20000000
+
+ //------------------------------------------------------------------------
+ // PostScript prolog and setup
+@@ -82,16 +85,24 @@
+ " } for",
+ "~123sn",
+ "/pdfSetup {",
+- " 3 1 roll 2 array astore",
+ " /setpagedevice where {",
+- " pop 3 dict begin",
++ " pop 2 dict begin",
++ " /Policies 1 dict dup begin /PageSize 6 def end def",
++ " { /Duplex true def } if",
++ " currentdict end setpagedevice",
++ " } {",
++ " pop",
++ " } ifelse",
++ "} def",
++ "/pdfSetupPaper {",
++ " 2 array astore",
++ " /setpagedevice where {",
++ " pop 2 dict begin",
+ " /PageSize exch def",
+ " /ImagingBBox null def",
+- " /Policies 1 dict dup begin /PageSize 3 def end def",
+- " { /Duplex true def } if",
+ " currentdict end setpagedevice",
+ " } {",
+- " pop pop",
++ " pop",
+ " } ifelse",
+ "} def",
+ "~1sn",
+@@ -377,82 +388,82 @@
+ "/Td { pdfTextMat transform moveto } def",
+ "/Tm { /pdfTextMat exch def } def",
+ "% text string operators",
++ "/xyshow where {",
++ " pop",
++ " /xyshow2 {",
++ " dup length array",
++ " 0 2 2 index length 1 sub {",
++ " 2 index 1 index 2 copy get 3 1 roll 1 add get",
++ " pdfTextMat dtransform",
++ " 4 2 roll 2 copy 6 5 roll put 1 add 3 1 roll dup 4 2 roll put",
++ " } for",
++ " exch pop",
++ " xyshow",
++ " } def",
++ "}{",
++ " /xyshow2 {",
++ " currentfont /FontType get 0 eq {",
++ " 0 2 3 index length 1 sub {",
++ " currentpoint 4 index 3 index 2 getinterval show moveto",
++ " 2 copy get 2 index 3 2 roll 1 add get",
++ " pdfTextMat dtransform rmoveto",
++ " } for",
++ " } {",
++ " 0 1 3 index length 1 sub {",
++ " currentpoint 4 index 3 index 1 getinterval show moveto",
++ " 2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get",
++ " pdfTextMat dtransform rmoveto",
++ " } for",
++ " } ifelse",
++ " pop pop",
++ " } def",
++ "} ifelse",
+ "/cshow where {",
+ " pop",
+- " /cshow2 {",
+- " dup {",
+- " pop pop",
+- " 1 string dup 0 3 index put 3 index exec",
++ " /xycp {", // xycharpath
++ " 0 3 2 roll",
++ " {",
++ " pop pop currentpoint 3 2 roll",
++ " 1 string dup 0 4 3 roll put false charpath moveto",
++ " 2 copy get 2 index 2 index 1 add get",
++ " pdfTextMat dtransform rmoveto",
++ " 2 add",
+ " } exch cshow",
+ " pop pop",
+ " } def",
+ "}{",
+- " /cshow2 {",
++ " /xycp {", // xycharpath
+ " currentfont /FontType get 0 eq {",
+- " 0 2 2 index length 1 sub {",
+- " 2 copy get exch 1 add 2 index exch get",
+- " 2 copy exch 256 mul add",
+- " 2 string dup 0 6 5 roll put dup 1 5 4 roll put",
+- " 3 index exec",
++ " 0 2 3 index length 1 sub {",
++ " currentpoint 4 index 3 index 2 getinterval false charpath moveto",
++ " 2 copy get 2 index 3 2 roll 1 add get",
++ " pdfTextMat dtransform rmoveto",
+ " } for",
+ " } {",
+- " dup {",
+- " 1 string dup 0 3 index put 3 index exec",
+- " } forall",
++ " 0 1 3 index length 1 sub {",
++ " currentpoint 4 index 3 index 1 getinterval false charpath moveto",
++ " 2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get",
++ " pdfTextMat dtransform rmoveto",
++ " } for",
+ " } ifelse",
+ " pop pop",
+ " } def",
+ "} ifelse",
+- "/awcp {", // awidthcharpath
+- " exch {",
+- " false charpath",
+- " 5 index 5 index rmoveto",
+- " 6 index eq { 7 index 7 index rmoveto } if",
+- " } exch cshow2",
+- " 6 {pop} repeat",
+- "} def",
+ "/Tj {",
+ " fCol", // because stringwidth has to draw Type 3 chars
+- " 1 index stringwidth pdfTextMat idtransform pop",
+- " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
+- " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
+- " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
+- " pdfTextMat dtransform",
+- " 6 5 roll Tj1",
+- "} def",
+- "/Tj16 {",
+- " fCol", // because stringwidth has to draw Type 3 chars
+- " 2 index stringwidth pdfTextMat idtransform pop",
+- " sub exch div",
+- " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
+- " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
+- " pdfTextMat dtransform",
+- " 6 5 roll Tj1",
+- "} def",
+- "/Tj16V {",
+- " fCol", // because stringwidth has to draw Type 3 chars
+- " 2 index stringwidth pdfTextMat idtransform exch pop",
+- " sub exch div",
+- " 0 pdfWordSpacing pdfTextMat dtransform 32",
+- " 4 3 roll pdfCharSpacing add 0 exch",
+- " pdfTextMat dtransform",
+- " 6 5 roll Tj1",
+- "} def",
+- "/Tj1 {",
+ " 0 pdfTextRise pdfTextMat dtransform rmoveto",
+- " currentpoint 8 2 roll",
++ " currentpoint 4 2 roll",
+ " pdfTextRender 1 and 0 eq {",
+- " 6 copy awidthshow",
++ " 2 copy xyshow2",
+ " } if",
+ " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
+- " 7 index 7 index moveto",
+- " 6 copy",
++ " 3 index 3 index moveto",
++ " 2 copy",
+ " currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
+- " false awcp currentpoint stroke moveto",
++ " xycp currentpoint stroke moveto",
+ " } if",
+ " pdfTextRender 4 and 0 ne {",
+- " 8 6 roll moveto",
+- " false awcp",
++ " 4 2 roll moveto xycp",
+ " /pdfTextClipPath [ pdfTextClipPath aload pop",
+ " {/moveto cvx}",
+ " {/lineto cvx}",
+@@ -461,13 +472,13 @@
+ " pathforall ] def",
+ " currentpoint newpath moveto",
+ " } {",
+- " 8 {pop} repeat",
++ " pop pop pop pop",
+ " } ifelse",
+ " 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
+ "} def",
+- "/TJm { pdfFontSize 0.001 mul mul neg 0",
++ "/TJm { 0.001 mul pdfFontSize mul pdfHorizScaling mul neg 0",
+ " pdfTextMat dtransform rmoveto } def",
+- "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
++ "/TJmV { 0.001 mul pdfFontSize mul neg 0 exch",
+ " pdfTextMat dtransform rmoveto } def",
+ "/Tclip { pdfTextClipPath cvx exec clip newpath",
+ " /pdfTextClipPath [] def } def",
+@@ -495,19 +506,52 @@
+ " fCol /pdfImBuf1 4 index 7 add 8 idiv string def",
+ " { currentfile pdfImBuf1 readhexstring pop } imagemask",
+ "} def",
++ "/pdfImStr {",
++ " 2 copy exch length lt {",
++ " 2 copy get exch 1 add exch",
++ " } {",
++ " ()",
++ " } ifelse",
++ "} def",
+ "/pdfImM1a {",
+- " { 2 copy get exch 1 add exch } imagemask",
++ " { pdfImStr } imagemask",
+ " pop pop",
+ "} def",
+ "~23sn",
+- "% Level 2 image operators",
++ "% Level 2/3 image operators",
+ "/pdfImBuf 100 string def",
+- "/pdfIm {",
+- " image",
++ "/pdfImStr {",
++ " 2 copy exch length lt {",
++ " 2 copy get exch 1 add exch",
++ " } {",
++ " ()",
++ " } ifelse",
++ "} def",
++ "/skipEOD {",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
++ "/pdfIm { image skipEOD } def",
++ "~3sn",
++ "/pdfMask {",
++ " /ReusableStreamDecode filter",
++ " skipEOD",
++ " /maskStream exch def",
++ "} def",
++ "/pdfMaskEnd { maskStream closefile } def",
++ "/pdfMaskInit {",
++ " /maskArray exch def",
++ " /maskIdx 0 def",
++ "} def",
++ "/pdfMaskSrc {",
++ " maskIdx maskArray length lt {",
++ " maskArray maskIdx get",
++ " /maskIdx maskIdx 1 add def",
++ " } {",
++ " ()",
++ " } ifelse",
++ "} def",
+ "~23s",
+ "/pdfImSep {",
+ " findcmykcustomcolor exch",
+@@ -523,17 +567,10 @@
+ " 255 exch sub put",
+ " } for }",
+ " 6 5 roll customcolorimage",
+- " { currentfile pdfImBuf readline",
+- " not { pop exit } if",
+- " (%-EOD-) eq { exit } if } loop",
++ " skipEOD",
+ "} def",
+ "~23sn",
+- "/pdfImM {",
+- " fCol imagemask",
+- " { currentfile pdfImBuf readline",
+- " not { pop exit } if",
+- " (%-EOD-) eq { exit } if } loop",
+- "} def",
++ "/pdfImM { fCol imagemask skipEOD } def",
+ "/pr { 2 index 2 index 3 2 roll putinterval 4 add } def",
+ "/pdfImClip {",
+ " gsave",
+@@ -607,7 +644,7 @@
+ " func n array astore",
+ "} def",
+ "/axialSH {",
+- " dup 0 eq {",
++ " dup 2 lt {",
+ " true",
+ " } {",
+ " dup 8 eq {",
+@@ -753,25 +790,12 @@
+ double mWidth; // width of 'm' character
+ };
+
+-static char *psFonts[] = {
+- "Courier",
+- "Courier-Bold",
+- "Courier-Oblique",
+- "Courier-BoldOblique",
+- "Helvetica",
+- "Helvetica-Bold",
+- "Helvetica-Oblique",
+- "Helvetica-BoldOblique",
+- "Symbol",
+- "Times-Roman",
+- "Times-Bold",
+- "Times-Italic",
+- "Times-BoldItalic",
+- "ZapfDingbats",
+- NULL
+-};
+-
+-static PSSubstFont psSubstFonts[] = {
++// NB: must be in same order as base14SubstFonts in GfxFont.cc
++static PSSubstFont psBase14SubstFonts[14] = {
++ {"Courier", 0.600},
++ {"Courier-Oblique", 0.600},
++ {"Courier-Bold", 0.600},
++ {"Courier-BoldOblique", 0.600},
+ {"Helvetica", 0.833},
+ {"Helvetica-Oblique", 0.833},
+ {"Helvetica-Bold", 0.889},
+@@ -780,22 +804,28 @@
+ {"Times-Italic", 0.722},
+ {"Times-Bold", 0.833},
+ {"Times-BoldItalic", 0.778},
+- {"Courier", 0.600},
+- {"Courier-Oblique", 0.600},
+- {"Courier-Bold", 0.600},
+- {"Courier-BoldOblique", 0.600}
++ // the last two are never used for substitution
++ {"Symbol", 0},
++ {"ZapfDingbats", 0}
++};
++
++// Mapping from Type 1/1C font file to PS font name.
++struct PST1FontName {
++ Ref fontFileID;
++ GString *psName; // PostScript font name used for this
++ // embedded font file
+ };
+
+ // Encoding info for substitute 16-bit font
+ struct PSFont16Enc {
+ Ref fontID;
+- GString *enc;
++ GString *enc; // NULL means font wasn't correctly substituted
+ };
+
+ //------------------------------------------------------------------------
+@@ -845,6 +875,13 @@
+ };
+
+ //------------------------------------------------------------------------
++
++struct PSOutPaperSize {
++ PSOutPaperSize(int wA, int hA) { w = wA; h = hA; }
++ int w, h;
++};
++
++//------------------------------------------------------------------------
+ // DeviceNRecoder
+ //------------------------------------------------------------------------
+
+@@ -897,6 +934,9 @@
+ if (imgStr) {
+ delete imgStr;
+ }
++ if (str->isEncoder()) {
++ delete str;
++ }
+ }
+
+ void DeviceNRecoder::reset() {
+@@ -942,10 +982,12 @@
+ fwrite(data, 1, len, (FILE *)stream);
+ }
+
+ PSOutputDev::PSOutputDev(char *fileName, PDFDoc *docA,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+- GBool manualCtrlA) {
++ GBool manualCtrlA,
++ PSOutCustomCodeCbk customCodeCbkA,
++ void *customCodeCbkDataA) {
+ FILE *f;
+ PSFileType fileTypeA;
+
+@@ -953,15 +995,18 @@
+ underlayCbkData = NULL;
+ overlayCbk = NULL;
+ overlayCbkData = NULL;
++ customCodeCbk = customCodeCbkA;
++ customCodeCbkData = customCodeCbkDataA;
+
+ fontIDs = NULL;
+- fontFileIDs = NULL;
+- fontFileNames = NULL;
++ fontNames = new GHash(gTrue);
++ t1FontNames = NULL;
+ font8Info = NULL;
+ font16Enc = NULL;
+ imgIDs = NULL;
+ formIDs = NULL;
+ xobjStack = NULL;
++ paperSizes = NULL;
+ embFontList = NULL;
+ customColors = NULL;
+ haveTextClip = gFalse;
+@@ -978,71 +1023,82 @@
+ signal(SIGPIPE, (SignalFunc)SIG_IGN);
+ #endif
+ if (!(f = popen(fileName + 1, "w"))) {
+ error(errIO, -1, "Couldn't run print command '{0:s}'", fileName);
+ ok = gFalse;
+ return;
+ }
+ #else
+ error(errIO, -1, "Print commands are not supported ('{0:s}')", fileName);
+ ok = gFalse;
+ return;
+ #endif
+ } else {
+ fileTypeA = psFile;
+ if (!(f = fopen(fileName, "w"))) {
+ error(errIO, -1, "Couldn't open PostScript file '{0:s}'", fileName);
+ ok = gFalse;
+ return;
+ }
+ }
+
+ init(outputToFile, f, fileTypeA,
+- xrefA, catalog, firstPage, lastPage, modeA,
++ docA, firstPage, lastPage, modeA,
+ imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
+ }
+
+ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
+ PDFDoc *docA,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+- GBool manualCtrlA) {
++ GBool manualCtrlA,
++ PSOutCustomCodeCbk customCodeCbkA,
++ void *customCodeCbkDataA) {
+ underlayCbk = NULL;
+ underlayCbkData = NULL;
+ overlayCbk = NULL;
+ overlayCbkData = NULL;
++ customCodeCbk = customCodeCbkA;
++ customCodeCbkData = customCodeCbkDataA;
+
+ fontIDs = NULL;
+- fontFileIDs = NULL;
+- fontFileNames = NULL;
++ fontNames = new GHash(gTrue);
++ t1FontNames = NULL;
+ font8Info = NULL;
+ font16Enc = NULL;
+ imgIDs = NULL;
+ formIDs = NULL;
+ xobjStack = NULL;
++ paperSizes = NULL;
+ embFontList = NULL;
+ customColors = NULL;
+ haveTextClip = gFalse;
+ t3String = NULL;
+
+ init(outputFuncA, outputStreamA, psGeneric,
+ docA, firstPage, lastPage, modeA,
+ imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
+ }
+
+ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
+ PSFileType fileTypeA, PDFDoc *docA,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool manualCtrlA) {
+ Catalog *catalog;
+ Page *page;
+ PDFRectangle *box;
++ PSOutPaperSize *size;
++ GList *names;
++ int pg, w, h, i;
+
+ // initialize
+ ok = gTrue;
+ outputFunc = outputFuncA;
+ outputStream = outputStreamA;
+ fileType = fileTypeA;
+ doc = docA;
+ xref = doc->getXRef();
+ catalog = doc->getCatalog();
+ level = globalParams->getPSLevel();
+ mode = modeA;
+ paperWidth = globalParams->getPSPaperWidth();
+@@ -1055,18 +1111,34 @@
+ globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY);
+ }
+ if (paperWidth < 0 || paperHeight < 0) {
+- // this check is needed in case the document has zero pages
+- if (firstPage > 0 && firstPage <= catalog->getNumPages()) {
+- page = catalog->getPage(firstPage);
+- paperWidth = (int)ceil(page->getMediaWidth());
+- paperHeight = (int)ceil(page->getMediaHeight());
+- } else {
+- paperWidth = 1;
+- paperHeight = 1;
+- }
+- imgLLX = imgLLY = 0;
+- imgURX = paperWidth;
+- imgURY = paperHeight;
++ paperMatch = gTrue;
++ paperSizes = new GList();
++ paperWidth = paperHeight = 1; // in case the document has zero pages
++ for (pg = (firstPage >= 1) ? firstPage : 1;
++ pg <= lastPage && pg <= catalog->getNumPages();
++ ++pg) {
++ page = catalog->getPage(pg);
++ w = (int)ceil(page->getMediaWidth());
++ h = (int)ceil(page->getMediaHeight());
++ for (i = 0; i < paperSizes->getLength(); ++i) {
++ size = (PSOutPaperSize *)paperSizes->get(i);
++ if (size->w == w && size->h == h) {
++ break;
++ }
++ }
++ if (i == paperSizes->getLength()) {
++ paperSizes->append(new PSOutPaperSize(w, h));
++ }
++ if (w > paperWidth) {
++ paperWidth = w;
++ }
++ if (h > paperHeight) {
++ paperHeight = h;
++ }
++ }
++ // NB: img{LLX,LLY,URX,URY} will be set by startPage()
++ } else {
++ paperMatch = gFalse;
+ }
+ preload = globalParams->getPSPreload();
+ manualCtrl = manualCtrlA;
+@@ -1088,17 +1160,21 @@
+ clipLLX0 = clipLLY0 = 0;
+ clipURX0 = clipURY0 = -1;
+
+- // initialize fontIDs, fontFileIDs, and fontFileNames lists
++ // initialize fontIDs and fontNames lists
+ fontIDSize = 64;
+ fontIDLen = 0;
+ fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref));
+- fontFileIDSize = 64;
+- fontFileIDLen = 0;
+- fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref));
+- fontFileNameSize = 64;
+- fontFileNameLen = 0;
+- fontFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *));
+- nextTrueTypeNum = 0;
++ for (i = 0; i < 14; ++i) {
++ fontNames->add(new GString(psBase14SubstFonts[i].psName), 1);
++ }
++ names = globalParams->getPSResidentFonts();
++ for (i = 0; i < names->getLength(); ++i) {
++ fontNames->add((GString *)names->get(i), 1);
++ }
++ delete names;
++ t1FontNameSize = 64;
++ t1FontNameLen = 0;
++ t1FontNames = (PST1FontName *)gmallocn(t1FontNameSize, sizeof(PST1FontName));
+ font8InfoLen = 0;
+ font8InfoSize = 0;
+ font16EncLen = 0;
+@@ -1173,20 +1249,21 @@
+ }
+ #endif
+ }
++ if (paperSizes) {
++ deleteGList(paperSizes, PSOutPaperSize);
++ }
+ if (embFontList) {
+ delete embFontList;
+ }
+ if (fontIDs) {
+ gfree(fontIDs);
+ }
+- if (fontFileIDs) {
+- gfree(fontFileIDs);
+- }
+- if (fontFileNames) {
+- for (i = 0; i < fontFileNameLen; ++i) {
+- delete fontFileNames[i];
++ delete fontNames;
++ if (t1FontNames) {
++ for (i = 0; i < t1FontNameLen; ++i) {
++ delete t1FontNames[i].psName;
+ }
+- gfree(fontFileNames);
++ gfree(t1FontNames);
+ }
+ if (font8Info) {
+ for (i = 0; i < font8InfoLen; ++i) {
+@@ -1196,7 +1273,9 @@
+ }
+ if (font16Enc) {
+ for (i = 0; i < font16EncLen; ++i) {
+- delete font16Enc[i].enc;
++ if (font16Enc[i].enc) {
++ delete font16Enc[i].enc;
++ }
+ }
+ gfree(font16Enc);
+ }
+@@ -1216,7 +1295,9 @@
+ PDFRectangle *mediaBox, PDFRectangle *cropBox,
+ int pageRotate) {
+ Object info, obj1;
++ PSOutPaperSize *size;
+ double x1, y1, x2, y2;
++ int i;
+
+ switch (mode) {
+ case psModePS:
+@@ -1230,7 +1311,7 @@
+ break;
+ }
+
+- writePSFmt("% Produced by xpdf/pdftops {0:s}\n", xpdfVersion);
++ writePSFmt("%XpdfVersion: {0:s}\n", xpdfVersion);
+ xref->getDocInfo(&info);
+ if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) {
+ writePS("%%Creator: ");
+@@ -1254,14 +1335,24 @@
+
+ switch (mode) {
+ case psModePS:
+- writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n",
+- paperWidth, paperHeight);
++ if (paperMatch) {
++ for (i = 0; i < paperSizes->getLength(); ++i) {
++ size = (PSOutPaperSize *)paperSizes->get(i);
++ writePSFmt("%%{0:s} {1:d}x{2:d} {1:d} {2:d} 0 () ()\n",
++ i==0 ? "DocumentMedia:" : "+", size->w, size->h);
++ }
++ } else {
++ writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n",
++ paperWidth, paperHeight);
++ }
+ writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight);
+ writePSFmt("%%Pages: {0:d}\n", lastPage - firstPage + 1);
+ writePS("%%EndComments\n");
+- writePS("%%BeginDefaults\n");
+- writePS("%%PageMedia: plain\n");
+- writePS("%%EndDefaults\n");
++ if (!paperMatch) {
++ writePS("%%BeginDefaults\n");
++ writePS("%%PageMedia: plain\n");
++ writePS("%%EndDefaults\n");
++ }
+ break;
+ case psModeEPS:
+ epsX1 = cropBox->x1;
+@@ -1343,7 +1434,9 @@
+ Page *page;
+ Dict *resDict;
+ Annots *annots;
+- Object obj1, obj2;
++ Object *acroForm;
++ Object obj1, obj2, obj3;
++ GString *s;
+ int pg, i;
+
+ if (mode == psModeForm) {
+@@ -1371,11 +1464,31 @@
+ }
+ delete annots;
+ }
++ if ((acroForm = catalog->getAcroForm()) && acroForm->isDict()) {
++ if (acroForm->dictLookup("DR", &obj1)->isDict()) {
++ setupResources(obj1.getDict());
++ }
++ obj1.free();
++ if (acroForm->dictLookup("Fields", &obj1)->isArray()) {
++ for (i = 0; i < obj1.arrayGetLength(); ++i) {
++ if (obj1.arrayGet(i, &obj2)->isDict()) {
++ if (obj2.dictLookup("DR", &obj3)->isDict()) {
++ setupResources(obj3.getDict());
++ }
++ obj3.free();
++ }
++ obj2.free();
++ }
++ }
++ obj1.free();
++ }
+ if (mode != psModeForm) {
+ if (mode != psModeEPS && !manualCtrl) {
+- writePSFmt("{0:d} {1:d} {2:s} pdfSetup\n",
+- paperWidth, paperHeight,
++ writePSFmt("{0:s} pdfSetup\n",
+ globalParams->getPSDuplex() ? "true" : "false");
++ if (!paperMatch) {
++ writePSFmt("{0:d} {1:d} pdfSetupPaper\n", paperWidth, paperHeight);
++ }
+ }
+ #if OPI_SUPPORT
+ if (globalParams->getPSOPI()) {
+@@ -1383,6 +1496,13 @@
+ }
+ #endif
+ }
++ if (customCodeCbk) {
++ if ((s = (*customCodeCbk)(this, psOutCustomDocSetup, 0,
++ customCodeCbkData))) {
++ writePS(s->getCString());
++ delete s;
++ }
++ }
+ }
+
+ void PSOutputDev::writePageTrailer() {
+@@ -1558,18 +1681,15 @@
+ }
+
+ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
+- Ref fontFileID;
+- GString *name;
+- PSFontParam *fontParam;
++ GfxFontLoc *fontLoc;
+ GString *psName;
+- char buf[16];
+ GBool subst;
++ char buf[16];
+ UnicodeMap *uMap;
+ char *charName;
+ double xs, ys;
+ int code;
+ double w1, w2;
+- double *fm;
+ int i, j;
+
+ // check if font is already set up
+@@ -1587,119 +1707,120 @@
+ }
+ fontIDs[fontIDLen++] = *font->getID();
+
++ psName = NULL;
+ xs = ys = 1;
+ subst = gFalse;
+
+- // check for resident 8-bit font
+- if (font->getName() &&
+- (fontParam = globalParams->getPSFont(font->getName()))) {
+- psName = new GString(fontParam->psFontName->getCString());
+-
+- // check for embedded Type 1 font
+- } else if (globalParams->getPSEmbedType1() &&
+- font->getType() == fontType1 &&
+- font->getEmbeddedFontID(&fontFileID)) {
+- psName = filterPSName(font->getEmbeddedFontName());
+- setupEmbeddedType1Font(&fontFileID, psName);
+-
+- // check for embedded Type 1C font
+- } else if (globalParams->getPSEmbedType1() &&
+- font->getType() == fontType1C &&
+- font->getEmbeddedFontID(&fontFileID)) {
+- // use the PDF font name because the embedded font name might
+- // not include the subset prefix
+- psName = filterPSName(font->getOrigName());
+- setupEmbeddedType1CFont(font, &fontFileID, psName);
+-
+- // check for embedded OpenType - Type 1C font
+- } else if (globalParams->getPSEmbedType1() &&
+- font->getType() == fontType1COT &&
+- font->getEmbeddedFontID(&fontFileID)) {
+- // use the PDF font name because the embedded font name might
+- // not include the subset prefix
+- psName = filterPSName(font->getOrigName());
+- setupEmbeddedOpenTypeT1CFont(font, &fontFileID, psName);
+-
+- // check for external Type 1 font file
+- } else if (globalParams->getPSEmbedType1() &&
+- font->getType() == fontType1 &&
+- font->getExtFontFile()) {
+- // this assumes that the PS font name matches the PDF font name
+- psName = font->getName()->copy();
+- setupExternalType1Font(font->getExtFontFile(), psName);
+-
+- // check for embedded TrueType font
+- } else if (globalParams->getPSEmbedTrueType() &&
+- (font->getType() == fontTrueType ||
+- font->getType() == fontTrueTypeOT) &&
+- font->getEmbeddedFontID(&fontFileID)) {
+- psName = filterPSName(font->getEmbeddedFontName());
+- setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
+-
+- // check for external TrueType font file
+- } else if (globalParams->getPSEmbedTrueType() &&
+- font->getType() == fontTrueType &&
+- font->getExtFontFile()) {
+- psName = filterPSName(font->getName());
+- setupExternalTrueTypeFont(font, psName);
+-
+- // check for embedded CID PostScript font
+- } else if (globalParams->getPSEmbedCIDPostScript() &&
+- font->getType() == fontCIDType0C &&
+- font->getEmbeddedFontID(&fontFileID)) {
+- psName = filterPSName(font->getEmbeddedFontName());
+- setupEmbeddedCIDType0Font(font, &fontFileID, psName);
+-
+- // check for embedded CID TrueType font
+- } else if (globalParams->getPSEmbedCIDTrueType() &&
+- (font->getType() == fontCIDType2 ||
+- font->getType() == fontCIDType2OT) &&
+- font->getEmbeddedFontID(&fontFileID)) {
+- psName = filterPSName(font->getEmbeddedFontName());
+- //~ should check to see if font actually uses vertical mode
+- setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue);
+-
+- // check for embedded OpenType - CID CFF font
+- } else if (globalParams->getPSEmbedCIDPostScript() &&
+- font->getType() == fontCIDType0COT &&
+- font->getEmbeddedFontID(&fontFileID)) {
+- psName = filterPSName(font->getEmbeddedFontName());
+- setupEmbeddedOpenTypeCFFFont(font, &fontFileID, psName);
+-
+- // check for Type 3 font
+- } else if (font->getType() == fontType3) {
++ if (font->getType() == fontType3) {
+ psName = GString::format("T3_{0:d}_{1:d}",
+ font->getID()->num, font->getID()->gen);
+ setupType3Font(font, psName, parentResDict);
+-
+- // do 8-bit font substitution
+- } else if (!font->isCIDFont()) {
+- subst = gTrue;
+- name = font->getName();
+- psName = NULL;
+- if (name) {
+- for (i = 0; psFonts[i]; ++i) {
+- if (name->cmp(psFonts[i]) == 0) {
+- psName = new GString(psFonts[i]);
+- break;
++ } else {
++ fontLoc = font->locateFont(xref, gTrue);
++ switch (fontLoc->locType) {
++ case gfxFontLocEmbedded:
++ switch (fontLoc->fontType) {
++ case fontType1:
++ // this assumes that the PS font name matches the PDF font name
++ psName = font->getEmbeddedFontName()->copy();
++ setupEmbeddedType1Font(&fontLoc->embFontID, psName);
++ break;
++ case fontType1C:
++ psName = makePSFontName(font, &fontLoc->embFontID);
++ setupEmbeddedType1CFont(font, &fontLoc->embFontID, psName);
++ break;
++ case fontType1COT:
++ psName = makePSFontName(font, &fontLoc->embFontID);
++ setupEmbeddedOpenTypeT1CFont(font, &fontLoc->embFontID, psName);
++ break;
++ case fontTrueType:
++ case fontTrueTypeOT:
++ psName = makePSFontName(font, font->getID());
++ setupEmbeddedTrueTypeFont(font, &fontLoc->embFontID, psName);
++ break;
++ case fontCIDType0C:
++ psName = makePSFontName(font, &fontLoc->embFontID);
++ setupEmbeddedCIDType0Font(font, &fontLoc->embFontID, psName);
++ break;
++ case fontCIDType2:
++ case fontCIDType2OT:
++ psName = makePSFontName(font, font->getID());
++ //~ should check to see if font actually uses vertical mode
++ setupEmbeddedCIDTrueTypeFont(font, &fontLoc->embFontID, psName, gTrue);
++ break;
++ case fontCIDType0COT:
++ psName = makePSFontName(font, &fontLoc->embFontID);
++ setupEmbeddedOpenTypeCFFFont(font, &fontLoc->embFontID, psName);
++ break;
++ default:
++ break;
++ }
++ break;
++ case gfxFontLocExternal:
++ //~ add cases for external 16-bit fonts
++ switch (fontLoc->fontType) {
++ case fontType1:
++ if (font->getName()) {
++ // this assumes that the PS font name matches the PDF font name
++ psName = font->getName()->copy();
++ } else {
++ //~ this won't work -- the PS font name won't match
++ psName = makePSFontName(font, font->getID());
+ }
++ setupExternalType1Font(fontLoc->path, psName);
++ break;
++ case fontTrueType:
++ case fontTrueTypeOT:
++ psName = makePSFontName(font, font->getID());
++ setupExternalTrueTypeFont(font, fontLoc->path, psName);
++ break;
++ case fontCIDType2:
++ case fontCIDType2OT:
++ psName = makePSFontName(font, font->getID());
++ //~ should check to see if font actually uses vertical mode
++ setupExternalCIDTrueTypeFont(font, fontLoc->path, psName, gTrue);
++ break;
++ default:
++ break;
+ }
++ break;
++ case gfxFontLocResident:
++ psName = fontLoc->path->copy();
++ break;
+ }
++
+ if (!psName) {
+- if (font->isFixedWidth()) {
+- i = 8;
+- } else if (font->isSerif()) {
+- i = 4;
++ if (font->isCIDFont()) {
++ error(errSyntaxError, -1,
++ "Couldn't find a font to substitute for '{0:s}' ('{1:s}' character collection)",
++ font->getName() ? font->getName()->getCString()
++ : "(unnamed)",
++ ((GfxCIDFont *)font)->getCollection()
++ ? ((GfxCIDFont *)font)->getCollection()->getCString()
++ : "(unknown)");
++ if (font16EncLen >= font16EncSize) {
++ font16EncSize += 16;
++ font16Enc = (PSFont16Enc *)greallocn(font16Enc,
++ font16EncSize,
++ sizeof(PSFont16Enc));
++ }
++ font16Enc[font16EncLen].fontID = *font->getID();
++ font16Enc[font16EncLen].enc = NULL;
++ ++font16EncLen;
+ } else {
+- i = 0;
+- }
+- if (font->isBold()) {
+- i += 2;
+- }
+- if (font->isItalic()) {
+- i += 1;
++ error(errSyntaxError, -1,
++ "Couldn't find a font to substitute for '{0:s}'",
++ font->getName() ? font->getName()->getCString()
++ : "(unnamed)");
+ }
+- psName = new GString(psSubstFonts[i].psName);
++ delete fontLoc;
++ return;
++ }
++
++ // scale substituted 8-bit fonts
++ if (fontLoc->locType == gfxFontLocResident &&
++ fontLoc->substIdx >= 0) {
++ subst = gTrue;
+ for (code = 0; code < 256; ++code) {
+ if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
+ charName[0] == 'm' && charName[1] == '\0') {
+@@ -1711,56 +1832,37 @@
+ } else {
+ w1 = 0;
+ }
+- w2 = psSubstFonts[i].mWidth;
++ w2 = psBase14SubstFonts[fontLoc->substIdx].mWidth;
+ xs = w1 / w2;
+ if (xs < 0.1) {
+ xs = 1;
+ }
+- if (font->getType() == fontType3) {
+- // This is a hack which makes it possible to substitute for some
+- // Type 3 fonts. The problem is that it's impossible to know what
+- // the base coordinate system used in the font is without actually
+- // rendering the font.
+- ys = xs;
+- fm = font->getFontMatrix();
+- if (fm[0] != 0) {
+- ys *= fm[3] / fm[0];
+- }
+- } else {
+- ys = 1;
+- }
+ }
+
+- // do 16-bit font substitution
+- } else if ((fontParam = globalParams->
+- getPSFont16(font->getName(),
+- ((GfxCIDFont *)font)->getCollection(),
+- font->getWMode()))) {
+- subst = gTrue;
+- psName = fontParam->psFontName->copy();
+- if (font16EncLen >= font16EncSize) {
+- font16EncSize += 16;
+- font16Enc = (PSFont16Enc *)greallocn(font16Enc,
+- font16EncSize, sizeof(PSFont16Enc));
+- }
+- font16Enc[font16EncLen].fontID = *font->getID();
+- font16Enc[font16EncLen].enc = fontParam->encoding->copy();
+- if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) {
+- uMap->decRefCnt();
++ // handle encodings for substituted CID fonts
++ if (fontLoc->locType == gfxFontLocResident &&
++ fontLoc->fontType >= fontCIDType0) {
++ subst = gTrue;
++ if (font16EncLen >= font16EncSize) {
++ font16EncSize += 16;
++ font16Enc = (PSFont16Enc *)greallocn(font16Enc,
++ font16EncSize,
++ sizeof(PSFont16Enc));
++ }
++ font16Enc[font16EncLen].fontID = *font->getID();
++ if ((uMap = globalParams->getUnicodeMap(fontLoc->encoding))) {
++ font16Enc[font16EncLen].enc = fontLoc->encoding->copy();
++ uMap->decRefCnt();
++ } else {
++ error(errSyntaxError, -1,
++ "Couldn't find Unicode map for 16-bit font encoding '{0:t}'",
++ fontLoc->encoding);
++ font16Enc[font16EncLen].enc = NULL;
++ }
+ ++font16EncLen;
+- } else {
+- error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
+- font16Enc[font16EncLen].enc->getCString());
+ }
+
+- // give up - can't do anything with this font
+- } else {
+- error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
+- font->getName() ? font->getName()->getCString() : "(unnamed)",
+- ((GfxCIDFont *)font)->getCollection()
+- ? ((GfxCIDFont *)font)->getCollection()->getCString()
+- : "(unknown)");
+- return;
++ delete fontLoc;
+ }
+
+ // generate PostScript code to set up the font
+@@ -1787,11 +1889,6 @@
+ charName = buf;
+ } else {
+ charName = ((Gfx8BitFont *)font)->getCharName(i+j);
+- // this is a kludge for broken PDF files that encode char 32
+- // as .notdef
+- if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
+- charName = "space";
+- }
+ }
+ writePS("/");
+ writePSName(charName ? charName : (char *)".notdef");
+@@ -1821,36 +1918,30 @@
+ int i;
+
+ // check if font is already embedded
+- for (i = 0; i < fontFileIDLen; ++i) {
+- if (fontFileIDs[i].num == id->num &&
+- fontFileIDs[i].gen == id->gen)
+- return;
+- }
+-
+- // add entry to fontFileIDs list
+- if (fontFileIDLen >= fontFileIDSize) {
+- fontFileIDSize += 64;
+- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
++ if (fontNames->lookupInt(psName)) {
++ return;
+ }
+- fontFileIDs[fontFileIDLen++] = *id;
++ fontNames->add(psName->copy(), 1);
+
+ // get the font stream and info
+ refObj.initRef(id->num, id->gen);
+ refObj.fetch(xref, &strObj);
+ refObj.free();
+ if (!strObj.isStream()) {
+ error(errSyntaxError, -1, "Embedded font file object is not a stream");
+ goto err1;
+ }
+ if (!(dict = strObj.streamGetDict())) {
+ error(errSyntaxError, -1,
+ "Embedded font stream is missing its dictionary");
+ goto err1;
+ }
+ dict->lookup("Length1", &obj1);
+ dict->lookup("Length2", &obj2);
+ dict->lookup("Length3", &obj3);
+ if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
+ error(errSyntaxError, -1,
+ "Missing length fields in embedded font stream dictionary");
+ obj1.free();
+ obj2.free();
+ obj3.free();
+@@ -1947,22 +2039,12 @@
+ void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) {
+ FILE *fontFile;
+ int c;
+- int i;
+
+ // check if font is already embedded
+- for (i = 0; i < fontFileNameLen; ++i) {
+- if (!fontFileNames[i]->cmp(fileName)) {
+- return;
+- }
+- }
+-
+- // add entry to fontFileNames list
+- if (fontFileNameLen >= fontFileNameSize) {
+- fontFileNameSize += 64;
+- fontFileNames = (GString **)greallocn(fontFileNames,
+- fontFileNameSize, sizeof(GString *));
++ if (fontNames->lookupInt(psName)) {
++ return;
+ }
+- fontFileNames[fontFileNameLen++] = fileName->copy();
++ fontNames->add(psName->copy(), 1);
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+@@ -1992,18 +2074,22 @@
+ int i;
+
+ // check if font is already embedded
+- for (i = 0; i < fontFileIDLen; ++i) {
+- if (fontFileIDs[i].num == id->num &&
+- fontFileIDs[i].gen == id->gen)
++ for (i = 0; i < t1FontNameLen; ++i) {
++ if (t1FontNames[i].fontFileID.num == id->num &&
++ t1FontNames[i].fontFileID.gen == id->gen) {
++ psName->clear();
++ psName->insert(0, t1FontNames[i].psName);
+ return;
++ }
+ }
+-
+- // add entry to fontFileIDs list
+- if (fontFileIDLen >= fontFileIDSize) {
+- fontFileIDSize += 64;
+- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+- }
+- fontFileIDs[fontFileIDLen++] = *id;
++ if (t1FontNameLen == t1FontNameSize) {
++ t1FontNameSize *= 2;
++ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
++ sizeof(PST1FontName));
++ }
++ t1FontNames[t1FontNameLen].fontFileID = *id;
++ t1FontNames[t1FontNameLen].psName = psName->copy();
++ ++t1FontNameLen;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+@@ -2012,13 +2098,14 @@
+ embFontList->append("\n");
+
+ // convert it to a Type 1 font
+- fontBuf = font->readEmbFontFile(xref, &fontLen);
+- if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
+- ffT1C->convertToType1(psName->getCString(), NULL, gTrue,
+- outputFunc, outputStream);
+- delete ffT1C;
++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
++ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
++ ffT1C->convertToType1(psName->getCString(), NULL, gTrue,
++ outputFunc, outputStream);
++ delete ffT1C;
++ }
++ gfree(fontBuf);
+ }
+- gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+@@ -2032,18 +2119,22 @@
+ int i;
+
+ // check if font is already embedded
+- for (i = 0; i < fontFileIDLen; ++i) {
+- if (fontFileIDs[i].num == id->num &&
+- fontFileIDs[i].gen == id->gen)
++ for (i = 0; i < t1FontNameLen; ++i) {
++ if (t1FontNames[i].fontFileID.num == id->num &&
++ t1FontNames[i].fontFileID.gen == id->gen) {
++ psName->clear();
++ psName->insert(0, t1FontNames[i].psName);
+ return;
++ }
+ }
+-
+- // add entry to fontFileIDs list
+- if (fontFileIDLen >= fontFileIDSize) {
+- fontFileIDSize += 64;
+- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+- }
+- fontFileIDs[fontFileIDLen++] = *id;
++ if (t1FontNameLen == t1FontNameSize) {
++ t1FontNameSize *= 2;
++ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
++ sizeof(PST1FontName));
++ }
++ t1FontNames[t1FontNameLen].fontFileID = *id;
++ t1FontNames[t1FontNameLen].psName = psName->copy();
++ ++t1FontNameLen;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+@@ -2052,15 +2143,16 @@
+ embFontList->append("\n");
+
+ // convert it to a Type 1 font
+- fontBuf = font->readEmbFontFile(xref, &fontLen);
+- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+- if (ffTT->isOpenTypeCFF()) {
+- ffTT->convertToType1(psName->getCString(), NULL, gTrue,
+- outputFunc, outputStream);
++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
++ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
++ if (ffTT->isOpenTypeCFF()) {
++ ffTT->convertToType1(psName->getCString(), NULL, gTrue,
++ outputFunc, outputStream);
++ }
++ delete ffTT;
+ }
+- delete ffTT;
++ gfree(fontBuf);
+ }
+- gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+@@ -2071,26 +2163,7 @@
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ int *codeToGID;
+- int i;
+-
+- // check if font is already embedded
+- for (i = 0; i < fontFileIDLen; ++i) {
+- if (fontFileIDs[i].num == id->num &&
+- fontFileIDs[i].gen == id->gen) {
+- psName->appendf("_{0:d}", nextTrueTypeNum++);
+- break;
+- }
+- }
+-
+- // add entry to fontFileIDs list
+- if (i == fontFileIDLen) {
+- if (fontFileIDLen >= fontFileIDSize) {
+- fontFileIDSize += 64;
+- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+- }
+- fontFileIDs[fontFileIDLen++] = *id;
+- }
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+@@ -2099,60 +2172,38 @@
+ embFontList->append("\n");
+
+ // convert it to a Type 42 font
+- fontBuf = font->readEmbFontFile(xref, &fontLen);
+- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+- codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
+- ffTT->convertToType42(psName->getCString(),
+- ((Gfx8BitFont *)font)->getHasEncoding()
+- ? ((Gfx8BitFont *)font)->getEncoding()
+- : (char **)NULL,
+- codeToGID, outputFunc, outputStream);
+- if (codeToGID) {
+- if (font8InfoLen >= font8InfoSize) {
+- font8InfoSize += 16;
+- font8Info = (PSFont8Info *)greallocn(font8Info,
+- font8InfoSize,
+- sizeof(PSFont8Info));
++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
++ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
++ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
++ ffTT->convertToType42(psName->getCString(),
++ ((Gfx8BitFont *)font)->getHasEncoding()
++ ? ((Gfx8BitFont *)font)->getEncoding()
++ : (char **)NULL,
++ codeToGID, outputFunc, outputStream);
++ if (codeToGID) {
++ if (font8InfoLen >= font8InfoSize) {
++ font8InfoSize += 16;
++ font8Info = (PSFont8Info *)greallocn(font8Info,
++ font8InfoSize,
++ sizeof(PSFont8Info));
++ }
++ font8Info[font8InfoLen].fontID = *font->getID();
++ font8Info[font8InfoLen].codeToGID = codeToGID;
++ ++font8InfoLen;
+ }
+- font8Info[font8InfoLen].fontID = *font->getID();
+- font8Info[font8InfoLen].codeToGID = codeToGID;
+- ++font8InfoLen;
++ delete ffTT;
+ }
+- delete ffTT;
++ gfree(fontBuf);
+ }
+- gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+ }
+
+-void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) {
+- GString *fileName;
+- char *fontBuf;
+- int fontLen;
++void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *fileName,
++ GString *psName) {
+ FoFiTrueType *ffTT;
+ int *codeToGID;
+- int i;
+-
+- // check if font is already embedded
+- fileName = font->getExtFontFile();
+- for (i = 0; i < fontFileNameLen; ++i) {
+- if (!fontFileNames[i]->cmp(fileName)) {
+- psName->appendf("_{0:d}", nextTrueTypeNum++);
+- break;
+- }
+- }
+-
+- // add entry to fontFileNames list
+- if (i == fontFileNameLen) {
+- if (fontFileNameLen >= fontFileNameSize) {
+- fontFileNameSize += 64;
+- fontFileNames =
+- (GString **)greallocn(fontFileNames,
+- fontFileNameSize, sizeof(GString *));
+- }
+- fontFileNames[fontFileNameLen++] = fileName->copy();
+- }
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+@@ -2161,8 +2212,7 @@
+ embFontList->append("\n");
+
+ // convert it to a Type 42 font
+- fontBuf = font->readExtFontFile(&fontLen);
+- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
++ if ((ffTT = FoFiTrueType::load(fileName->getCString()))) {
+ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
+ ffTT->convertToType42(psName->getCString(),
+ ((Gfx8BitFont *)font)->getHasEncoding()
+@@ -2182,7 +2232,6 @@
+ }
+ delete ffTT;
+ }
+- gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+@@ -2196,18 +2245,22 @@
+ int i;
+
+ // check if font is already embedded
+- for (i = 0; i < fontFileIDLen; ++i) {
+- if (fontFileIDs[i].num == id->num &&
+- fontFileIDs[i].gen == id->gen)
++ for (i = 0; i < t1FontNameLen; ++i) {
++ if (t1FontNames[i].fontFileID.num == id->num &&
++ t1FontNames[i].fontFileID.gen == id->gen) {
++ psName->clear();
++ psName->insert(0, t1FontNames[i].psName);
+ return;
++ }
+ }
+-
+- // add entry to fontFileIDs list
+- if (fontFileIDLen >= fontFileIDSize) {
+- fontFileIDSize += 64;
+- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+- }
+- fontFileIDs[fontFileIDLen++] = *id;
++ if (t1FontNameLen == t1FontNameSize) {
++ t1FontNameSize *= 2;
++ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
++ sizeof(PST1FontName));
++ }
++ t1FontNames[t1FontNameLen].fontFileID = *id;
++ t1FontNames[t1FontNameLen].psName = psName->copy();
++ ++t1FontNameLen;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+@@ -2216,18 +2269,21 @@
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+- fontBuf = font->readEmbFontFile(xref, &fontLen);
+- if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
+- if (globalParams->getPSLevel() >= psLevel3) {
+- // Level 3: use a CID font
+- ffT1C->convertToCIDType0(psName->getCString(), 0, NULL,
+- outputFunc, outputStream);
+- } else {
+- // otherwise: use a non-CID composite font
+- ffT1C->convertToType0(psName->getCString(), 0, NULL,
+- outputFunc, outputStream);
++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
++ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
++ if (globalParams->getPSLevel() >= psLevel3) {
++ // Level 3: use a CID font
++ ffT1C->convertToCIDType0(psName->getCString(), NULL, 0,
++ outputFunc, outputStream);
++ } else {
++ // otherwise: use a non-CID composite font
++ ffT1C->convertToType0(psName->getCString(), NULL, 0,
++ outputFunc, outputStream);
++ }
++ delete ffT1C;
+ }
+- delete ffT1C;
++ gfree(fontBuf);
+ }
+- gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+@@ -2239,23 +2295,50 @@
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+- int i;
+
+- // check if font is already embedded
+- for (i = 0; i < fontFileIDLen; ++i) {
+- if (fontFileIDs[i].num == id->num &&
+- fontFileIDs[i].gen == id->gen) {
+- psName->appendf("_{0:d}", nextTrueTypeNum++);
+- break;
++ // beginning comment
++ writePSFmt("%%BeginResource: font {0:t}\n", psName);
++ embFontList->append("%%+ font ");
++ embFontList->append(psName->getCString());
++ embFontList->append("\n");
++
++ // convert it to a Type 0 font
++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
++ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
++ if (globalParams->getPSLevel() >= psLevel3) {
++ // Level 3: use a CID font
++ ffTT->convertToCIDType2(psName->getCString(),
++ ((GfxCIDFont *)font)->getCIDToGID(),
++ ((GfxCIDFont *)font)->getCIDToGIDLen(),
++ needVerticalMetrics,
++ outputFunc, outputStream);
++ } else {
++ // otherwise: use a non-CID composite font
++ ffTT->convertToType0(psName->getCString(),
++ ((GfxCIDFont *)font)->getCIDToGID(),
++ ((GfxCIDFont *)font)->getCIDToGIDLen(),
++ needVerticalMetrics,
++ outputFunc, outputStream);
++ }
++ delete ffTT;
+ }
++ gfree(fontBuf);
+ }
+
+- // add entry to fontFileIDs list
+- if (fontFileIDLen >= fontFileIDSize) {
+- fontFileIDSize += 64;
+- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+- }
+- fontFileIDs[fontFileIDLen++] = *id;
++ // ending comment
++ writePS("%%EndResource\n");
++}
++
++void PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font,
++ GString *fileName,
++ GString *psName,
++ GBool needVerticalMetrics) {
++ FoFiTrueType *ffTT;
++ int *codeToGID;
++ int codeToGIDLen;
++ CharCodeToUnicode *ctu;
++ Unicode uBuf[8];
++ int cmap, code;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+@@ -2264,26 +2347,62 @@
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+- fontBuf = font->readEmbFontFile(xref, &fontLen);
+- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+- if (globalParams->getPSLevel() >= psLevel3) {
+- // Level 3: use a CID font
+- ffTT->convertToCIDType2(psName->getCString(),
+- ((GfxCIDFont *)font)->getCIDToGID(),
+- ((GfxCIDFont *)font)->getCIDToGIDLen(),
+- needVerticalMetrics,
+- outputFunc, outputStream);
++ //~ this should use fontNum to load the correct font
++ if ((ffTT = FoFiTrueType::load(fileName->getCString()))) {
++
++ // check for embedding permission
++ if (ffTT->getEmbeddingRights() >= 1) {
++
++ // create a CID-to-GID mapping, via Unicode
++ if ((ctu = ((GfxCIDFont *)font)->getToUnicode())) {
++ // look for a Unicode cmap
++ for (cmap = 0; cmap < ffTT->getNumCmaps(); ++cmap) {
++ if ((ffTT->getCmapPlatform(cmap) == 3 &&
++ ffTT->getCmapEncoding(cmap) == 1) ||
++ ffTT->getCmapPlatform(cmap) == 0) {
++ break;
++ }
++ }
++ if (cmap < ffTT->getNumCmaps()) {
++ // map CID -> Unicode -> GID
++ codeToGIDLen = ctu->getLength();
++ codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int));
++ for (code = 0; code < codeToGIDLen; ++code) {
++ if (ctu->mapToUnicode(code, uBuf, 8) > 0) {
++ codeToGID[code] = ffTT->mapCodeToGID(cmap, uBuf[0]);
++ } else {
++ codeToGID[code] = 0;
++ }
++ }
++ if (globalParams->getPSLevel() >= psLevel3) {
++ // Level 3: use a CID font
++ ffTT->convertToCIDType2(psName->getCString(),
++ codeToGID, codeToGIDLen,
++ needVerticalMetrics,
++ outputFunc, outputStream);
++ } else {
++ // otherwise: use a non-CID composite font
++ ffTT->convertToType0(psName->getCString(),
++ codeToGID, codeToGIDLen,
++ needVerticalMetrics,
++ outputFunc, outputStream);
++ }
++ gfree(codeToGID);
++ }
++ ctu->decRefCnt();
++ } else {
++ error(errSyntaxError, -1,
++ "Couldn't find a mapping to Unicode for font '{0:s}'",
++ font->getName() ? font->getName()->getCString() : "(unnamed)");
++ }
+ } else {
+- // otherwise: use a non-CID composite font
+- ffTT->convertToType0(psName->getCString(),
+- ((GfxCIDFont *)font)->getCIDToGID(),
+- ((GfxCIDFont *)font)->getCIDToGIDLen(),
+- needVerticalMetrics,
+- outputFunc, outputStream);
++ error(errSyntaxError, -1,
++ "TrueType font '%s' does not allow embedding",
++ font->getName() ? font->getName()->getCString() : "(unnamed)");
++
+ }
+ delete ffTT;
+ }
+- gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+@@ -2297,18 +2416,22 @@
+ int i;
+
+ // check if font is already embedded
+- for (i = 0; i < fontFileIDLen; ++i) {
+- if (fontFileIDs[i].num == id->num &&
+- fontFileIDs[i].gen == id->gen)
++ for (i = 0; i < t1FontNameLen; ++i) {
++ if (t1FontNames[i].fontFileID.num == id->num &&
++ t1FontNames[i].fontFileID.gen == id->gen) {
++ psName->clear();
++ psName->insert(0, t1FontNames[i].psName);
+ return;
++ }
+ }
+-
+- // add entry to fontFileIDs list
+- if (fontFileIDLen >= fontFileIDSize) {
+- fontFileIDSize += 64;
+- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+- }
+- fontFileIDs[fontFileIDLen++] = *id;
++ if (t1FontNameLen == t1FontNameSize) {
++ t1FontNameSize *= 2;
++ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
++ sizeof(PST1FontName));
++ }
++ t1FontNames[t1FontNameLen].fontFileID = *id;
++ t1FontNames[t1FontNameLen].psName = psName->copy();
++ ++t1FontNameLen;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+@@ -2317,21 +2440,27 @@
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+- fontBuf = font->readEmbFontFile(xref, &fontLen);
+- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+- if (ffTT->isOpenTypeCFF()) {
+- if (globalParams->getPSLevel() >= psLevel3) {
+- // Level 3: use a CID font
+- ffTT->convertToCIDType0(psName->getCString(),
+- ((GfxCIDFont *)font)->getCIDToGID(),
+- ((GfxCIDFont *)font)->getCIDToGIDLen(),
+- outputFunc, outputStream);
+- } else {
+- // otherwise: use a non-CID composite font
+- ffTT->convertToType0(psName->getCString(),
+- ((GfxCIDFont *)font)->getCIDToGID(),
+- ((GfxCIDFont *)font)->getCIDToGIDLen(),
+- outputFunc, outputStream);
++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
++ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
++ if (ffTT->isOpenTypeCFF()) {
++ if (globalParams->getPSLevel() >= psLevel3) {
++ // Level 3: use a CID font
++ ffTT->convertToCIDType0(psName->getCString(),
++ ((GfxCIDFont *)font)->getCIDToGID(),
++ ((GfxCIDFont *)font)->getCIDToGIDLen(),
++ outputFunc, outputStream);
++ } else {
++ // otherwise: use a non-CID composite font
++ ffTT->convertToType0(psName->getCString(),
++ ((GfxCIDFont *)font)->getCIDToGID(),
++ ((GfxCIDFont *)font)->getCIDToGIDLen(),
++ outputFunc, outputStream);
++ }
+ }
++ delete ffTT;
+ }
+- delete ffTT;
++ gfree(fontBuf);
+ }
+- gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+@@ -2390,9 +2519,10 @@
+ box.y1 = m[1];
+ box.x2 = m[2];
+ box.y2 = m[3];
+ gfx = new Gfx(doc, this, resDict, &box, NULL);
+ inType3Char = gTrue;
+ for (i = 0; i < charProcs->getLength(); ++i) {
++ t3FillColorOnly = gFalse;
+ t3Cacheable = gFalse;
+ t3NeedsRestore = gFalse;
+ writePS("/");
+@@ -2430,9 +2560,45 @@
+ writePS("%%EndResource\n");
+ }
+
++// Make a unique PS font name, based on the names given in the PDF
++// font object, and an object ID (font file object for
++GString *PSOutputDev::makePSFontName(GfxFont *font, Ref *id) {
++ GString *psName, *s;
++
++ if ((s = font->getEmbeddedFontName())) {
++ psName = filterPSName(s);
++ if (!fontNames->lookupInt(psName)) {
++ fontNames->add(psName->copy(), 1);
++ return psName;
++ }
++ delete psName;
++ }
++ if ((s = font->getName())) {
++ psName = filterPSName(s);
++ if (!fontNames->lookupInt(psName)) {
++ fontNames->add(psName->copy(), 1);
++ return psName;
++ }
++ delete psName;
++ }
++ psName = GString::format("FF{0:d}_{1:d}", id->num, id->gen);
++ if ((s = font->getEmbeddedFontName())) {
++ s = filterPSName(s);
++ psName->append('_')->append(s);
++ delete s;
++ } else if ((s = font->getName())) {
++ s = filterPSName(s);
++ psName->append('_')->append(s);
++ delete s;
++ }
++ fontNames->add(psName->copy(), 1);
++ return psName;
++}
++
+ void PSOutputDev::setupImages(Dict *resDict) {
+- Object xObjDict, xObj, xObjRef, subtypeObj;
+- int i;
++ Object xObjDict, xObj, xObjRef, subtypeObj, maskObj, maskRef;
++ Ref imgID;
++ int i, j;
+
+ if (!(mode == psModeForm || inType3Char || preload)) {
+ return;
+@@ -2447,9 +2613,32 @@
+ xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
+ if (subtypeObj.isName("Image")) {
+ if (xObjRef.isRef()) {
+- setupImage(xObjRef.getRef(), xObj.getStream());
++ imgID = xObjRef.getRef();
++ for (j = 0; j < imgIDLen; ++j) {
++ if (imgIDs[j].num == imgID.num && imgIDs[j].gen == imgID.gen) {
++ break;
++ }
++ }
++ if (j == imgIDLen) {
++ if (imgIDLen >= imgIDSize) {
++ if (imgIDSize == 0) {
++ imgIDSize = 64;
++ } else {
++ imgIDSize *= 2;
++ }
++ imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref));
++ }
++ imgIDs[imgIDLen++] = imgID;
++ setupImage(imgID, xObj.getStream(), gFalse);
++ if (level >= psLevel3 &&
++ xObj.streamGetDict()->lookup("Mask", &maskObj)->isStream()) {
++ setupImage(imgID, maskObj.getStream(), gTrue);
++ }
++ maskObj.free();
++ }
+ } else {
+ error(errSyntaxError, -1,
+ "Image in resource dict is not an indirect reference");
+ }
+ }
+ subtypeObj.free();
+@@ -2461,30 +2650,12 @@
+ xObjDict.free();
+ }
+
+-void PSOutputDev::setupImage(Ref id, Stream *str) {
++void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
+ GBool useRLE, useCompressed, useASCIIHex;
+ GString *s;
+ int c;
+ int size, line, col, i;
+
+- // check if image is already setup
+- for (i = 0; i < imgIDLen; ++i) {
+- if (imgIDs[i].num == id.num && imgIDs[i].gen == id.gen) {
+- return;
+- }
+- }
+-
+- // add entry to imgIDs list
+- if (imgIDLen >= imgIDSize) {
+- if (imgIDSize == 0) {
+- imgIDSize = 64;
+- } else {
+- imgIDSize *= 2;
+- }
+- imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref));
+- }
+- imgIDs[imgIDLen++] = id;
+-
+ // filters
+ //~ this does not correctly handle the DeviceN color space
+ //~ -- need to use DeviceNRecoder
+@@ -2493,17 +2664,21 @@
+ useCompressed = gFalse;
+ useASCIIHex = gTrue;
+ } else {
+- s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
+- if (s) {
++ if (globalParams->getPSUncompressPreloadedImages()) {
+ useRLE = gFalse;
+- useCompressed = gTrue;
+- delete s;
+- } else {
+- useRLE = gTrue;
+ useCompressed = gFalse;
++ } else {
++ s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
++ if (s) {
++ useRLE = gFalse;
++ useCompressed = gTrue;
++ delete s;
++ } else {
++ useRLE = gTrue;
++ useCompressed = gFalse;
++ }
+ }
+- useASCIIHex = level == psLevel1 || level == psLevel1Sep ||
+- globalParams->getPSASCIIHex();
++ useASCIIHex = globalParams->getPSASCIIHex();
+ }
+ if (useCompressed) {
+ str = str->getUndecodedStream();
+@@ -2552,8 +2727,8 @@
+ if (useRLE) {
+ ++size;
+ }
+- writePSFmt("{0:d} array dup /ImData_{1:d}_{2:d} exch def\n",
+- size, id.num, id.gen);
++ writePSFmt("{0:d} array dup /{1:s}Data_{2:d}_{3:d} exch def\n",
++ size, mask ? "Mask" : "Im", id.num, id.gen);
+ str->close();
+
+ // write the data into the array
+@@ -2722,12 +2898,14 @@
+ int rotateA, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY,
+ int sliceW, int sliceH,
+ GBool printing,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData) {
+-#if HAVE_SPLASH
+ PreScanOutputDev *scan;
+ GBool rasterize;
++#if HAVE_SPLASH
++ GBool mono;
++ double dpi;
+ SplashOutputDev *splashOut;
+ SplashColor paperColor;
+ PDFRectangle box;
+@@ -2737,43 +2915,33 @@
+ Object obj;
+ Guchar *p;
+ Guchar col[4];
++ double hDPI2, vDPI2;
+ double m0, m1, m2, m3, m4, m5;
++ int nStripes, stripeH, stripeY;
+ int c, w, h, x, y, comp, i;
++#endif
+
+- scan = new PreScanOutputDev();
+- page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop,
+- sliceX, sliceY, sliceW, sliceH,
+- printing, catalog, abortCheckCbk, abortCheckCbkData);
+- rasterize = scan->usesTransparency();
+- delete scan;
++ if (globalParams->getPSAlwaysRasterize()) {
++ rasterize = gTrue;
++ } else {
++ scan = new PreScanOutputDev();
++ page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop,
++ sliceX, sliceY, sliceW, sliceH,
++ printing, abortCheckCbk, abortCheckCbkData);
++ rasterize = scan->usesTransparency() || scan->usesPatternImageMask();
++ delete scan;
++ }
+ if (!rasterize) {
+ return gTrue;
+ }
+
+- // rasterize the page
+- if (level == psLevel1) {
+- paperColor[0] = 0xff;
+- splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse,
+- paperColor, gTrue, gFalse);
+-#if SPLASH_CMYK
+- } else if (level == psLevel1Sep) {
+- paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0;
+- splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse,
+- paperColor, gTrue, gFalse);
+-#endif
+- } else {
+- paperColor[0] = paperColor[1] = paperColor[2] = 0xff;
+- splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse,
+- paperColor, gTrue, gFalse);
+- }
+- splashOut->startDoc(xref);
+- page->displaySlice(splashOut, splashDPI, splashDPI, rotateA,
+- useMediaBox, crop,
+- sliceX, sliceY, sliceW, sliceH,
+- printing, catalog, abortCheckCbk, abortCheckCbkData);
++#if HAVE_SPLASH
++ // get the rasterization parameters
++ dpi = globalParams->getPSRasterResolution();
++ mono = globalParams->getPSRasterMono();
+
+ // start the PS page
+- page->makeBox(splashDPI, splashDPI, rotateA, useMediaBox, gFalse,
++ page->makeBox(dpi, dpi, rotateA, useMediaBox, gFalse,
+ sliceX, sliceY, sliceW, sliceH, &box, &crop);
+ rotateA += page->getRotate();
+ if (rotateA >= 360) {
+@@ -2781,166 +2949,215 @@
+ } else if (rotateA < 0) {
+ rotateA += 360;
+ }
+- state = new GfxState(splashDPI, splashDPI, &box, rotateA, gFalse);
+- startPage(page->getNum(), state);
+- delete state;
+- switch (rotateA) {
+- case 0:
+- default: // this should never happen
++ state = new GfxState(dpi, dpi, &box, rotateA, gFalse);
++ startPage(page->getNum(), state);
++ delete state;
++
++ // set up the SplashOutputDev
++ if (mono || level == psLevel1) {
++ paperColor[0] = 0xff;
++ splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse,
++ paperColor, gFalse,
++ globalParams->getAntialiasPrinting());
++#if SPLASH_CMYK
++ } else if (level == psLevel1Sep) {
++ paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0;
++ splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse,
++ paperColor, gFalse,
++ globalParams->getAntialiasPrinting());
++#endif
++ } else {
++ paperColor[0] = paperColor[1] = paperColor[2] = 0xff;
++ splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse,
++ paperColor, gFalse,
++ globalParams->getAntialiasPrinting());
++ }
++ splashOut->startDoc(xref);
++
++ // break the page into stripes
++ hDPI2 = xScale * dpi;
++ vDPI2 = yScale * dpi;
++ if (sliceW < 0 || sliceH < 0) {
++ if (useMediaBox) {
++ box = *page->getMediaBox();
++ } else {
++ box = *page->getCropBox();
++ }
++ sliceX = sliceY = 0;
++ sliceW = (int)((box.x2 - box.x1) * hDPI2 / 72.0);
++ sliceH = (int)((box.y2 - box.y1) * vDPI2 / 72.0);
++ }
++ nStripes = (int)ceil((double)(sliceW * sliceH) /
++ (double)rasterizationSliceSize);
++ stripeH = (sliceH + nStripes - 1) / nStripes;
++
++ // render the stripes
++ for (stripeY = sliceY; stripeY < sliceH; stripeY += stripeH) {
++
++ // rasterize a stripe
++ page->makeBox(hDPI2, vDPI2, 0, useMediaBox, gFalse,
++ sliceX, stripeY, sliceW, stripeH, &box, &crop);
+ m0 = box.x2 - box.x1;
+ m1 = 0;
+ m2 = 0;
+ m3 = box.y2 - box.y1;
+ m4 = box.x1;
+ m5 = box.y1;
+- break;
+- case 90:
+- m0 = 0;
+- m1 = box.y2 - box.y1;
+- m2 = -(box.x2 - box.x1);
+- m3 = 0;
+- m4 = box.x2;
+- m5 = box.y1;
+- break;
+- case 180:
+- m0 = -(box.x2 - box.x1);
+- m1 = 0;
+- m2 = 0;
+- m3 = -(box.y2 - box.y1);
+- m4 = box.x2;
+- m5 = box.y2;
+- break;
+- case 270:
+- m0 = 0;
+- m1 = -(box.y2 - box.y1);
+- m2 = box.x2 - box.x1;
+- m3 = 0;
+- m4 = box.x1;
+- m5 = box.y2;
+- break;
+- }
+-
+- //~ need to add the process colors
+-
+- // draw the rasterized image
+- bitmap = splashOut->getBitmap();
+- w = bitmap->getWidth();
+- h = bitmap->getHeight();
+- writePS("gsave\n");
+- writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] concat\n",
+- m0, m1, m2, m3, m4, m5);
+- switch (level) {
+- case psLevel1:
+- writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
+- w, h, w, -h, h);
+- p = bitmap->getDataPtr();
+- i = 0;
+- for (y = 0; y < h; ++y) {
+- for (x = 0; x < w; ++x) {
+- writePSFmt("{0:02x}", *p++);
+- if (++i == 32) {
+- writePSChar('\n');
+- i = 0;
+- }
+- }
+- }
+- if (i != 0) {
+- writePSChar('\n');
+- }
+- break;
+- case psLevel1Sep:
+- writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
+- w, h, w, -h, h);
+- p = bitmap->getDataPtr();
+- i = 0;
+- col[0] = col[1] = col[2] = col[3] = 0;
+- for (y = 0; y < h; ++y) {
+- for (comp = 0; comp < 4; ++comp) {
++ page->displaySlice(splashOut, hDPI2, vDPI2,
++ (360 - page->getRotate()) % 360, useMediaBox, crop,
++ sliceX, stripeY, sliceW, stripeH,
++ printing, abortCheckCbk, abortCheckCbkData);
++
++ // draw the rasterized image
++ bitmap = splashOut->getBitmap();
++ w = bitmap->getWidth();
++ h = bitmap->getHeight();
++ writePS("gsave\n");
++ writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
++ m0, m1, m2, m3, m4, m5);
++ switch (level) {
++ case psLevel1:
++ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
++ w, h, w, -h, h);
++ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
++ i = 0;
++ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+- writePSFmt("{0:02x}", p[4*x + comp]);
+- col[comp] |= p[4*x + comp];
++ writePSFmt("{0:02x}", *p++);
+ if (++i == 32) {
+ writePSChar('\n');
+ i = 0;
+ }
+ }
+ }
+- p += bitmap->getRowSize();
+- }
+- if (i != 0) {
++ if (i != 0) {
++ writePSChar('\n');
++ }
++ break;
++ case psLevel1Sep:
++ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
++ w, h, w, -h, h);
++ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
++ i = 0;
++ col[0] = col[1] = col[2] = col[3] = 0;
++ for (y = 0; y < h; ++y) {
++ for (comp = 0; comp < 4; ++comp) {
++ for (x = 0; x < w; ++x) {
++ writePSFmt("{0:02x}", p[4*x + comp]);
++ col[comp] |= p[4*x + comp];
++ if (++i == 32) {
++ writePSChar('\n');
++ i = 0;
++ }
++ }
++ }
++ p -= bitmap->getRowSize();
++ }
++ if (i != 0) {
++ writePSChar('\n');
++ }
++ if (col[0]) {
++ processColors |= psProcessCyan;
++ }
++ if (col[1]) {
++ processColors |= psProcessMagenta;
++ }
++ if (col[2]) {
++ processColors |= psProcessYellow;
++ }
++ if (col[3]) {
++ processColors |= psProcessBlack;
++ }
++ break;
++ case psLevel2:
++ case psLevel2Sep:
++ case psLevel3:
++ case psLevel3Sep:
++ if (mono) {
++ writePS("/DeviceGray setcolorspace\n");
++ } else {
++ writePS("/DeviceRGB setcolorspace\n");
++ }
++ writePS("<<\n /ImageType 1\n");
++ writePSFmt(" /Width {0:d}\n", bitmap->getWidth());
++ writePSFmt(" /Height {0:d}\n", bitmap->getHeight());
++ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
++ writePS(" /BitsPerComponent 8\n");
++ if (mono) {
++ writePS(" /Decode [0 1]\n");
++ } else {
++ writePS(" /Decode [0 1 0 1 0 1]\n");
++ }
++ writePS(" /DataSource currentfile\n");
++ if (globalParams->getPSASCIIHex()) {
++ writePS(" /ASCIIHexDecode filter\n");
++ } else {
++ writePS(" /ASCII85Decode filter\n");
++ }
++ writePS(" /RunLengthDecode filter\n");
++ writePS(">>\n");
++ writePS("image\n");
++ obj.initNull();
++ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
++ str0 = new MemStream((char *)p, 0, w * h * (mono ? 1 : 3), &obj);
++ str = new RunLengthEncoder(str0);
++ if (globalParams->getPSASCIIHex()) {
++ str = new ASCIIHexEncoder(str);
++ } else {
++ str = new ASCII85Encoder(str);
++ }
++ str->reset();
++ while ((c = str->getChar()) != EOF) {
++ writePSChar(c);
++ }
++ str->close();
++ delete str;
++ delete str0;
+ writePSChar('\n');
++ processColors |= mono ? psProcessBlack : psProcessCMYK;
++ break;
+ }
+- if (col[0]) {
+- processColors |= psProcessCyan;
+- }
+- if (col[1]) {
+- processColors |= psProcessMagenta;
+- }
+- if (col[2]) {
+- processColors |= psProcessYellow;
+- }
+- if (col[3]) {
+- processColors |= psProcessBlack;
+- }
+- break;
+- case psLevel2:
+- case psLevel2Sep:
+- case psLevel3:
+- case psLevel3Sep:
+- writePS("/DeviceRGB setcolorspace\n");
+- writePS("<<\n /ImageType 1\n");
+- writePSFmt(" /Width {0:d}\n", bitmap->getWidth());
+- writePSFmt(" /Height {0:d}\n", bitmap->getHeight());
+- writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
+- writePS(" /BitsPerComponent 8\n");
+- writePS(" /Decode [0 1 0 1 0 1]\n");
+- writePS(" /DataSource currentfile\n");
+- if (globalParams->getPSASCIIHex()) {
+- writePS(" /ASCIIHexDecode filter\n");
+- } else {
+- writePS(" /ASCII85Decode filter\n");
+- }
+- writePS(" /RunLengthDecode filter\n");
+- writePS(">>\n");
+- writePS("image\n");
+- obj.initNull();
+- str0 = new MemStream((char *)bitmap->getDataPtr(), 0, w * h * 3, &obj);
+- str = new RunLengthEncoder(str0);
+- if (globalParams->getPSASCIIHex()) {
+- str = new ASCIIHexEncoder(str);
+- } else {
+- str = new ASCII85Encoder(str);
+- }
+- str->reset();
+- while ((c = str->getChar()) != EOF) {
+- writePSChar(c);
+- }
+- str->close();
+- delete str;
+- delete str0;
+- processColors |= psProcessCMYK;
+- break;
++ writePS("grestore\n");
+ }
++
+ delete splashOut;
+- writePS("grestore\n");
+
+ // finish the PS page
+ endPage();
+
+ return gFalse;
+-#else
++
++#else // HAVE_SPLASH
++
++ error(errSyntaxWarning, -1,
++ "PDF page uses transparency and PSOutputDev was built without"
++ " the Splash rasterizer - output may not be correct");
+ return gTrue;
+-#endif
++#endif // HAVE_SPLASH
+ }
+
+ void PSOutputDev::startPage(int pageNum, GfxState *state) {
+- int x1, y1, x2, y2, width, height;
++ Page *page;
++ int x1, y1, x2, y2, width, height, t;
+ int imgWidth, imgHeight, imgWidth2, imgHeight2;
+ GBool landscape;
+-
++ GString *s;
+
+ if (mode == psModePS) {
+ writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage);
++ if (paperMatch) {
++ page = doc->getCatalog()->getPage(pageNum);
++ imgLLX = imgLLY = 0;
++ imgURX = (int)ceil(page->getMediaWidth());
++ imgURY = (int)ceil(page->getMediaHeight());
++ if (state->getRotate() == 90 || state->getRotate() == 270) {
++ t = imgURX;
++ imgURX = imgURY;
++ imgURY = t;
++ }
++ writePSFmt("%%PageMedia: {0:d}x{1:d}\n", imgURX, imgURY);
++ writePSFmt("%%PageBoundingBox: 0 0 {0:d} {1:d}\n", imgURX, imgURY);
++ }
+ writePS("%%BeginPageSetup\n");
+ }
+
+@@ -2966,20 +3183,25 @@
+ height = y2 - y1;
+ tx = ty = 0;
+ // rotation and portrait/landscape mode
+- if (rotate0 >= 0) {
++ if (paperMatch) {
++ rotate = (360 - state->getRotate()) % 360;
++ landscape = gFalse;
++ } else if (rotate0 >= 0) {
+ rotate = (360 - rotate0) % 360;
+ landscape = gFalse;
+ } else {
+ rotate = (360 - state->getRotate()) % 360;
+ if (rotate == 0 || rotate == 180) {
+- if (width > height && width > imgWidth) {
++ if ((width < height && imgWidth > imgHeight && height > imgHeight) ||
++ (width > height && imgWidth < imgHeight && width > imgWidth)) {
+ rotate += 90;
+ landscape = gTrue;
+ } else {
+ landscape = gFalse;
+ }
+ } else { // rotate == 90 || rotate == 270
+- if (height > width && height > imgWidth) {
++ if ((height < width && imgWidth > imgHeight && width > imgHeight) ||
++ (height > width && imgWidth < imgHeight && height > imgWidth)) {
+ rotate = 270 - rotate;
+ landscape = gTrue;
+ } else {
+@@ -2989,6 +3211,9 @@
+ }
+ writePSFmt("%%PageOrientation: {0:s}\n",
+ landscape ? "Landscape" : "Portrait");
++ if (paperMatch) {
++ writePSFmt("{0:d} {1:d} pdfSetupPaper\n", imgURX, imgURY);
++ }
+ writePS("pdfStartPage\n");
+ if (rotate == 0) {
+ imgWidth2 = imgWidth;
+@@ -3015,9 +3240,9 @@
+ xScale = xScale0;
+ yScale = yScale0;
+ } else if ((globalParams->getPSShrinkLarger() &&
+- (width > imgWidth2 || height > imgHeight2)) ||
+- (globalParams->getPSExpandSmaller() &&
+- (width < imgWidth2 && height < imgHeight2))) {
++ (width > imgWidth2 || height > imgHeight2)) ||
++ (globalParams->getPSExpandSmaller() &&
++ (width < imgWidth2 && height < imgHeight2))) {
+ xScale = (double)imgWidth2 / (double)width;
+ yScale = (double)imgHeight2 / (double)height;
+ if (yScale < xScale) {
+@@ -3038,8 +3263,8 @@
+ }
+ // center
+ if (tx0 >= 0 && ty0 >= 0) {
+- tx += rotate == 0 ? tx0 : ty0;
+- ty += rotate == 0 ? ty0 : -tx0;
++ tx += (rotate == 0 || rotate == 180) ? tx0 : ty0;
++ ty += (rotate == 0 || rotate == 180) ? ty0 : -tx0;
+ } else if (globalParams->getPSCenter()) {
+ if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
+ tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2;
+@@ -3049,22 +3274,21 @@
+ ty += (imgHeight2 - yScale * height) / 2;
+ }
+ }
+- tx += rotate == 0 ? imgLLX : imgLLY;
+- ty += rotate == 0 ? imgLLY : -imgLLX;
++ tx += (rotate == 0 || rotate == 180) ? imgLLX : imgLLY;
++ ty += (rotate == 0 || rotate == 180) ? imgLLY : -imgLLX;
+ if (tx != 0 || ty != 0) {
+ writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty);
+ }
+ if (xScale != 1 || yScale != 1) {
+ writePSFmt("{0:.6f} {1:.6f} scale\n", xScale, yScale);
+ }
+ if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
+ writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re W\n",
+ clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0);
+ } else {
+ writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1);
+ }
+
+- writePS("%%EndPageSetup\n");
+ ++seqPage;
+ break;
+
+@@ -3101,6 +3325,18 @@
+ rotate = 0;
+ break;
+ }
++
++ if (customCodeCbk) {
++ if ((s = (*customCodeCbk)(this, psOutCustomPageSetup, pageNum,
++ customCodeCbkData))) {
++ writePS(s->getCString());
++ delete s;
++ }
++ }
++
++ if (mode == psModePS) {
++ writePS("%%EndPageSetup\n");
++ }
+ }
+
+ void PSOutputDev::endPage() {
+@@ -3458,25 +3693,33 @@
++void PSOutputDev::saveTextPos(GfxState *state) {
++ writePS("currentpoint\n");
++}
++
++void PSOutputDev::restoreTextPos(GfxState *state) {
++ writePS("m\n");
++}
++
+ void PSOutputDev::stroke(GfxState *state) {
+ doPath(state->getPath());
+- if (t3String) {
+- // if we're construct a cacheable Type 3 glyph, we need to do
++ if (inType3Char && t3FillColorOnly) {
++ // if we're constructing a cacheable Type 3 glyph, we need to do
+ // everything in the fill color
+ writePS("Sf\n");
+ } else {
+@@ -3494,19 +3737,19 @@
+ writePS("f*\n");
+ }
+
+@@ -3526,34 +3769,37 @@
+ box.y1 = bbox[1];
+ box.x2 = bbox[2];
+ box.y2 = bbox[3];
+ gfx = new Gfx(doc, this, resDict, &box, NULL);
+ writePS("/x {\n");
+ if (paintType == 2) {
+ writePSFmt("{0:.6g} 0 {1:.6g} {2:.6g} {3:.6g} {4:.6g} setcachedevice\n",
+ xStep, bbox[0], bbox[1], bbox[2], bbox[3]);
++ t3FillColorOnly = gTrue;
+ } else {
+ if (x1 - 1 <= x0) {
+ writePS("1 0 setcharwidth\n");
+ } else {
+ writePSFmt("{0:.6g} 0 setcharwidth\n", xStep);
+ }
++ t3FillColorOnly = gFalse;
+ }
+ inType3Char = gTrue;
+ ++numTilingPatterns;
+- gfx->display(str);
++ gfx2->display(str);
+ --numTilingPatterns;
+ inType3Char = gFalse;
+ writePS("} def\n");
+- delete gfx;
++ delete gfx2;
+ writePS("end\n");
+ writePS("currentdict end\n");
+ writePSFmt("/xpdfTile{0:d} exch definefont pop\n", numTilingPatterns);
+
+ // draw the tiles
+ writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns);
++ writePS("fCol\n");
+ writePSFmt("gsave [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
+ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ writePSFmt("{0:d} 1 {1:d} {{ {2:.6g} exch {3:.6g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n",
+ y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1);
+ writePS("grestore\n");
+ }
+@@ -3698,7 +3944,10 @@
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, r0, x1, y1, r1, t0, t1;
+ double xa, ya, ra;
+- double sz, xz, yz, sMin, sMax, sa, ta;
++ double sz, sMin, sMax, h, ta;
++ double sLeft, sRight, sTop, sBottom, sZero, sDiag;
++ GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero;
++ GBool haveSMin, haveSMax;
+ double theta, alpha, a1, a2;
+ GBool enclosed;
+ int i;
+@@ -3717,19 +3966,23 @@
+
+ // Compute the point at which r(s) = 0; check for the enclosed
+ // circles case; and compute the angles for the tangent lines.
+- if (r0 == r1) {
+- enclosed = x0 == x1 && y0 == y1;
++ h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
++ 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) {
++ enclosed = gTrue;
++ theta = 0; // make gcc happy
++ sz = 0; // make gcc happy
+ } else {
++ enclosed = gFalse;
+ sz = -r0 / (r1 - r0);
+- xz = x0 + sz * (x1 - x0);
+- yz = y0 + sz * (y1 - y0);
+- enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
+- theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
+- if (r0 > r1) {
+- theta = -theta;
+- }
++ theta = asin((r1 - r0) / h);
+ }
+ if (enclosed) {
+ a1 = 0;
+@@ -3749,80 +4002,122 @@
+ sMin = 0;
+ sMax = 1;
+ } else {
+- sMin = 1;
+- sMax = 0;
+- // solve for x(s) + r(s) = xMin
+- if ((x1 + r1) - (x0 + r0) != 0) {
+- sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
+- if (sa < sMin) {
+- sMin = sa;
+- } else if (sa > sMax) {
+- sMax = sa;
+- }
+- }
+- // solve for x(s) - r(s) = xMax
+- if ((x1 - r1) - (x0 - r0) != 0) {
+- sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
+- if (sa < sMin) {
+- sMin = sa;
+- } else if (sa > sMax) {
+- sMax = sa;
+- }
+- }
+- // solve for y(s) + r(s) = yMin
+- if ((y1 + r1) - (y0 + r0) != 0) {
+- sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
+- if (sa < sMin) {
+- sMin = sa;
+- } else if (sa > sMax) {
+- sMax = sa;
+- }
+- }
+- // solve for y(s) - r(s) = yMax
+- if ((y1 - r1) - (y0 - r0) != 0) {
+- sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
+- if (sa < sMin) {
+- sMin = sa;
+- } else if (sa > sMax) {
+- sMax = sa;
+- }
+- }
+- // check against sz
+- if (r0 < r1) {
+- if (sMin < sz) {
+- sMin = sz;
+- }
+- } else if (r0 > r1) {
+- if (sMax > sz) {
+- sMax = sz;
+- }
++ // solve x(sLeft) + r(sLeft) = xMin
++ if ((haveSLeft = fabs((x1 + r1) - (x0 + r0)) > 0.000001)) {
++ sLeft = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
++ } else {
++ sLeft = 0; // make gcc happy
++ }
++ // solve x(sRight) - r(sRight) = xMax
++ if ((haveSRight = fabs((x1 - r1) - (x0 - r0)) > 0.000001)) {
++ sRight = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
++ } else {
++ sRight = 0; // make gcc happy
++ }
++ // solve y(sBottom) + r(sBottom) = yMin
++ if ((haveSBottom = fabs((y1 + r1) - (y0 + r0)) > 0.000001)) {
++ sBottom = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
++ } else {
++ sBottom = 0; // make gcc happy
++ }
++ // solve y(sTop) - r(sTop) = yMax
++ if ((haveSTop = fabs((y1 - r1) - (y0 - r0)) > 0.000001)) {
++ sTop = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
++ } else {
++ sTop = 0; // make gcc happy
++ }
++ // solve r(sZero) = 0
++ if ((haveSZero = fabs(r1 - r0) > 0.000001)) {
++ sZero = -r0 / (r1 - r0);
++ } else {
++ sZero = 0; // make gcc happy
++ }
++ // solve r(sDiag) = sqrt((xMax-xMin)^2 + (yMax-yMin)^2)
++ if (haveSZero) {
++ sDiag = (sqrt((xMax - xMin) * (xMax - xMin) +
++ (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
++ } else {
++ sDiag = 0; // make gcc happy
+ }
+- // check the 'extend' flags
+- if (!shading->getExtend0() && sMin < 0) {
++ // compute sMin
++ if (shading->getExtend0()) {
++ sMin = 0;
++ haveSMin = gFalse;
++ if (x0 < x1 && haveSLeft && sLeft < 0) {
++ sMin = sLeft;
++ haveSMin = gTrue;
++ } else if (x0 > x1 && haveSRight && sRight < 0) {
++ sMin = sRight;
++ haveSMin = gTrue;
++ }
++ if (y0 < y1 && haveSBottom && sBottom < 0) {
++ if (!haveSMin || sBottom > sMin) {
++ sMin = sBottom;
++ haveSMin = gTrue;
++ }
++ } else if (y0 > y1 && haveSTop && sTop < 0) {
++ if (!haveSMin || sTop > sMin) {
++ sMin = sTop;
++ haveSMin = gTrue;
++ }
++ }
++ if (haveSZero && sZero < 0) {
++ if (!haveSMin || sZero > sMin) {
++ sMin = sZero;
++ }
++ }
++ } else {
+ sMin = 0;
+ }
+- if (!shading->getExtend1() && sMax > 1) {
++ // compute sMax
++ if (shading->getExtend1()) {
++ sMax = 1;
++ haveSMax = gFalse;
++ if (x1 < x0 && haveSLeft && sLeft > 1) {
++ sMax = sLeft;
++ haveSMax = gTrue;
++ } else if (x1 > x0 && haveSRight && sRight > 1) {
++ sMax = sRight;
++ haveSMax = gTrue;
++ }
++ if (y1 < y0 && haveSBottom && sBottom > 1) {
++ if (!haveSMax || sBottom < sMax) {
++ sMax = sBottom;
++ haveSMax = gTrue;
++ }
++ } else if (y1 > y0 && haveSTop && sTop > 1) {
++ if (!haveSMax || sTop < sMax) {
++ sMax = sTop;
++ haveSMax = gTrue;
++ }
++ }
++ if (haveSZero && sDiag > 1) {
++ if (!haveSMax || sDiag < sMax) {
++ sMax = sDiag;
++ }
++ }
++ } else {
+ sMax = 1;
+ }
+ }
+
+ // generate the PS code
+@@ -3970,15 +4265,16 @@
+ GString *s2;
+- double dx, dy, dx2, dy2, originX, originY;
++ double dx, dy, originX, originY;
+ char *p;
+ UnicodeMap *uMap;
+ CharCode code;
+ Unicode u[8];
+ char buf[8];
+- int len, nChars, uLen, n, m, i, j;
++ double *dxdy;
++ int dxdySize, len, nChars, uLen, n, m, i, j;
+
+ // check for invisible text -- this is used by Acrobat Capture
+ if (state->getRender() == 3) {
+@@ -4003,6 +4299,10 @@
+ for (i = 0; i < font16EncLen; ++i) {
+ if (font->getID()->num == font16Enc[i].fontID.num &&
+ font->getID()->gen == font16Enc[i].fontID.gen) {
++ if (!font16Enc[i].enc) {
++ // font substitution failed, so don't output any text
++ return;
++ }
+ uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
+ break;
+ }
+@@ -4019,63 +4319,89 @@
+ }
+ }
+
+- // compute width of chars in string, ignoring char spacing and word
+- // spacing -- the Tj operator will adjust for the metrics of the
+- // font that's actually used
+- dx = dy = 0;
++ // compute the positioning (dx, dy) for each char in the string
+ nChars = 0;
+ p = s->getCString();
+ len = s->getLength();
+ s2 = new GString();
++ dxdySize = font->isCIDFont() ? 8 : s->getLength();
++ dxdy = (double *)gmallocn(2 * dxdySize, sizeof(double));
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
+- &dx2, &dy2, &originX, &originY);
++ &dx, &dy, &originX, &originY);
++ dx *= state->getFontSize();
++ dy *= state->getFontSize();
++ if (wMode) {
++ dy += state->getCharSpace();
++ if (n == 1 && *p == ' ') {
++ dy += state->getWordSpace();
++ }
++ } else {
++ dx += state->getCharSpace();
++ if (n == 1 && *p == ' ') {
++ dx += state->getWordSpace();
++ }
++ }
++ dx *= state->getHorizScaling();
+ if (font->isCIDFont()) {
+ if (uMap) {
++ if (nChars + uLen > dxdySize) {
++ do {
++ dxdySize *= 2;
++ } while (nChars + uLen > dxdySize);
++ dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double));
++ }
+ for (i = 0; i < uLen; ++i) {
+ m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
+ for (j = 0; j < m; ++j) {
+ s2->append(buf[j]);
+ }
++ //~ this really needs to get the number of chars in the target
++ //~ encoding - which may be more than the number of Unicode
++ //~ chars
++ dxdy[2 * nChars] = dx;
++ dxdy[2 * nChars + 1] = dy;
++ ++nChars;
+ }
+- //~ this really needs to get the number of chars in the target
+- //~ encoding - which may be more than the number of Unicode
+- //~ chars
+- nChars += uLen;
+ } else {
++ if (nChars + 1 > dxdySize) {
++ dxdySize *= 2;
++ dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double));
++ }
+ s2->append((char)((code >> 8) & 0xff));
+ s2->append((char)(code & 0xff));
++ dxdy[2 * nChars] = dx;
++ dxdy[2 * nChars + 1] = dy;
+ ++nChars;
+ }
+ } else {
+ if (!codeToGID || codeToGID[code] >= 0) {
+ s2->append((char)code);
++ dxdy[2 * nChars] = dx;
++ dxdy[2 * nChars + 1] = dy;
++ ++nChars;
+ }
+ }
+- dx += dx2;
+- dy += dy2;
+ p += n;
+ len -= n;
+ }
+- dx *= state->getFontSize() * state->getHorizScaling();
+- dy *= state->getFontSize();
+ if (uMap) {
+ uMap->decRefCnt();
+ }
+
+- if (s2->getLength() > 0) {
++ if (nChars > 0) {
+ writePSString(s2);
+- if (font->isCIDFont()) {
+- if (wMode) {
+- writePSFmt(" {0:d} {1:.4g} Tj16V\n", nChars, dy);
+- } else {
+- writePSFmt(" {0:d} {1:.4g} Tj16\n", nChars, dx);
++ writePS("\n[");
++ for (i = 0; i < 2 * nChars; ++i) {
++ if (i > 0) {
++ writePS("\n");
+ }
+- } else {
+- writePSFmt(" {0:.4g} Tj\n", dx);
++ writePSFmt("{0:.6g}", dxdy[i]);
+ }
++ writePS("] Tj\n");
+ }
++ gfree(dxdy);
+ delete s2;
+
+ if (state->getRender() & 4) {
+@@ -4730,24 +5056,32 @@
+
+ // data source
+ if (mode == psModeForm || inType3Char || preload) {
+- writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
++ writePS(" /DataSource { pdfImStr }\n");
+ } else {
+ writePS(" /DataSource currentfile\n");
+ }
+
+ // filters
+- s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
+- " ");
+- if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
+- inlineImg || !s) {
+- useRLE = gTrue;
+- useASCII = !(mode == psModeForm || inType3Char || preload);
++ if ((mode == psModeForm || inType3Char || preload) &&
++ globalParams->getPSUncompressPreloadedImages()) {
++ s = NULL;
++ useRLE = gFalse;
+ useCompressed = gFalse;
++ useASCII = gFalse;
+ } else {
+- useRLE = gFalse;
+- useASCII = str->isBinary() &&
+- !(mode == psModeForm || inType3Char || preload);
+- useCompressed = gTrue;
++ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
++ " ");
++ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
++ inlineImg || !s) {
++ useRLE = gTrue;
++ useASCII = !(mode == psModeForm || inType3Char || preload);
++ useCompressed = gFalse;
++ } else {
++ useRLE = gFalse;
++ useASCII = str->isBinary() &&
++ !(mode == psModeForm || inType3Char || preload);
++ useCompressed = gTrue;
++ }
+ }
+ if (useASCII) {
+ writePSFmt(" /ASCII{0:s}Decode filter\n",
+@@ -4872,6 +5206,7 @@
+ int n, numComps;
+ GBool useRLE, useASCII, useASCIIHex, useCompressed;
+ GBool maskUseRLE, maskUseASCII, maskUseCompressed;
++ GString *maskFilters;
+ GfxSeparationColorSpace *sepCS;
+ GfxColor color;
+ GfxCMYK cmyk;
+@@ -4881,6 +5216,83 @@
+ useASCIIHex = globalParams->getPSASCIIHex();
+ useRLE = useASCII = useCompressed = gFalse; // make gcc happy
+ maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy
++ maskFilters = NULL; // make gcc happy
++
++ // explicit masking
++ if (maskStr) {
++
++ // mask data source
++ if ((mode == psModeForm || inType3Char || preload) &&
++ globalParams->getPSUncompressPreloadedImages()) {
++ s = NULL;
++ maskUseRLE = gFalse;
++ maskUseCompressed = gFalse;
++ maskUseASCII = gFalse;
++ } else {
++ s = maskStr->getPSFilter(3, " ");
++ if (!s) {
++ maskUseRLE = gTrue;
++ maskUseASCII = !(mode == psModeForm || inType3Char || preload);
++ maskUseCompressed = gFalse;
++ } else {
++ maskUseRLE = gFalse;
++ maskUseASCII = maskStr->isBinary() &&
++ !(mode == psModeForm || inType3Char || preload);
++ maskUseCompressed = gTrue;
++ }
++ }
++ maskFilters = new GString();
++ if (maskUseASCII) {
++ maskFilters->appendf(" /ASCII{0:s}Decode filter\n",
++ useASCIIHex ? "Hex" : "85");
++ }
++ if (maskUseRLE) {
++ maskFilters->append(" /RunLengthDecode filter\n");
++ }
++ if (maskUseCompressed) {
++ maskFilters->append(s);
++ }
++ if (s) {
++ delete s;
++ }
++ if (mode == psModeForm || inType3Char || preload) {
++ writePSFmt("MaskData_{0:d}_{1:d} pdfMaskInit\n",
++ ref->getRefNum(), ref->getRefGen());
++ } else {
++ writePS("currentfile\n");
++ writePS(maskFilters->getCString());
++ writePS("pdfMask\n");
++
++ // add RunLengthEncode and ASCIIHex/85 encode filters
++ if (maskUseCompressed) {
++ maskStr = maskStr->getUndecodedStream();
++ }
++ if (maskUseRLE) {
++ maskStr = new RunLengthEncoder(maskStr);
++ }
++ if (maskUseASCII) {
++ if (useASCIIHex) {
++ maskStr = new ASCIIHexEncoder(maskStr);
++ } else {
++ maskStr = new ASCII85Encoder(maskStr);
++ }
++ }
++
++ // copy the stream data
++ maskStr->reset();
++ while ((c = maskStr->getChar()) != EOF) {
++ writePSChar(c);
++ }
++ maskStr->close();
++ writePSChar('\n');
++ writePS("%-EOD-\n");
++
++ // delete encoders
++ if (maskUseRLE || maskUseASCII) {
++ delete maskStr;
++ }
++ }
++ }
+
+ // color space
+ if (colorMap) {
+@@ -5015,24 +5427,32 @@
+
+ // data source
+ if (mode == psModeForm || inType3Char || preload) {
+- writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
++ writePS(" /DataSource { pdfImStr }\n");
+ } else {
+ writePS(" /DataSource currentfile\n");
+ }
+
+ // filters
+- s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
+- " ");
+- if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
+- inlineImg || !s) {
+- useRLE = gTrue;
+- useASCII = !(mode == psModeForm || inType3Char || preload);
++ if ((mode == psModeForm || inType3Char || preload) &&
++ globalParams->getPSUncompressPreloadedImages()) {
++ s = NULL;
++ useRLE = gFalse;
+ useCompressed = gFalse;
++ useASCII = gFalse;
+ } else {
+- useRLE = gFalse;
+- useASCII = str->isBinary() &&
+- !(mode == psModeForm || inType3Char || preload);
+- useCompressed = gTrue;
++ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
++ " ");
++ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
++ inlineImg || !s) {
++ useRLE = gTrue;
++ useASCII = !(mode == psModeForm || inType3Char || preload);
++ useCompressed = gFalse;
++ } else {
++ useRLE = gFalse;
++ useASCII = str->isBinary() &&
++ !(mode == psModeForm || inType3Char || preload);
++ useCompressed = gTrue;
++ }
+ }
+ if (useASCII) {
+ writePSFmt(" /ASCII{0:s}Decode filter\n",
+@@ -5065,30 +5485,13 @@
+ maskInvert ? 1 : 0, maskInvert ? 0 : 1);
+
+ // mask data source
+- writePS(" /DataSource currentfile\n");
+- s = maskStr->getPSFilter(3, " ");
+- if (!s) {
+- maskUseRLE = gTrue;
+- maskUseASCII = gTrue;
+- maskUseCompressed = gFalse;
++ if (mode == psModeForm || inType3Char || preload) {
++ writePS(" /DataSource {pdfMaskSrc}\n");
++ writePS(maskFilters->getCString());
+ } else {
+- maskUseRLE = gFalse;
+- maskUseASCII = maskStr->isBinary();
+- maskUseCompressed = gTrue;
+- }
+- if (maskUseASCII) {
+- writePSFmt(" /ASCII{0:s}Decode filter\n",
+- useASCIIHex ? "Hex" : "85");
+- }
+- if (maskUseRLE) {
+- writePS(" /RunLengthDecode filter\n");
+- }
+- if (maskUseCompressed) {
+- writePS(s->getCString());
+- }
+- if (s) {
+- delete s;
++ writePS(" /DataSource maskStream\n");
+ }
++ delete maskFilters;
+
+ writePS(">>\n");
+ writePS(">>\n");
+@@ -5116,39 +5519,6 @@
+
+ }
+
+- // explicit masking
+- if (maskStr) {
+-
+- if (maskUseCompressed) {
+- maskStr = maskStr->getUndecodedStream();
+- }
+-
+- // add RunLengthEncode and ASCIIHex/85 encode filters
+- if (maskUseRLE) {
+- maskStr = new RunLengthEncoder(maskStr);
+- }
+- if (maskUseASCII) {
+- if (useASCIIHex) {
+- maskStr = new ASCIIHexEncoder(maskStr);
+- } else {
+- maskStr = new ASCII85Encoder(maskStr);
+- }
+- }
+-
+- // copy the stream data
+- maskStr->reset();
+- while ((c = maskStr->getChar()) != EOF) {
+- writePSChar(c);
+- }
+- maskStr->close();
+- writePSChar('\n');
+-
+- // delete encoders
+- if (maskUseRLE || maskUseASCII) {
+- delete maskStr;
+- }
+- }
+-
+ // get rid of the array and index
+ if (mode == psModeForm || inType3Char || preload) {
+ writePS("pop pop\n");
+@@ -5196,6 +5566,13 @@
+ delete str;
+ }
+ }
++
++ // close the mask stream
++ if (maskStr) {
++ if (!(mode == psModeForm || inType3Char || preload)) {
++ writePS("pdfMaskEnd\n");
++ }
++ }
+ }
+
+ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
+@@ -5898,6 +6275,7 @@
+ t3URY = ury;
+ t3String = new GString();
+ writePS("q\n");
++ t3FillColorOnly = gTrue;
+ t3Cacheable = gTrue;
+ t3NeedsRestore = gTrue;
+ }
+diff -ru xpdf-3.02/xpdf/PSOutputDev.h xpdf-3.03/xpdf/PSOutputDev.h
+--- xpdf-3.02/xpdf/PSOutputDev.h 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/PSOutputDev.h 2011-08-15 23:08:53.000000000 +0200
+@@ -21,15 +21,20 @@
+ #include "GlobalParams.h"
+ #include "OutputDev.h"
+
++class GHash;
++class PDFDoc;
++class XRef;
+ class Function;
+ class GfxPath;
+ class GfxFont;
+ class GfxColorSpace;
+ class GfxSeparationColorSpace;
+ class PDFRectangle;
++struct PST1FontName;
+ struct PSFont8Info;
+ struct PSFont16Enc;
+ class PSOutCustomColor;
++class PSOutputDev;
+
+ //------------------------------------------------------------------------
+ // PSOutputDev
+@@ -48,25 +53,38 @@
+ psGeneric // write to a generic stream
+ };
+
+-typedef void (*PSOutputFunc)(void *stream, const char *data, int len);
++enum PSOutCustomCodeLocation {
++ psOutCustomDocSetup,
++ psOutCustomPageSetup
++};
++
++typedef void (*PSOutputFunc)(void *stream, const char *data, int len);
++
++typedef GString *(*PSOutCustomCodeCbk)(PSOutputDev *psOut,
++ PSOutCustomCodeLocation loc, int n,
++ void *data);
+
+ class PSOutputDev: public OutputDev {
+ public:
+
+ // Open a PostScript output file, and write the prolog.
+ PSOutputDev(char *fileName, PDFDoc *docA,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA = 0, int imgLLYA = 0,
+ int imgURXA = 0, int imgURYA = 0,
+- GBool manualCtrlA = gFalse);
++ GBool manualCtrlA = gFalse,
++ PSOutCustomCodeCbk customCodeCbkA = NULL,
++ void *customCodeCbkDataA = NULL);
+
+ // Open a PSOutputDev that will write to a generic stream.
+ PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
+ PDFDoc *docA,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA = 0, int imgLLYA = 0,
+ int imgURXA = 0, int imgURYA = 0,
+- GBool manualCtrlA = gFalse);
++ GBool manualCtrlA = gFalse,
++ PSOutCustomCodeCbk customCodeCbkA = NULL,
++ void *customCodeCbkDataA = NULL);
+
+ // Destructor -- writes the trailer and closes the file.
+ virtual ~PSOutputDev();
+@@ -171,12 +189,14 @@
+ virtual void updateHorizScaling(GfxState *state);
+ virtual void updateTextPos(GfxState *state);
+ virtual void updateTextShift(GfxState *state, double shift);
++ virtual void saveTextPos(GfxState *state);
++ virtual void restoreTextPos(GfxState *state);
+
+ //----- path painting
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
+@@ -244,10 +264,10 @@
+ private:
+
+ void init(PSOutputFunc outputFuncA, void *outputStreamA,
+ PSFileType fileTypeA, PDFDoc *docA,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool manualCtrlA);
+@@ -256,14 +282,20 @@
+ void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName);
+ void setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, GString *psName);
+ void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName);
+- void setupExternalTrueTypeFont(GfxFont *font, GString *psName);
++ void setupExternalTrueTypeFont(GfxFont *font, GString *fileName,
++ GString *psName);
+ void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName);
+ void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName,
+ GBool needVerticalMetrics);
++ void setupExternalCIDTrueTypeFont(GfxFont *font,
++ GString *fileName,
++ GString *psName,
++ GBool needVerticalMetrics);
+ void setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, GString *psName);
+ void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict);
++ GString *makePSFontName(GfxFont *font, Ref *id);
+ void setupImages(Dict *resDict);
+- void setupImage(Ref id, Stream *str);
++ void setupImage(Ref id, Stream *str, GBool mask);
+ void setupForms(Dict *resDict);
+ void setupForm(Ref id, Object *strObj);
+ void addProcessColor(double c, double m, double y, double k);
+@@ -308,6 +335,7 @@
+ PSOutMode mode; // PostScript mode (PS, EPS, form)
+ int paperWidth; // width of paper, in pts
+ int paperHeight; // height of paper, in pts
++ GBool paperMatch; // true if paper size is set to match each page
+ int imgLLX, imgLLY, // imageable area, in pts
+ imgURX, imgURY;
+ GBool preload; // load all images into memory, and
+@@ -322,20 +350,21 @@
+ void *underlayCbkData;
+ void (*overlayCbk)(PSOutputDev *psOut, void *data);
+ void *overlayCbkData;
++ GString *(*customCodeCbk)(PSOutputDev *psOut,
++ PSOutCustomCodeLocation loc, int n,
++ void *data);
++ void *customCodeCbkData;
+
+ PDFDoc *doc;
+ XRef *xref; // the xref table for this PDF file
+
+ Ref *fontIDs; // list of object IDs of all used fonts
+ int fontIDLen; // number of entries in fontIDs array
+ int fontIDSize; // size of fontIDs array
+- Ref *fontFileIDs; // list of object IDs of all embedded fonts
+- int fontFileIDLen; // number of entries in fontFileIDs array
+- int fontFileIDSize; // size of fontFileIDs array
+- GString **fontFileNames; // list of names of all embedded external fonts
+- int fontFileNameLen; // number of entries in fontFileNames array
+- int fontFileNameSize; // size of fontFileNames array
+- int nextTrueTypeNum; // next unique number to append to a TrueType
+- // font name
++ GHash *fontNames; // all used font names
++ PST1FontName *t1FontNames; // font names for Type 1/1C fonts
++ int t1FontNameLen; // number of entries in t1FontNames array
++ int t1FontNameSize; // size of t1FontNames array
+ PSFont8Info *font8Info; // info for 8-bit fonts
+ int font8InfoLen; // number of entries in font8Info array
+ int font8InfoSize; // size of font8Info array
+@@ -354,6 +383,8 @@
+ int numTilingPatterns; // current number of nested tiling patterns
+ int nextFunc; // next unique number to use for a function
+
++ GList *paperSizes; // list of used paper sizes, if paperMatch
++ // is true [PSOutPaperSize]
+ double tx0, ty0; // global translation
+ double xScale0, yScale0; // global scaling
+ int rotate0; // rotation angle (0, 90, 180, 270)
+@@ -378,6 +409,7 @@
+ GString *t3String; // Type 3 content string
+ double t3WX, t3WY, // Type 3 character parameters
+ t3LLX, t3LLY, t3URX, t3URY;
++ GBool t3FillColorOnly; // operators should only use the fill color
+ GBool t3Cacheable; // cleared if char is not cacheable
+ GBool t3NeedsRestore; // set if a 'q' operator was issued
+
+@@ -388,7 +420,6 @@
+
+ GBool ok; // set up ok?
+
+-
+ friend class WinPDFPrinter;
+ };
+
+diff -ru xpdf-3.02/xpdf/SplashOutputDev.cc xpdf-3.03/xpdf/SplashOutputDev..cc
+--- xpdf-3.02/xpdf/SplashOutputDev.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/SplashOutputDev.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -14,14 +14,18 @@
+
+ #include <string.h>
+ #include <math.h>
++#include <limits.h>
+ #include "gfile.h"
+ #include "GlobalParams.h"
+ #include "Error.h"
+ #include "Object.h"
++#include "Gfx.h"
+ #include "GfxFont.h"
+ #include "Link.h"
+ #include "CharCodeToUnicode.h"
+ #include "FontEncodingTables.h"
++#include "BuiltinFont.h"
++#include "BuiltinFontTables.h"
+ #include "FoFiTrueType.h"
+ #include "SplashBitmap.h"
+ #include "SplashGlyphBitmap.h"
+@@ -45,6 +49,13 @@
+
+ //------------------------------------------------------------------------
+
++// Type 3 font cache size parameters
++#define type3FontCacheAssoc 8
++#define type3FontCacheMaxSets 8
++#define type3FontCacheSize (128*1024)
++
++//------------------------------------------------------------------------
++
+ // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
+ static inline Guchar div255(int x) {
+ return (Guchar)((x + (x >> 8) + 0x80) >> 8);
+@@ -180,64 +191,100 @@
+ }
+ }
+
+-static void cvtRGBToHSV(Guchar r, Guchar g, Guchar b, int *h, int *s, int *v) {
+- int cmax, cmid, cmin, x;
++static int getLum(int r, int g, int b) {
++ return (int)(0.3 * r + 0.59 * g + 0.11 * b);
++}
+
+- if (r >= g) {
+- if (g >= b) { x = 0; cmax = r; cmid = g; cmin = b; }
+- else if (b >= r) { x = 4; cmax = b; cmid = r; cmin = g; }
+- else { x = 5; cmax = r; cmid = b; cmin = g; }
+- } else {
+- if (r >= b) { x = 1; cmax = g; cmid = r; cmin = b; }
+- else if (g >= b) { x = 2; cmax = g; cmid = b; cmin = r; }
+- else { x = 3; cmax = b; cmid = g; cmin = r; }
+- }
+- if (cmax == cmin) {
+- *h = *s = 0;
++static int getSat(int r, int g, int b) {
++ int rgbMin, rgbMax;
++
++ rgbMin = rgbMax = r;
++ if (g < rgbMin) {
++ rgbMin = g;
++ } else if (g > rgbMax) {
++ rgbMax = g;
++ }
++ if (b < rgbMin) {
++ rgbMin = b;
++ } else if (b > rgbMax) {
++ rgbMax = b;
++ }
++ return rgbMax - rgbMin;
++}
++
++static void clipColor(int rIn, int gIn, int bIn,
++ Guchar *rOut, Guchar *gOut, Guchar *bOut) {
++ int lum, rgbMin, rgbMax;
++
++ lum = getLum(rIn, gIn, bIn);
++ rgbMin = rgbMax = rIn;
++ if (gIn < rgbMin) {
++ rgbMin = gIn;
++ } else if (gIn > rgbMax) {
++ rgbMax = gIn;
++ }
++ if (bIn < rgbMin) {
++ rgbMin = bIn;
++ } else if (bIn > rgbMax) {
++ rgbMax = bIn;
++ }
++ if (rgbMin < 0) {
++ *rOut = (Guchar)(lum + ((rIn - lum) * lum) / (lum - rgbMin));
++ *gOut = (Guchar)(lum + ((gIn - lum) * lum) / (lum - rgbMin));
++ *bOut = (Guchar)(lum + ((bIn - lum) * lum) / (lum - rgbMin));
++ } else if (rgbMax > 255) {
++ *rOut = (Guchar)(lum + ((rIn - lum) * (255 - lum)) / (rgbMax - lum));
++ *gOut = (Guchar)(lum + ((gIn - lum) * (255 - lum)) / (rgbMax - lum));
++ *bOut = (Guchar)(lum + ((bIn - lum) * (255 - lum)) / (rgbMax - lum));
+ } else {
+- *h = x * 60;
+- if (x & 1) {
+- *h += ((cmax - cmid) * 60) / (cmax - cmin);
+- } else {
+- *h += ((cmid - cmin) * 60) / (cmax - cmin);
+- }
+- *s = (255 * (cmax - cmin)) / cmax;
++ *rOut = rIn;
++ *gOut = gIn;
++ *bOut = bIn;
+ }
+- *v = cmax;
+ }
+
+-static void cvtHSVToRGB(int h, int s, int v, Guchar *r, Guchar *g, Guchar *b) {
+- int x, f, cmax, cmid, cmin;
++static void setLum(Guchar rIn, Guchar gIn, Guchar bIn, int lum,
++ Guchar *rOut, Guchar *gOut, Guchar *bOut) {
++ int d;
++
++ d = lum - getLum(rIn, gIn, bIn);
++ clipColor(rIn + d, gIn + d, bIn + d, rOut, gOut, bOut);
++}
++
++static void setSat(Guchar rIn, Guchar gIn, Guchar bIn, int sat,
++ Guchar *rOut, Guchar *gOut, Guchar *bOut) {
++ int rgbMin, rgbMid, rgbMax;
++ Guchar *minOut, *midOut, *maxOut;
+
+- if (s == 0) {
+- *r = *g = *b = v;
++ if (rIn < gIn) {
++ rgbMin = rIn; minOut = rOut;
++ rgbMid = gIn; midOut = gOut;
+ } else {
+- x = h / 60;
+- f = h % 60;
+- cmax = v;
+- if (x & 1) {
+- cmid = div255(v * 255 - ((s * f) / 60));
+- } else {
+- cmid = div255(v * (255 - ((s * (60 - f)) / 60)));
+- }
+- cmin = div255(v * (255 - s));
+- switch (x) {
+- case 0: *r = cmax; *g = cmid; *b = cmin; break;
+- case 1: *g = cmax; *r = cmid; *b = cmin; break;
+- case 2: *g = cmax; *b = cmid; *r = cmin; break;
+- case 3: *b = cmax; *g = cmid; *r = cmin; break;
+- case 4: *b = cmax; *r = cmid; *g = cmin; break;
+- case 5: *r = cmax; *b = cmid; *g = cmin; break;
+- }
++ rgbMin = gIn; minOut = gOut;
++ rgbMid = rIn; midOut = rOut;
+ }
++ if (bIn > rgbMid) {
++ rgbMax = bIn; maxOut = bOut;
++ } else if (bIn > rgbMin) {
++ rgbMax = rgbMid; maxOut = midOut;
++ rgbMid = bIn; midOut = bOut;
++ } else {
++ rgbMax = rgbMid; maxOut = midOut;
++ rgbMid = rgbMin; midOut = minOut;
++ rgbMin = bIn; minOut = bOut;
++ }
++ if (rgbMax > rgbMin) {
++ *midOut = (Guchar)((rgbMid - rgbMin) * sat) / (rgbMax - rgbMin);
++ *maxOut = (Guchar)sat;
++ } else {
++ *midOut = *maxOut = 0;
++ }
++ *minOut = 0;
+ }
+
+ static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+- int hs, ss, vs, hd, sd, vd;
+-#if SPLASH_CMYK
+- Guchar r, g, b;
+-#endif
++ Guchar r0, g0, b0, r1, g1, b1;
+
+ switch (cm) {
+ case splashModeMono1:
+@@ -246,25 +293,22 @@
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+- cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
+- cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
+- cvtHSVToRGB(hs, sd, vd, &blend[0], &blend[1], &blend[2]);
++ setSat(src[0], src[1], src[2], getSat(dest[0], dest[1], dest[2]),
++ &r0, &g0, &b0);
++ setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]),
++ &blend[0], &blend[1], &blend[2]);
+ break;
+ #if SPLASH_CMYK
+ case splashModeCMYK8:
+- //~ (0xff - ...) should be clipped
+- cvtRGBToHSV(0xff - (src[0] + src[3]),
+- 0xff - (src[1] + src[3]),
+- 0xff - (src[2] + src[3]), &hs, &ss, &vs);
+- cvtRGBToHSV(0xff - (dest[0] + dest[3]),
+- 0xff - (dest[1] + dest[3]),
+- 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
+- cvtHSVToRGB(hs, sd, vd, &r, &g, &b);
+- //~ should do black generation
+- blend[0] = 0xff - r;
+- blend[1] = 0xff - g;
+- blend[2] = 0xff - b;
+- blend[3] = 0;
++ // NB: inputs have already been converted to additive mode
++ setSat(src[0], src[1], src[2], getSat(dest[0], dest[1], dest[2]),
++ &r0, &g0, &b0);
++ setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]),
++ &r1, &g1, &b1);
++ blend[0] = r1;
++ blend[1] = g1;
++ blend[2] = b1;
++ blend[3] = dest[3];
+ break;
+ #endif
+ }
+@@ -273,10 +317,7 @@
+ static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend,
+ SplashColorMode cm) {
+- int hs, ss, vs, hd, sd, vd;
+-#if SPLASH_CMYK
+- Guchar r, g, b;
+-#endif
++ Guchar r0, g0, b0, r1, g1, b1;
+
+ switch (cm) {
+ case splashModeMono1:
+@@ -285,25 +326,22 @@
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+- cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
+- cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
+- cvtHSVToRGB(hd, ss, vd, &blend[0], &blend[1], &blend[2]);
++ setSat(dest[0], dest[1], dest[2], getSat(src[0], src[1], src[2]),
++ &r0, &g0, &b0);
++ setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]),
++ &blend[0], &blend[1], &blend[2]);
+ break;
+ #if SPLASH_CMYK
+ case splashModeCMYK8:
+- //~ (0xff - ...) should be clipped
+- cvtRGBToHSV(0xff - (src[0] + src[3]),
+- 0xff - (src[1] + src[3]),
+- 0xff - (src[2] + src[3]), &hs, &ss, &vs);
+- cvtRGBToHSV(0xff - (dest[0] + dest[3]),
+- 0xff - (dest[1] + dest[3]),
+- 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
+- cvtHSVToRGB(hd, ss, vd, &r, &g, &b);
+- //~ should do black generation
+- blend[0] = 0xff - r;
+- blend[1] = 0xff - g;
+- blend[2] = 0xff - b;
+- blend[3] = 0;
++ // NB: inputs have already been converted to additive mode
++ setSat(dest[0], dest[1], dest[2], getSat(src[0], src[1], src[2]),
++ &r0, &g0, &b0);
++ setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]),
++ &r1, &g1, &b1);
++ blend[0] = r1;
++ blend[1] = g1;
++ blend[2] = b1;
++ blend[3] = dest[3];
+ break;
+ #endif
+ }
+@@ -311,7 +349,6 @@
+
+ static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+- int hs, ss, vs, hd, sd, vd;
+ #if SPLASH_CMYK
+ Guchar r, g, b;
+ #endif
+@@ -323,25 +360,18 @@
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+- cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
+- cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
+- cvtHSVToRGB(hs, ss, vd, &blend[0], &blend[1], &blend[2]);
++ setLum(src[0], src[1], src[2], getLum(dest[0], dest[1], dest[2]),
++ &blend[0], &blend[1], &blend[2]);
+ break;
+ #if SPLASH_CMYK
+ case splashModeCMYK8:
+- //~ (0xff - ...) should be clipped
+- cvtRGBToHSV(0xff - (src[0] + src[3]),
+- 0xff - (src[1] + src[3]),
+- 0xff - (src[2] + src[3]), &hs, &ss, &vs);
+- cvtRGBToHSV(0xff - (dest[0] + dest[3]),
+- 0xff - (dest[1] + dest[3]),
+- 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
+- cvtHSVToRGB(hs, ss, vd, &r, &g, &b);
+- //~ should do black generation
+- blend[0] = 0xff - r;
+- blend[1] = 0xff - g;
+- blend[2] = 0xff - b;
+- blend[3] = 0;
++ // NB: inputs have already been converted to additive mode
++ setLum(src[0], src[1], src[2], getLum(dest[0], dest[1], dest[2]),
++ &r, &g, &b);
++ blend[0] = r;
++ blend[1] = g;
++ blend[2] = b;
++ blend[3] = dest[3];
+ break;
+ #endif
+ }
+@@ -350,7 +380,6 @@
+ static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend,
+ SplashColorMode cm) {
+- int hs, ss, vs, hd, sd, vd;
+ #if SPLASH_CMYK
+ Guchar r, g, b;
+ #endif
+@@ -362,25 +391,18 @@
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+- cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
+- cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
+- cvtHSVToRGB(hd, sd, vs, &blend[0], &blend[1], &blend[2]);
++ setLum(dest[0], dest[1], dest[2], getLum(src[0], src[1], src[2]),
++ &blend[0], &blend[1], &blend[2]);
+ break;
+ #if SPLASH_CMYK
+ case splashModeCMYK8:
+- //~ (0xff - ...) should be clipped
+- cvtRGBToHSV(0xff - (src[0] + src[3]),
+- 0xff - (src[1] + src[3]),
+- 0xff - (src[2] + src[3]), &hs, &ss, &vs);
+- cvtRGBToHSV(0xff - (dest[0] + dest[3]),
+- 0xff - (dest[1] + dest[3]),
+- 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
+- cvtHSVToRGB(hd, sd, vs, &r, &g, &b);
+- //~ should do black generation
+- blend[0] = 0xff - r;
+- blend[1] = 0xff - g;
+- blend[2] = 0xff - b;
+- blend[3] = 0;
++ // NB: inputs have already been converted to additive mode
++ setLum(dest[0], dest[1], dest[2], getLum(src[0], src[1], src[2]),
++ &r, &g, &b);
++ blend[0] = r;
++ blend[1] = g;
++ blend[2] = b;
++ blend[3] = src[3];
+ break;
+ #endif
+ }
+@@ -510,21 +503,23 @@
+ glyphW = glyphWA;
+ glyphH = glyphHA;
+ validBBox = validBBoxA;
++ // sanity check for excessively large glyphs (which most likely
++ // indicate an incorrect BBox)
++ i = glyphW * glyphH;
++ if (i > 100000 || glyphW > INT_MAX / glyphH || glyphW <= 0 || glyphH <= 0) {
++ glyphW = glyphH = 100;
++ validBBox = gFalse;
++ }
+ if (aa) {
+ glyphSize = glyphW * glyphH;
+ } else {
+ glyphSize = ((glyphW + 7) >> 3) * glyphH;
+ }
+- cacheAssoc = 8;
+- if (glyphSize <= 256) {
+- cacheSets = 8;
+- } else if (glyphSize <= 512) {
+- cacheSets = 4;
+- } else if (glyphSize <= 1024) {
+- cacheSets = 2;
+- } else {
+- cacheSets = 1;
+- }
++ cacheAssoc = type3FontCacheAssoc;
++ for (cacheSets = type3FontCacheMaxSets;
++ cacheSets > 1 &&
++ cacheSets * cacheAssoc * glyphSize > type3FontCacheSize;
++ cacheSets >>= 1) ;
+ cacheData = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize);
+ cacheTags = (T3FontCacheTag *)gmallocn(cacheSets * cacheAssoc,
+ sizeof(T3FontCacheTag));
+@@ -584,6 +579,7 @@
+ colorMode = colorModeA;
+ bitmapRowPad = bitmapRowPadA;
+ bitmapTopDown = bitmapTopDownA;
++ bitmapUpsideDown = gFalse;
+ allowAntialias = allowAntialiasA;
+ vectorAntialias = allowAntialias &&
+ globalParams->getVectorAntialias() &&
+@@ -591,12 +587,15 @@
+ setupScreenParams(72.0, 72.0);
+ reverseVideo = reverseVideoA;
+ splashColorCopy(paperColor, paperColorA);
++ skipHorizText = gFalse;
++ skipRotatedText = gFalse;
+
+ xref = NULL;
+
+ bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode,
+ colorMode != splashModeMono1, bitmapTopDown);
+ splash = new Splash(bitmap, vectorAntialias, &screenParams);
++ splash->setMinLineWidth(globalParams->getMinLineWidth());
+ splash->clear(paperColor, 0);
+
+ fontEngine = NULL;
+@@ -609,6 +608,8 @@
+ textClipPath = NULL;
+
+ transpGroupStack = NULL;
++
++ nestCount = 0;
+ }
+
+ void SplashOutputDev::setupScreenParams(double hDPI, double vDPI) {
+@@ -723,15 +726,18 @@
+ bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode,
+ colorMode != splashModeMono1, bitmapTopDown);
+ }
+ splash = new Splash(bitmap, vectorAntialias, &screenParams);
++ splash->setMinLineWidth(globalParams->getMinLineWidth());
+ if (state) {
+ ctm = state->getCTM();
+ mat[0] = (SplashCoord)ctm[0];
+@@ -835,7 +841,10 @@
+ }
+
+ void SplashOutputDev::updateFlatness(GfxState *state) {
++#if 0 // Acrobat ignores the flatness setting, and always renders curves
++ // with a fairly small flatness value
+ splash->setFlatness(state->getFlatness());
++#endif
+ }
+
+ void SplashOutputDev::updateLineJoin(GfxState *state) {
+@@ -868,14 +877,24 @@
+ GfxCMYK cmyk;
+ #endif
+
+- state->getFillGray(&gray);
+- state->getFillRGB(&rgb);
++ switch (colorMode) {
++ case splashModeMono1:
++ case splashModeMono8:
++ state->getFillGray(&gray);
++ splash->setFillPattern(getColor(gray));
++ break;
++ case splashModeRGB8:
++ case splashModeBGR8:
++ state->getFillRGB(&rgb);
++ splash->setFillPattern(getColor(&rgb));
++ break;
+ #if SPLASH_CMYK
+- state->getFillCMYK(&cmyk);
+- splash->setFillPattern(getColor(gray, &rgb, &cmyk));
+-#else
+- splash->setFillPattern(getColor(gray, &rgb));
++ case splashModeCMYK8:
++ state->getFillCMYK(&cmyk);
++ splash->setFillPattern(getColor(&cmyk));
++ break;
+ #endif
++ }
+ }
+
+ void SplashOutputDev::updateStrokeColor(GfxState *state) {
+@@ -885,28 +904,41 @@
+ GfxCMYK cmyk;
+ #endif
+
+- state->getStrokeGray(&gray);
+- state->getStrokeRGB(&rgb);
++ switch (colorMode) {
++ case splashModeMono1:
++ case splashModeMono8:
++ state->getStrokeGray(&gray);
++ splash->setStrokePattern(getColor(gray));
++ break;
++ case splashModeRGB8:
++ case splashModeBGR8:
++ state->getStrokeRGB(&rgb);
++ splash->setStrokePattern(getColor(&rgb));
++ break;
+ #if SPLASH_CMYK
+- state->getStrokeCMYK(&cmyk);
+- splash->setStrokePattern(getColor(gray, &rgb, &cmyk));
+-#else
+- splash->setStrokePattern(getColor(gray, &rgb));
++ case splashModeCMYK8:
++ state->getStrokeCMYK(&cmyk);
++ splash->setStrokePattern(getColor(&cmyk));
++ break;
+ #endif
++ }
+ }
+
+-#if SPLASH_CMYK
+-SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb,
+- GfxCMYK *cmyk) {
+-#else
+-SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) {
+-#endif
+- SplashPattern *pattern;
++SplashPattern *SplashOutputDev::getColor(GfxGray gray) {
+ SplashColor color;
+- GfxColorComp r, g, b;
+
+ if (reverseVideo) {
+ gray = gfxColorComp1 - gray;
++ }
++ color[0] = colToByte(gray);
++ return new SplashSolidColor(color);
++}
++
++SplashPattern *SplashOutputDev::getColor(GfxRGB *rgb) {
++ GfxColorComp r, g, b;
++ SplashColor color;
++
++ if (reverseVideo) {
+ r = gfxColorComp1 - rgb->r;
+ g = gfxColorComp1 - rgb->g;
+ b = gfxColorComp1 - rgb->b;
+@@ -915,33 +947,58 @@
+ g = rgb->g;
+ b = rgb->b;
+ }
++ color[0] = colToByte(r);
++ color[1] = colToByte(g);
++ color[2] = colToByte(b);
++ return new SplashSolidColor(color);
++}
+
+- pattern = NULL; // make gcc happy
+- switch (colorMode) {
+- case splashModeMono1:
+- case splashModeMono8:
+- color[0] = colToByte(gray);
+- pattern = new SplashSolidColor(color);
+- break;
+- case splashModeRGB8:
+- case splashModeBGR8:
+- color[0] = colToByte(r);
+- color[1] = colToByte(g);
+- color[2] = colToByte(b);
+- pattern = new SplashSolidColor(color);
+- break;
+ #if SPLASH_CMYK
+- case splashModeCMYK8:
+- color[0] = colToByte(cmyk->c);
+- color[1] = colToByte(cmyk->m);
+- color[2] = colToByte(cmyk->y);
+- color[3] = colToByte(cmyk->k);
+- pattern = new SplashSolidColor(color);
+- break;
++SplashPattern *SplashOutputDev::getColor(GfxCMYK *cmyk) {
++ SplashColor color;
++
++ color[0] = colToByte(cmyk->c);
++ color[1] = colToByte(cmyk->m);
++ color[2] = colToByte(cmyk->y);
++ color[3] = colToByte(cmyk->k);
++ return new SplashSolidColor(color);
++}
+ #endif
+- }
+
+- return pattern;
+ }
+
+ void SplashOutputDev::updateBlendMode(GfxState *state) {
+@@ -956,35 +1013,82 @@
+ splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity());
+ }
+
+ void SplashOutputDev::updateFont(GfxState *state) {
+ needFontUpdate = gTrue;
+ }
+
+ void SplashOutputDev::doUpdateFont(GfxState *state) {
+ GfxFont *gfxFont;
++ GfxFontLoc *fontLoc;
+ GfxFontType fontType;
+ SplashOutFontFileID *id;
+ SplashFontFile *fontFile;
++ int fontNum;
+ FoFiTrueType *ff;
+ Ref embRef;
+ Object refObj, strObj;
+- GString *tmpFileName, *fileName, *substName;
++ GString *tmpFileName, *fileName;
+ FILE *tmpFile;
+ int *codeToGID;
+- DisplayFontParam *dfp;
+ CharCodeToUnicode *ctu;
+ double *textMat;
+- double m11, m12, m21, m22, w1, w2, fontSize;
++ double m11, m12, m21, m22, fontSize;
++ double w, fontScaleMin, fontScaleAvg, fontScale;
++ Gushort ww;
+ SplashCoord mat[4];
+ char *name;
+ Unicode uBuf[8];
+- int c, substIdx, n, code, cmap;
++ int c, substIdx, n, code, cmap, i;
+
+ needFontUpdate = gFalse;
+ font = NULL;
+ tmpFileName = NULL;
+ substIdx = -1;
+- dfp = NULL;
+
+ if (!(gfxFont = state->getFont())) {
+ goto err1;
+@@ -994,6 +1098,13 @@
+ goto err1;
+ }
+
++ // sanity-check the font size - skip anything larger than 10 inches
++ // (this avoids problems allocating memory for the font cache)
++ if (state->getTransformedFontSize()
++ > 10 * (state->getHDPI() + state->getVDPI())) {
++ goto err1;
++ }
++
+ // check the font file cache
+ id = new SplashOutFontFileID(gfxFont->getID());
+ if ((fontFile = fontEngine->getFontFile(id))) {
+@@ -1001,19 +1112,32 @@
+
+ } else {
+
+- // if there is an embedded font, write it to disk
+- if (gfxFont->getEmbeddedFontID(&embRef)) {
++ fileName = NULL;
++ fontNum = 0;
++
++ if (!(fontLoc = gfxFont->locateFont(xref, gFalse))) {
++ error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
++ gfxFont->getName() ? gfxFont->getName()->getCString()
++ : "(unnamed)");
++ goto err2;
++ }
++
++ // embedded font
++ if (fontLoc->locType == gfxFontLocEmbedded) {
++ gfxFont->getEmbeddedFontID(&embRef);
+ if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
+- error(-1, "Couldn't create temporary font file");
++ error(errIO, -1, "Couldn't create temporary font file");
++ delete fontLoc;
+ goto err2;
+ }
+ refObj.initRef(embRef.num, embRef.gen);
+ refObj.fetch(xref, &strObj);
+ refObj.free();
+ if (!strObj.isStream()) {
+- error(-1, "Embedded font object is wrong type");
++ error(errSyntaxError, -1, "Embedded font object is wrong type");
+ strObj.free();
+ fclose(tmpFile);
++ delete fontLoc;
+ goto err2;
+ }
+ strObj.streamReset();
+@@ -1025,94 +1149,53 @@
+ fclose(tmpFile);
+ fileName = tmpFileName;
+
+- // if there is an external font file, use it
+- } else if (!(fileName = gfxFont->getExtFontFile())) {
+-
+- // look for a display font mapping or a substitute font
+- if (gfxFont->isCIDFont()) {
+- if (((GfxCIDFont *)gfxFont)->getCollection()) {
+- dfp = globalParams->
+- getDisplayCIDFont(gfxFont->getName(),
+- ((GfxCIDFont *)gfxFont)->getCollection());
+- }
+- } else {
+- if (gfxFont->getName()) {
+- dfp = globalParams->getDisplayFont(gfxFont->getName());
+- }
+- if (!dfp) {
+- // 8-bit font substitution
+- if (gfxFont->isFixedWidth()) {
+- substIdx = 8;
+- } else if (gfxFont->isSerif()) {
+- substIdx = 4;
+- } else {
+- substIdx = 0;
+- }
+- if (gfxFont->isBold()) {
+- substIdx += 2;
+- }
+- if (gfxFont->isItalic()) {
+- substIdx += 1;
+- }
+- substName = new GString(splashOutSubstFonts[substIdx].name);
+- dfp = globalParams->getDisplayFont(substName);
+- delete substName;
+- id->setSubstIdx(substIdx);
+- }
+- }
+- if (!dfp) {
+- error(-1, "Couldn't find a font for '%s'",
+- gfxFont->getName() ? gfxFont->getName()->getCString()
+- : "(unnamed)");
+- goto err2;
+- }
+- switch (dfp->kind) {
+- case displayFontT1:
+- fileName = dfp->t1.fileName;
+- fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
+- break;
+- case displayFontTT:
+- fileName = dfp->tt.fileName;
+- fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
+- break;
++ // external font
++ } else { // gfxFontLocExternal
++ fileName = fontLoc->path;
++ fontNum = fontLoc->fontNum;
++ if (fontLoc->substIdx >= 0) {
++ id->setSubstIdx(fontLoc->substIdx);
+ }
+ }
+
+ // load the font file
+- switch (fontType) {
++ switch (fontLoc->fontType) {
+ case fontType1:
+ if (!(fontFile = fontEngine->loadType1Font(
+- id,
+- fileName->getCString(),
+- fileName == tmpFileName,
+- (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
+- error(-1, "Couldn't create a font for '%s'",
++ id,
++ fileName->getCString(),
++ fileName == tmpFileName,
++ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
++ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
++ delete fontLoc;
+ goto err2;
+ }
+ break;
+ case fontType1C:
+ if (!(fontFile = fontEngine->loadType1CFont(
+- id,
+- fileName->getCString(),
+- fileName == tmpFileName,
+- (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
+- error(-1, "Couldn't create a font for '%s'",
++ id,
++ fileName->getCString(),
++ fileName == tmpFileName,
++ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
++ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
++ delete fontLoc;
+ goto err2;
+ }
+ break;
+ case fontType1COT:
+ if (!(fontFile = fontEngine->loadOpenTypeT1CFont(
+- id,
+- fileName->getCString(),
+- fileName == tmpFileName,
+- (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
+- error(-1, "Couldn't create a font for '%s'",
++ id,
++ fileName->getCString(),
++ fileName == tmpFileName,
++ (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
++ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
++ delete fontLoc;
+ goto err2;
+ }
+ break;
+@@ -1122,18 +1205,33 @@
+ codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
+ n = 256;
+ delete ff;
++ // if we're substituting for a non-TrueType font, we need to mark
++ // all notdef codes as "do not draw" (rather than drawing TrueType
++ // notdef glyphs)
++ if (gfxFont->getType() != fontTrueType &&
++ gfxFont->getType() != fontTrueTypeOT) {
++ for (i = 0; i < 256; ++i) {
++ if (codeToGID[i] == 0) {
++ codeToGID[i] = -1;
++ }
++ }
++ }
+ } else {
+ codeToGID = NULL;
+ n = 0;
+ }
+ if (!(fontFile = fontEngine->loadTrueTypeFont(
+ id,
+- fileName->getCString(),
++ fileName->getCString(), fontNum,
+ fileName == tmpFileName,
+- codeToGID, n))) {
+- error(-1, "Couldn't create a font for '%s'",
++ codeToGID, n,
++ gfxFont->getEmbeddedFontName()
++ ? gfxFont->getEmbeddedFontName()->getCString()
++ : (char *)NULL))) {
++ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
++ delete fontLoc;
+ goto err2;
+ }
+ break;
+@@ -1143,20 +1241,32 @@
+ id,
+ fileName->getCString(),
+ fileName == tmpFileName))) {
+- error(-1, "Couldn't create a font for '%s'",
++ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
++ delete fontLoc;
+ goto err2;
+ }
+ break;
+ case fontCIDType0COT:
+ if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
+ n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
+ codeToGID = (int *)gmallocn(n, sizeof(int));
+ memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
+ n * sizeof(int));
+ } else {
+ codeToGID = NULL;
+ n = 0;
+ }
+ if (!(fontFile = fontEngine->loadOpenTypeCFFFont(
+ id,
+ codeToGID, n))) {
+ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
++ delete fontLoc;
+ goto err2;
+ }
+ break;
+@@ -1164,9 +1274,17 @@
+ case fontCIDType2OT:
+ codeToGID = NULL;
+ n = 0;
+- if (dfp) {
++ if (fontLoc->locType == gfxFontLocEmbedded) {
++ if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
++ n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
++ codeToGID = (int *)gmallocn(n, sizeof(int));
++ memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
++ n * sizeof(int));
++ }
++ } else {
+ // create a CID-to-GID mapping, via Unicode
+ if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) {
++ //~ this should use fontNum to load the correct font
+ if ((ff = FoFiTrueType::load(fileName->getCString()))) {
+ // look for a Unicode cmap
+ for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) {
+@@ -1179,12 +1297,12 @@
+ if (cmap < ff->getNumCmaps()) {
+ // map CID -> Unicode -> GID
+ n = ctu->getLength();
+- codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
++ codeToGID = (int *)gmallocn(n, sizeof(int));
+ for (code = 0; code < n; ++code) {
+ if (ctu->mapToUnicode(code, uBuf, 8) > 0) {
+ codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]);
+ } else {
+- codeToGID[code] = 0;
++ codeToGID[code] = -1;
+ }
+ }
+ }
+@@ -1192,26 +1310,24 @@
+ }
+ ctu->decRefCnt();
+ } else {
+- error(-1, "Couldn't find a mapping to Unicode for font '%s'",
++ error(errSyntaxError, -1,
++ "Couldn't find a mapping to Unicode for font '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ }
+- } else {
+- if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
+- n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
+- codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
+- memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
+- n * sizeof(Gushort));
+- }
+ }
+ if (!(fontFile = fontEngine->loadTrueTypeFont(
+ id,
+- fileName->getCString(),
++ fileName->getCString(), fontNum,
+ fileName == tmpFileName,
+- codeToGID, n))) {
+- error(-1, "Couldn't create a font for '%s'",
++ codeToGID, n,
++ gfxFont->getEmbeddedFontName()
++ ? gfxFont->getEmbeddedFontName()->getCString()
++ : (char *)NULL))) {
++ error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
++ delete fontLoc;
+ goto err2;
+ }
+ break;
+@@ -1219,6 +1335,8 @@
+ // this shouldn't happen
+ goto err2;
+ }
++
++ delete fontLoc;
+ }
+
+ // get the font matrix
+@@ -1230,26 +1348,42 @@
+ m22 = textMat[3] * fontSize;
+
+ // for substituted fonts: adjust the font matrix -- compare the
+- // width of 'm' in the original font and the substituted font
++ // widths of letters and digits (A-Z, a-z, 0-9) in the original font
++ // and the substituted font
+ substIdx = ((SplashOutFontFileID *)fontFile->getID())->getSubstIdx();
+- if (substIdx >= 0) {
++ if (substIdx >= 0 && substIdx < 12) {
++ fontScaleMin = 1;
++ fontScaleAvg = 0;
++ n = 0;
+ for (code = 0; code < 256; ++code) {
+ if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
+- name[0] == 'm' && name[1] == '\0') {
+- break;
++ name[0] && !name[1] &&
++ ((name[0] >= 'A' && name[0] <= 'Z') ||
++ (name[0] >= 'a' && name[0] <= 'z') ||
++ (name[0] >= '0' && name[0] <= '9'))) {
++ w = ((Gfx8BitFont *)gfxFont)->getWidth(code);
++ builtinFontSubst[substIdx]->widths->getWidth(name, &ww);
++ if (w > 0.01 && ww > 10) {
++ w /= ww * 0.001;
++ if (w < fontScaleMin) {
++ fontScaleMin = w;
++ }
++ fontScaleAvg += w;
++ ++n;
++ }
+ }
+ }
+- if (code < 256) {
+- w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
+- w2 = splashOutSubstFonts[substIdx].mWidth;
+- if (!gfxFont->isSymbolic()) {
+- // if real font is substantially narrower than substituted
+- // font, reduce the font size accordingly
+- if (w1 > 0.01 && w1 < 0.9 * w2) {
+- w1 /= w2;
+- m11 *= w1;
+- m21 *= w1;
+- }
++ // if real font is narrower than substituted font, reduce the font
++ // size accordingly -- this currently uses a scale factor halfway
++ // between the minimum and average computed scale factors, which
++ // is a bit of a kludge, but seems to produce mostly decent
++ // results
++ if (n) {
++ fontScaleAvg /= n;
++ if (fontScaleAvg < 1) {
++ fontScale = 0.5 * (fontScaleMin + fontScaleAvg);
++ m11 *= fontScale;
++ m12 *= fontScale;
+ }
+ }
+ }
+@@ -1375,6 +1655,18 @@
+ Unicode *u, int uLen) {
+ SplashPath *path;
+ int render;
++ GBool doFill, doStroke, doClip, strokeAdjust;
++ double m[4];
++ GBool horiz;
++
++ if (skipHorizText || skipRotatedText) {
++ state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]);
++ horiz = m[0] > 0 && fabs(m[1]) < 0.001 &&
++ fabs(m[2]) < 0.001 && m[3] < 0;
++ if ((skipHorizText && horiz) || (skipRotatedText && !horiz)) {
++ return;
++ }
++ }
+
+ // check for invisible text -- this is used by Acrobat Capture
+ render = state->getRender();
+@@ -1392,36 +1684,76 @@
+ x -= originX;
+ y -= originY;
+
+- // fill
+- if (!(render & 1)) {
+- if (!state->getFillColorSpace()->isNonMarking()) {
+- splash->fillChar((SplashCoord)x, (SplashCoord)y, code, font);
++ doFill = !(render & 1) && !state->getFillColorSpace()->isNonMarking();
++ doStroke = ((render & 3) == 1 || (render & 3) == 2) &&
++ !state->getStrokeColorSpace()->isNonMarking();
++ doClip = render & 4;
++
++ path = NULL;
++ if (doStroke || doClip) {
++ if ((path = font->getGlyphPath(code))) {
++ path->offset((SplashCoord)x, (SplashCoord)y);
+ }
+ }
+
++ // don't use stroke adjustment when stroking text -- the results
++ // tend to be ugly (because characters with horizontal upper or
++ // lower edges get misaligned relative to the other characters)
++ strokeAdjust = gFalse; // make gcc happy
++ if (doStroke) {
++ strokeAdjust = splash->getStrokeAdjust();
++ splash->setStrokeAdjust(gFalse);
++ }
++
++ // fill and stroke
++ if (doFill && doStroke) {
++ if (path) {
++ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
++ state->getOverprintMode(), state->getFillColor());
++ splash->fill(path, gFalse);
++ setOverprintMask(state->getStrokeColorSpace(),
++ state->getStrokeOverprint(),
++ state->getOverprintMode(),
++ state->getStrokeColor());
++ splash->stroke(path);
++ }
++
++ // fill
++ } else if (doFill) {
++ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
++ state->getOverprintMode(), state->getFillColor());
++ splash->fillChar((SplashCoord)x, (SplashCoord)y, code, font);
++
+ // stroke
+- if ((render & 3) == 1 || (render & 3) == 2) {
+- if (!state->getStrokeColorSpace()->isNonMarking()) {
+- if ((path = font->getGlyphPath(code))) {
+- path->offset((SplashCoord)x, (SplashCoord)y);
+- splash->stroke(path);
+- delete path;
+- }
++ } else if (doStroke) {
++ if (path) {
++ setOverprintMask(state->getStrokeColorSpace(),
++ state->getStrokeOverprint(),
++ state->getOverprintMode(),
++ state->getStrokeColor());
++ splash->stroke(path);
+ }
+ }
+
+ // clip
+- if (render & 4) {
+- if ((path = font->getGlyphPath(code))) {
+- path->offset((SplashCoord)x, (SplashCoord)y);
++ if (doClip) {
++ if (path) {
+ if (textClipPath) {
+ textClipPath->append(path);
+- delete path;
+ } else {
+ textClipPath = path;
++ path = NULL;
+ }
+ }
+ }
++
++ if (doStroke) {
++ splash->setStrokeAdjust(strokeAdjust);
++ }
++
++ if (path) {
++ delete path;
++ }
+ }
+
+ GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y,
+@@ -1433,9 +1765,20 @@
+ T3FontCache *t3Font;
+ T3GlyphStack *t3gs;
+ GBool validBBox;
++ double m[4];
++ GBool horiz;
+ double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
+ int i, j;
+
++ if (skipHorizText || skipRotatedText) {
++ state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]);
++ horiz = m[0] > 0 && fabs(m[1]) < 0.001 &&
++ fabs(m[2]) < 0.001 && m[3] < 0;
++ if ((skipHorizText && horiz) || (skipRotatedText && !horiz)) {
++ return gTrue;
++ }
++ }
++
+ if (!(gfxFont = state->getFont())) {
+ return gFalse;
+ }
+@@ -1517,10 +1860,10 @@
+ validBBox = gTrue;
+ }
+ t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3],
+- (int)floor(xMin - xt),
+- (int)floor(yMin - yt),
+- (int)ceil(xMax) - (int)floor(xMin) + 3,
+- (int)ceil(yMax) - (int)floor(yMin) + 3,
++ (int)floor(xMin - xt) - 2,
++ (int)floor(yMin - yt) - 2,
++ (int)ceil(xMax) - (int)floor(xMin) + 4,
++ (int)ceil(yMax) - (int)floor(yMin) + 4,
+ validBBox,
+ colorMode != splashModeMono1);
+ }
+@@ -1532,7 +1875,7 @@
+ for (j = 0; j < t3Font->cacheAssoc; ++j) {
+ if ((t3Font->cacheTags[i+j].mru & 0x8000) &&
+ t3Font->cacheTags[i+j].code == code) {
+- drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
++ drawType3Glyph(state, t3Font, &t3Font->cacheTags[i+j],
+ t3Font->cacheData + (i+j) * t3Font->glyphSize);
+ return gTrue;
+ }
+@@ -1547,6 +1890,8 @@
+ t3GlyphStack->cacheTag = NULL;
+ t3GlyphStack->cacheData = NULL;
+
++ haveT3Dx = gFalse;
++
+ return gFalse;
+ }
+
+@@ -1555,6 +1900,7 @@
+ double *ctm;
+
+ if (t3GlyphStack->cacheTag) {
++ --nestCount;
+ memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(),
+ t3GlyphStack->cache->glyphSize);
+ delete bitmap;
+@@ -1565,7 +1911,7 @@
+ state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
+ t3GlyphStack->origCTM4, t3GlyphStack->origCTM5);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
+- drawType3Glyph(t3GlyphStack->cache,
++ drawType3Glyph(state, t3GlyphStack->cache,
+ t3GlyphStack->cacheTag, t3GlyphStack->cacheData);
+ }
+ t3gs = t3GlyphStack;
+@@ -1574,6 +1920,7 @@
+ }
+
+ void SplashOutputDev::type3D0(GfxState *state, double wx, double wy) {
++ haveT3Dx = gTrue;
+ }
+
+ void SplashOutputDev::type3D1(GfxState *state, double wx, double wy,
+@@ -1584,6 +1931,12 @@
+ double xt, yt, xMin, xMax, yMin, yMax, x1, y1;
+ int i, j;
+
++ // ignore multiple d0/d1 operators
++ if (haveT3Dx) {
++ return;
++ }
++ haveT3Dx = gTrue;
++
+ t3Font = t3GlyphStack->cache;
+
+ // check for a valid bbox
+@@ -1662,7 +2015,7 @@
+ t3GlyphStack->origSplash->getScreen());
+ color[0] = 0;
+ splash->clear(color);
+- color[0] = 1;
++ color[0] = 0xff;
+ } else {
+ bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
+ splashModeMono8, gFalse);
+@@ -1672,18 +2025,23 @@
+ splash->clear(color);
+ color[0] = 0xff;
+ }
++ splash->setMinLineWidth(globalParams->getMinLineWidth());
+ splash->setFillPattern(new SplashSolidColor(color));
+ splash->setStrokePattern(new SplashSolidColor(color));
+ //~ this should copy other state from t3GlyphStack->origSplash?
++ //~ [this is likely the same situation as in beginTransparencyGroup()]
+ state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
+ -t3Font->glyphX, -t3Font->glyphY);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
++ ++nestCount;
+ }
+
+-void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font,
++void SplashOutputDev::drawType3Glyph(GfxState *state, T3FontCache *t3Font,
+ T3FontCacheTag *tag, Guchar *data) {
+ SplashGlyphBitmap glyph;
+
++ setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(),
++ state->getOverprintMode(), state->getFillColor());
+ glyph.x = -t3Font->glyphX;
+ glyph.y = -t3Font->glyphY;
+ glyph.w = t3Font->glyphW;
+@@ -1717,9 +2075,10 @@
+ if (imgMaskData->y == imgMaskData->height) {
+ return gFalse;
+ }
+- for (x = 0, p = imgMaskData->imgStr->getLine(), q = line;
+- x < imgMaskData->width;
+- ++x) {
++ if (!(p = imgMaskData->imgStr->getLine())) {
++ return gFalse;
++ }
++ for (x = 0, q = line; x < imgMaskData->width; ++x) {
+ *q++ = *p++ ^ imgMaskData->invert;
+ }
+ ++imgMaskData->y;
+@@ -1765,6 +2126,46 @@
+ str->close();
+ }
+
++void SplashOutputDev::setSoftMaskFromImageMask(GfxState *state,
++ Object *ref, Stream *str,
++ int width, int height,
++ GBool invert,
++ GBool inlineImg) {
++ double *ctm;
++ SplashCoord mat[6];
++ SplashOutImageMaskData imgMaskData;
++ SplashBitmap *maskBitmap;
++ Splash *maskSplash;
++ SplashColor maskColor;
++
++ ctm = state->getCTM();
++ mat[0] = ctm[0];
++ mat[1] = ctm[1];
++ mat[2] = -ctm[2];
++ mat[3] = -ctm[3];
++ mat[4] = ctm[2] + ctm[4];
++ mat[5] = ctm[3] + ctm[5];
++ imgMaskData.imgStr = new ImageStream(str, width, 1, 1);
++ imgMaskData.imgStr->reset();
++ imgMaskData.invert = invert ? 0 : 1;
++ imgMaskData.width = width;
++ imgMaskData.height = height;
++ imgMaskData.y = 0;
++ maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
++ 1, splashModeMono8, gFalse);
++ maskSplash = new Splash(maskBitmap, gTrue);
++ maskColor[0] = 0;
++ maskSplash->clear(maskColor);
++ maskColor[0] = 0xff;
++ maskSplash->setFillPattern(new SplashSolidColor(maskColor));
++ maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData,
++ width, height, mat, gFalse);
++ delete imgMaskData.imgStr;
++ str->close();
++ delete maskSplash;
++ splash->setSoftMask(maskBitmap);
++}
++
+ struct SplashOutImageData {
+ ImageStream *imgStr;
+ GfxImageColorMap *colorMap;
+@@ -1789,6 +2190,9 @@
+ if (imgData->y == imgData->height) {
+ return gFalse;
+ }
++ if (!(p = imgData->imgStr->getLine())) {
++ return gFalse;
++ }
+
+ nComps = imgData->colorMap->getNumPixelComps();
+
+@@ -1796,17 +2200,13 @@
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+- x < imgData->width;
+- ++x, ++p) {
++ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
+ *q++ = imgData->lookup[*p];
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+- x < imgData->width;
+- ++x, ++p) {
++ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
+ col = &imgData->lookup[3 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+@@ -1815,9 +2215,7 @@
+ break;
+ #if SPLASH_CMYK
+ case splashModeCMYK8:
+- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+- x < imgData->width;
+- ++x, ++p) {
++ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
+ col = &imgData->lookup[4 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+@@ -1831,18 +2229,14 @@
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+- x < imgData->width;
+- ++x, p += nComps) {
++ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
+ imgData->colorMap->getGray(p, &gray);
+ *q++ = colToByte(gray);
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+- x < imgData->width;
+- ++x, p += nComps) {
++ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
+ imgData->colorMap->getRGB(p, &rgb);
+ *q++ = colToByte(rgb.r);
+ *q++ = colToByte(rgb.g);
+@@ -1851,9 +2245,7 @@
+ break;
+ #if SPLASH_CMYK
+ case splashModeCMYK8:
+- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+- x < imgData->width;
+- ++x, p += nComps) {
++ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
+ imgData->colorMap->getCMYK(p, &cmyk);
+ *q++ = colToByte(cmyk.c);
+ *q++ = colToByte(cmyk.m);
+@@ -1885,10 +2277,13 @@
+ if (imgData->y == imgData->height) {
+ return gFalse;
+ }
++ if (!(p = imgData->imgStr->getLine())) {
++ return gFalse;
++ }
+
+ nComps = imgData->colorMap->getNumPixelComps();
+
+- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine;
++ for (x = 0, q = colorLine, aq = alphaLine;
+ x < imgData->width;
+ ++x, p += nComps) {
+ alpha = 0;
+@@ -1904,7 +2299,6 @@
+ case splashModeMono1:
+ case splashModeMono8:
+ *q++ = imgData->lookup[*p];
+- *aq++ = alpha;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+@@ -1912,7 +2306,6 @@
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+- *aq++ = alpha;
+ break;
+ #if SPLASH_CMYK
+ case splashModeCMYK8:
+@@ -1921,17 +2314,16 @@
+ *q++ = col[1];
+ *q++ = col[2];
+ *q++ = col[3];
+- *aq++ = alpha;
+ break;
+ #endif
+ }
++ *aq++ = alpha;
+ } else {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData->colorMap->getGray(p, &gray);
+ *q++ = colToByte(gray);
+- *aq++ = alpha;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+@@ -1939,7 +2331,6 @@
+ *q++ = colToByte(rgb.r);
+ *q++ = colToByte(rgb.g);
+ *q++ = colToByte(rgb.b);
+- *aq++ = alpha;
+ break;
+ #if SPLASH_CMYK
+ case splashModeCMYK8:
+@@ -1948,10 +2339,10 @@
+ *q++ = colToByte(cmyk.m);
+ *q++ = colToByte(cmyk.y);
+ *q++ = colToByte(cmyk.k);
+- *aq++ = alpha;
+ break;
+ #endif
+ }
++ *aq++ = alpha;
+ }
+ }
+
+@@ -2012,7 +2406,7 @@
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+- imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
++ imgData.lookup = (SplashColorPtr)gmallocn(n, 3);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getRGB(&pix, &rgb);
+@@ -2023,7 +2417,7 @@
+ break;
+ #if SPLASH_CMYK
+ case splashModeCMYK8:
+- imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
++ imgData.lookup = (SplashColorPtr)gmallocn(n, 4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getCMYK(&pix, &cmyk);
+@@ -2034,7 +2428,6 @@
+ }
+ break;
+ #endif
+- break;
+ }
+ }
+
+@@ -2071,7 +2464,6 @@
+ Guchar *alphaLine) {
+ SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data;
+ Guchar *p, *aq;
+- SplashColor maskColor;
+ SplashColorPtr q, col;
+ GfxRGB rgb;
+ GfxGray gray;
+@@ -2079,25 +2471,35 @@
+ GfxCMYK cmyk;
+ #endif
+ Guchar alpha;
++ Guchar *maskPtr;
++ int maskBit;
+ int nComps, x;
+
+ if (imgData->y == imgData->height) {
+ return gFalse;
+ }
++ if (!(p = imgData->imgStr->getLine())) {
++ return gFalse;
++ }
+
+ nComps = imgData->colorMap->getNumPixelComps();
+
+- for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine;
++ maskPtr = imgData->mask->getDataPtr() +
++ imgData->y * imgData->mask->getRowSize();
++ maskBit = 0x80;
++ for (x = 0, q = colorLine, aq = alphaLine;
+ x < imgData->width;
+ ++x, p += nComps) {
+- imgData->mask->getPixel(x, imgData->y, maskColor);
+- alpha = maskColor[0] ? 0xff : 0x00;
++ alpha = (*maskPtr & maskBit) ? 0xff : 0x00;
++ if (!(maskBit >>= 1)) {
++ ++maskPtr;
++ maskBit = 0x80;
++ }
+ if (imgData->lookup) {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ *q++ = imgData->lookup[*p];
+- *aq++ = alpha;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+@@ -2105,7 +2507,6 @@
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+- *aq++ = alpha;
+ break;
+ #if SPLASH_CMYK
+ case splashModeCMYK8:
+@@ -2114,17 +2515,16 @@
+ *q++ = col[1];
+ *q++ = col[2];
+ *q++ = col[3];
+- *aq++ = alpha;
+ break;
+ #endif
+ }
++ *aq++ = alpha;
+ } else {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData->colorMap->getGray(p, &gray);
+ *q++ = colToByte(gray);
+- *aq++ = alpha;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+@@ -2132,7 +2532,6 @@
+ *q++ = colToByte(rgb.r);
+ *q++ = colToByte(rgb.g);
+ *q++ = colToByte(rgb.b);
+- *aq++ = alpha;
+ break;
+ #if SPLASH_CMYK
+ case splashModeCMYK8:
+@@ -2141,10 +2540,10 @@
+ *q++ = colToByte(cmyk.m);
+ *q++ = colToByte(cmyk.y);
+ *q++ = colToByte(cmyk.k);
+- *aq++ = alpha;
+ break;
+ #endif
+ }
++ *aq++ = alpha;
+ }
+ }
+
+@@ -2433,7 +2838,7 @@
+ SplashTransparencyGroup *transpGroup;
+ SplashColor color;
+ double xMin, yMin, xMax, yMax, x, y;
+- int tx, ty, w, h;
++ int tx, ty, w, h, i;
+
+ // transform the bbox
+ state->transform(bbox[0], bbox[1], &x, &y);
+@@ -2475,14 +2880,14 @@
+ tx = (int)floor(xMin);
+ if (tx < 0) {
+ tx = 0;
+- } else if (tx > bitmap->getWidth()) {
+- tx = bitmap->getWidth();
++ } else if (tx >= bitmap->getWidth()) {
++ tx = bitmap->getWidth() - 1;
+ }
+ ty = (int)floor(yMin);
+ if (ty < 0) {
+ ty = 0;
+- } else if (ty > bitmap->getHeight()) {
+- ty = bitmap->getHeight();
++ } else if (ty >= bitmap->getHeight()) {
++ ty = bitmap->getHeight() - 1;
+ }
+ w = (int)ceil(xMax) - tx + 1;
+ if (tx + w > bitmap->getWidth()) {
+@@ -2512,31 +2917,47 @@
+ transpGroup->origBitmap = bitmap;
+ transpGroup->origSplash = splash;
+
+- //~ this ignores the blendingColorSpace arg
++ //~ this handles the blendingColorSpace arg for soft masks, but
++ //~ not yet for transparency groups
++
++ // switch to the blending color space
++ if (forSoftMask && isolated && blendingColorSpace) {
++ if (blendingColorSpace->getMode() == csDeviceGray ||
++ blendingColorSpace->getMode() == csCalGray ||
++ (blendingColorSpace->getMode() == csICCBased &&
++ blendingColorSpace->getNComps() == 1)) {
++ colorMode = splashModeMono8;
++ } else if (blendingColorSpace->getMode() == csDeviceRGB ||
++ blendingColorSpace->getMode() == csCalRGB ||
++ (blendingColorSpace->getMode() == csICCBased &&
++ blendingColorSpace->getNComps() == 3)) {
++ //~ does this need to use BGR8?
++ colorMode = splashModeRGB8;
++#if SPLASH_CMYK
++ } else if (blendingColorSpace->getMode() == csDeviceCMYK ||
++ (blendingColorSpace->getMode() == csICCBased &&
++ blendingColorSpace->getNComps() == 4)) {
++ colorMode = splashModeCMYK8;
++#endif
++ }
++ }
+
+ // create the temporary bitmap
+ bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue,
+ bitmapTopDown);
+ splash = new Splash(bitmap, vectorAntialias,
+ transpGroup->origSplash->getScreen());
++ splash->setMinLineWidth(globalParams->getMinLineWidth());
++ //~ Acrobat apparently copies at least the fill and stroke colors, and
++ //~ maybe other state(?) -- but not the clipping path (and not sure
++ //~ what else)
++ //~ [this is likely the same situation as in type3D1()]
++ splash->setFillPattern(transpGroup->origSplash->getFillPattern()->copy());
++ splash->setStrokePattern(
++ transpGroup->origSplash->getStrokePattern()->copy());
+ if (isolated) {
+- switch (colorMode) {
+- case splashModeMono1:
+- case splashModeMono8:
+- color[0] = 0;
+- break;
+- case splashModeRGB8:
+- case splashModeBGR8:
+- color[0] = color[1] = color[2] = 0;
+- break;
+-#if SPLASH_CMYK
+- case splashModeCMYK8:
+- color[0] = color[1] = color[2] = color[3] = 0;
+- break;
+-#endif
+- default:
+- // make gcc happy
+- break;
++ for (i = 0; i < splashMaxColorComps; ++i) {
++ color[i] = 0;
+ }
+ splash->clear(color, 0);
+ } else {
+@@ -2546,16 +2967,16 @@
+ transpGroup->tBitmap = bitmap;
+ state->shiftCTM(-tx, -ty);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
++ ++nestCount;
+ }
+
+ void SplashOutputDev::endTransparencyGroup(GfxState *state) {
+- double *ctm;
+-
+ // restore state
++ --nestCount;
+ delete splash;
+ bitmap = transpGroupStack->origBitmap;
++ colorMode = bitmap->getMode();
+ splash = transpGroupStack->origSplash;
+- ctm = state->getCTM();
+ state->shiftCTM(transpGroupStack->tx, transpGroupStack->ty);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
+ }
+@@ -2573,9 +2994,12 @@
+
+ // paint the transparency group onto the parent bitmap
+ // - the clip path was set in the parent's state)
+- splash->composite(tBitmap, 0, 0, tx, ty,
+- tBitmap->getWidth(), tBitmap->getHeight(),
+- gFalse, !isolated);
++ if (tx < bitmap->getWidth() && ty < bitmap->getHeight()) {
++ splash->setOverprintMask(0xffffffff);
++ splash->composite(tBitmap, 0, 0, tx, ty,
++ tBitmap->getWidth(), tBitmap->getHeight(),
++ gFalse, !isolated);
++ }
+
+ // pop the stack
+ transpGroup = transpGroupStack;
+@@ -2606,13 +3030,13 @@
+ tBitmap = transpGroupStack->tBitmap;
+
+ // composite with backdrop color
+- if (!alpha && colorMode != splashModeMono1) {
++ if (!alpha && tBitmap->getMode() != splashModeMono1) {
+ //~ need to correctly handle the case where no blending color
+ //~ space is given
+ tSplash = new Splash(tBitmap, vectorAntialias,
+ transpGroupStack->origSplash->getScreen());
+ if (transpGroupStack->blendingColorSpace) {
+- switch (colorMode) {
++ switch (tBitmap->getMode()) {
+ case splashModeMono1:
+ // transparency is not supported in mono1 mode
+ break;
+@@ -2648,36 +3072,38 @@
+ 1, splashModeMono8, gFalse);
+ memset(softMask->getDataPtr(), 0,
+ softMask->getRowSize() * softMask->getHeight());
+- p = softMask->getDataPtr() + ty * softMask->getRowSize() + tx;
+- for (y = 0; y < tBitmap->getHeight(); ++y) {
+- for (x = 0; x < tBitmap->getWidth(); ++x) {
+- tBitmap->getPixel(x, y, color);
+- if (alpha) {
+- //~ unimplemented
+- } else {
+- // convert to luminosity
+- switch (colorMode) {
+- case splashModeMono1:
+- case splashModeMono8:
+- lum = color[0] / 255.0;
+- break;
+- case splashModeRGB8:
+- case splashModeBGR8:
+- lum = (0.3 / 255.0) * color[0] +
+- (0.59 / 255.0) * color[1] +
+- (0.11 / 255.0) * color[2];
+- break;
+-#if SPLASH_CMYK
+- case splashModeCMYK8:
+- lum = (1 - color[4] / 255.0)
+- - (0.3 / 255.0) * color[0]
+- - (0.59 / 255.0) * color[1]
+- - (0.11 / 255.0) * color[2];
+- if (lum < 0) {
+- lum = 0;
+- }
+- break;
++ if (tx < softMask->getWidth() && ty < softMask->getHeight()) {
++ p = softMask->getDataPtr() + ty * softMask->getRowSize() + tx;
++ for (y = 0; y < tBitmap->getHeight(); ++y) {
++ for (x = 0; x < tBitmap->getWidth(); ++x) {
++ if (alpha) {
++ lum = tBitmap->getAlpha(x, y) / 255.0;
++ } else {
++ tBitmap->getPixel(x, y, color);
++ // convert to luminosity
++ switch (tBitmap->getMode()) {
++ case splashModeMono1:
++ case splashModeMono8:
++ lum = color[0] / 255.0;
++ break;
++ case splashModeRGB8:
++ case splashModeBGR8:
++ lum = (0.3 / 255.0) * color[0] +
++ (0.59 / 255.0) * color[1] +
++ (0.11 / 255.0) * color[2];
++ break;
++#if SPLASH_CMYK
++ case splashModeCMYK8:
++ lum = (1 - color[3] / 255.0)
++ - (0.3 / 255.0) * color[0]
++ - (0.59 / 255.0) * color[1]
++ - (0.11 / 255.0) * color[2];
++ if (lum < 0) {
++ lum = 0;
++ }
++ break;
+ #endif
++ }
+ }
+ if (transferFunc) {
+ transferFunc->transform(&lum, &lum2);
+@@ -2686,8 +3112,8 @@
+ }
+ p[x] = (int)(lum2 * 255.0 + 0.5);
+ }
++ p += softMask->getRowSize();
+ }
+- p += softMask->getRowSize();
+ }
+ splash->setSoftMask(softMask);
+
+@@ -2743,39 +3169,49 @@
+ rgb.r = byteToCol(r);
+ rgb.g = byteToCol(g);
+ rgb.b = byteToCol(b);
+- gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g + 0.5);
+- if (gray > gfxColorComp1) {
+- gray = gfxColorComp1;
+- }
++ switch (colorMode) {
++ case splashModeMono1:
++ case splashModeMono8:
++ gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g + 0.5);
++ if (gray > gfxColorComp1) {
++ gray = gfxColorComp1;
++ }
++ splash->setFillPattern(getColor(gray));
++ break;
++ case splashModeRGB8:
++ case splashModeBGR8:
++ splash->setFillPattern(getColor(&rgb));
++ break;
+ #if SPLASH_CMYK
+- cmyk.c = gfxColorComp1 - rgb.r;
+- cmyk.m = gfxColorComp1 - rgb.g;
+- cmyk.y = gfxColorComp1 - rgb.b;
+- cmyk.k = 0;
+- splash->setFillPattern(getColor(gray, &rgb, &cmyk));
+-#else
+- splash->setFillPattern(getColor(gray, &rgb));
++ case splashModeCMYK8:
++ cmyk.c = gfxColorComp1 - rgb.r;
++ cmyk.m = gfxColorComp1 - rgb.g;
++ cmyk.y = gfxColorComp1 - rgb.b;
++ cmyk.k = 0;
++ splash->setFillPattern(getColor(&cmyk));
++ break;
+ #endif
++ }
+ }
+
+-SplashFont *SplashOutputDev::getFont(GString *name, double *textMatA) {
+- DisplayFontParam *dfp;
++SplashFont *SplashOutputDev::getFont(GString *name, SplashCoord *textMatA) {
+ Ref ref;
+ SplashOutFontFileID *id;
++ GfxFontLoc *fontLoc;
+ SplashFontFile *fontFile;
+ SplashFont *fontObj;
+ FoFiTrueType *ff;
+- Gushort *codeToGID;
++ int *codeToGID;
+ Unicode u;
+ SplashCoord textMat[4];
+ int cmap, i;
+
+- for (i = 0; i < 16; ++i) {
+- if (!name->cmp(splashOutSubstFonts[i].name)) {
++ for (i = 0; i < nBuiltinFonts; ++i) {
++ if (!name->cmp(builtinFonts[i].name)) {
+ break;
+ }
+ }
+- if (i == 16) {
++ if (i == nBuiltinFonts) {
+ return NULL;
+ }
+ ref.num = i;
+@@ -2788,12 +3224,16 @@
+
+ // load the font file
+ } else {
+- dfp = globalParams->getDisplayFont(name);
+- if (dfp && dfp->kind == displayFontT1) {
+- fontFile = fontEngine->loadType1Font(id, dfp->t1.fileName->getCString(),
++ if (!(fontLoc = GfxFont::locateBase14Font(name))) {
++ return NULL;
++ }
++ if (fontLoc->fontType == fontType1) {
++ fontFile = fontEngine->loadType1Font(id, fontLoc->path->getCString(),
+ gFalse, winAnsiEncoding);
+- } else if (dfp && dfp->kind == displayFontTT) {
+- if (!(ff = FoFiTrueType::load(dfp->tt.fileName->getCString()))) {
++ } else if (fontLoc->fontType == fontTrueType) {
++ if (!(ff = FoFiTrueType::load(fontLoc->path->getCString()))) {
++ delete fontLoc;
++ delete id;
+ return NULL;
+ }
+ for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) {
+@@ -2805,9 +3245,11 @@
+ }
+ if (cmap == ff->getNumCmaps()) {
+ delete ff;
++ delete fontLoc;
++ delete id;
+ return NULL;
+ }
+- codeToGID = (Gushort *)gmallocn(256, sizeof(Gushort));
++ codeToGID = (int *)gmallocn(256, sizeof(int));
+ for (i = 0; i < 256; ++i) {
+ codeToGID[i] = 0;
+ if (winAnsiEncoding[i] &&
+@@ -2817,11 +3259,18 @@
+ }
+ delete ff;
+ fontFile = fontEngine->loadTrueTypeFont(id,
+- dfp->tt.fileName->getCString(),
+- gFalse, codeToGID, 256);
++ fontLoc->path->getCString(),
++ fontLoc->fontNum,
++ gFalse, codeToGID, 256, NULL);
+ } else {
++ delete fontLoc;
++ delete id;
+ return NULL;
+ }
++ delete fontLoc;
++ }
++ if (!fontFile) {
++ return NULL;
+ }
+
+ // create the scaled font
+@@ -2835,11 +3284,7 @@
+ }
+
+ #if 1 //~tmp: turn off anti-aliasing temporarily
+-GBool SplashOutputDev::getVectorAntialias() {
+- return splash->getVectorAntialias();
+-}
+-
+-void SplashOutputDev::setVectorAntialias(GBool vaa) {
+- splash->setVectorAntialias(vaa);
++void SplashOutputDev::setInShading(GBool sh) {
++ splash->setInShading(sh);
+ }
+ #endif
+diff -ru xpdf-3.02/xpdf/SplashOutputDev.h xpdf-3.03/xpdf/SplashOutputDev.h
+--- xpdf-3.02/xpdf/SplashOutputDev.h 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/SplashOutputDev.h 2011-08-15 23:08:53.000000000 +0200
+@@ -58,15 +58,21 @@
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+- virtual GBool upsideDown() { return gTrue; }
++ virtual GBool upsideDown() { return bitmapTopDown ^ bitmapUpsideDown; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gTrue; }
+
+@@ -124,6 +136,10 @@
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg);
++ virtual void setSoftMaskFromImageMask(GfxState *state,
++ Object *ref, Stream *str,
++ int width, int height, GBool invert,
++ GBool inlineImg);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg);
+@@ -174,6 +190,10 @@
+ // caller.
+ SplashBitmap *takeBitmap();
+
++ // Set this flag to true to generate an upside-down bitmap (useful
++ // for Windows BMP files).
++ void setBitmapUpsideDown(GBool f) { bitmapUpsideDown = f; }
++
+ // Get the Splash object.
+ Splash *getSplash() { return splash; }
+
+@@ -187,26 +207,36 @@
+ void setFillColor(int r, int g, int b);
+
+ // Get a font object for a Base-14 font, using the Latin-1 encoding.
+- SplashFont *getFont(GString *name, double *textMatA);
++ SplashFont *getFont(GString *name, SplashCoord *textMatA);
+
+ SplashFont *getCurrentFont() { return font; }
+
++ // If <skipTextA> is true, don't draw horizontal text.
++ // If <skipRotatedTextA> is true, don't draw rotated (non-horizontal) text.
++ void setSkipText(GBool skipHorizTextA, GBool skipRotatedTextA)
++ { skipHorizText = skipHorizTextA; skipRotatedText = skipRotatedTextA; }
++
++ int getNestCount() { return nestCount; }
++
++
+ #if 1 //~tmp: turn off anti-aliasing temporarily
+- virtual GBool getVectorAntialias();
+- virtual void setVectorAntialias(GBool vaa);
++ virtual void setInShading(GBool sh);
+ #endif
+
+ private:
+
+ void setupScreenParams(double hDPI, double vDPI);
++ SplashPattern *getColor(GfxGray gray);
++ SplashPattern *getColor(GfxRGB *rgb);
+ #if SPLASH_CMYK
+- SplashPattern *getColor(GfxGray gray, GfxRGB *rgb, GfxCMYK *cmyk);
+-#else
+- SplashPattern *getColor(GfxGray gray, GfxRGB *rgb);
++ SplashPattern *getColor(GfxCMYK *cmyk);
+ #endif
+@@ -219,11 +249,14 @@
+ SplashColorMode colorMode;
+ int bitmapRowPad;
+ GBool bitmapTopDown;
++ GBool bitmapUpsideDown;
+ GBool allowAntialias;
+ GBool vectorAntialias;
+ GBool reverseVideo; // reverse video mode
+ SplashColor paperColor; // paper color
+ SplashScreenParams screenParams;
++ GBool skipHorizText;
++ GBool skipRotatedText;
+
+ XRef *xref; // xref table for current document
+
+@@ -235,6 +268,7 @@
+ t3FontCache[splashOutT3FontCacheSize];
+ int nT3Fonts; // number of valid entries in t3FontCache
+ T3GlyphStack *t3GlyphStack; // Type 3 glyph context stack
++ GBool haveT3Dx; // set after seeing a d0/d1 operator
+
+ SplashFont *font; // current font
+ GBool needFontUpdate; // set when the font needs to be updated
+@@ -242,6 +276,8 @@
+
+ SplashTransparencyGroup * // transparency group stack
+ transpGroupStack;
++
++ int nestCount;
+ };
+
+ #endif
+diff -ru xpdf-3.02/xpdf/TextOutputDev.cc xpdf-3.03/xpdf/TextOutputDev.cc
+--- xpdf-3.02/xpdf/TextOutputDev.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/TextOutputDev.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -545,7 +618,7 @@
+
+ // insert the new word
+ if (cursor && wordBaseIdx == cursorBaseIdx &&
+- word->primaryCmp(cursor) > 0) {
++ word->primaryCmp(cursor) >= 0) {
+ w0 = cursor;
+ w1 = cursor->next;
+ } else {
+@@ -928,7 +1001,7 @@
+ xMax = blk->xMin + d1 * (blk->xMax - blk->xMin);
+ yMin = blk->yMin + d2 * (blk->yMax - blk->yMin);
+ yMax = blk->yMin + d3 * (blk->yMax - blk->yMin);
+- base = blk->yMin + base * (blk->yMax - blk->yMin);
++ base = blk->yMin + d4 * (blk->yMax - blk->yMin);
+ break;
+ case 1:
+ xMin = blk->xMax - d3 * (blk->xMax - blk->xMin);
+@@ -1150,15 +1223,15 @@
+ }
+ }
+
+-void TextBlock::coalesce(UnicodeMap *uMap) {
++void TextBlock::coalesce(UnicodeMap *uMap, double fixedPitch) {
+ TextWord *word0, *word1, *word2, *bestWord0, *bestWord1, *lastWord;
+ TextLine *line, *line0, *line1;
+ int poolMinBaseIdx, startBaseIdx, minBaseIdx, maxBaseIdx;
+ int baseIdx, bestWordBaseIdx, idx0, idx1;
+ double minBase, maxBase;
+- double fontSize, delta, priDelta, secDelta;
++ double fontSize, wordSpacing, delta, priDelta, secDelta;
+ TextLine **lineArray;
+- GBool found;
++ GBool found, overlap;
+ int col1, col2;
+ int i, j, k;
+
+@@ -1168,11 +1241,7 @@
+ while (word0) {
+ priDelta = dupMaxPriDelta * word0->fontSize;
+ secDelta = dupMaxSecDelta * word0->fontSize;
+- if (rot == 0 || rot == 3) {
+- maxBaseIdx = pool->getBaseIdx(word0->base + secDelta);
+- } else {
+- maxBaseIdx = pool->getBaseIdx(word0->base - secDelta);
+- }
++ maxBaseIdx = pool->getBaseIdx(word0->base + secDelta);
+ found = gFalse;
+ word1 = word2 = NULL; // make gcc happy
+ for (idx1 = idx0; idx1 <= maxBaseIdx; ++idx1) {
+@@ -1269,6 +1338,7 @@
+ maxBase = word0->base + maxIntraLineDelta * fontSize;
+ minBaseIdx = pool->getBaseIdx(minBase);
+ maxBaseIdx = pool->getBaseIdx(maxBase);
++ wordSpacing = fixedPitch ? fixedPitch : maxWordSpacing * fontSize;
+
+ // find the rest of the words in this line
+ while (1) {
+@@ -1277,25 +1347,32 @@
+ // this line
+ bestWordBaseIdx = 0;
+ bestWord0 = bestWord1 = NULL;
+- for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) {
++ overlap = gFalse;
++ for (baseIdx = minBaseIdx;
++ !overlap && baseIdx <= maxBaseIdx;
++ ++baseIdx) {
+ for (word0 = NULL, word1 = pool->getPool(baseIdx);
+ word1;
+ word0 = word1, word1 = word1->next) {
+ if (word1->base >= minBase &&
+- word1->base <= maxBase &&
+- (delta = lastWord->primaryDelta(word1)) >=
+- minCharSpacing * fontSize) {
+- if (delta < maxWordSpacing * fontSize &&
+- (!bestWord1 || word1->primaryCmp(bestWord1) < 0)) {
+- bestWordBaseIdx = baseIdx;
+- bestWord0 = word0;
+- bestWord1 = word1;
++ word1->base <= maxBase) {
++ delta = lastWord->primaryDelta(word1);
++ if (delta < minCharSpacing * fontSize) {
++ overlap = gTrue;
++ break;
++ } else {
++ if (delta < wordSpacing &&
++ (!bestWord1 || word1->primaryCmp(bestWord1) < 0)) {
++ bestWordBaseIdx = baseIdx;
++ bestWord0 = word0;
++ bestWord1 = word1;
++ }
++ break;
+ }
+- break;
+ }
+ }
+ }
+- if (!bestWord1) {
++ if (overlap || !bestWord1) {
+ break;
+ }
+
+@@ -1342,52 +1419,79 @@
+
+ // column assignment
+ nColumns = 0;
+- for (i = 0; i < nLines; ++i) {
+- line0 = lineArray[i];
+- col1 = 0;
+- for (j = 0; j < i; ++j) {
+- line1 = lineArray[j];
+- if (line1->primaryDelta(line0) >= 0) {
+- col2 = line1->col[line1->len] + 1;
+- } else {
+- k = 0; // make gcc happy
+- switch (rot) {
+- case 0:
+- for (k = 0;
+- k < line1->len &&
+- line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+- ++k) ;
+- break;
+- case 1:
+- for (k = 0;
+- k < line1->len &&
+- line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+- ++k) ;
+- break;
+- case 2:
+- for (k = 0;
+- k < line1->len &&
+- line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+- ++k) ;
+- break;
+- case 3:
+- for (k = 0;
+- k < line1->len &&
+- line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+- ++k) ;
+- break;
+- }
+- col2 = line1->col[k];
++ if (fixedPitch) {
++ for (i = 0; i < nLines; ++i) {
++ line0 = lineArray[i];
++ col1 = 0; // make gcc happy
++ switch (rot) {
++ case 0:
++ col1 = (int)((line0->xMin - xMin) / fixedPitch + 0.5);
++ break;
++ case 1:
++ col1 = (int)((line0->yMin - yMin) / fixedPitch + 0.5);
++ break;
++ case 2:
++ col1 = (int)((xMax - line0->xMax) / fixedPitch + 0.5);
++ break;
++ case 3:
++ col1 = (int)((yMax - line0->yMax) / fixedPitch + 0.5);
++ break;
+ }
+- if (col2 > col1) {
+- col1 = col2;
++ for (k = 0; k <= line0->len; ++k) {
++ line0->col[k] += col1;
++ }
++ if (line0->col[line0->len] > nColumns) {
++ nColumns = line0->col[line0->len];
+ }
+ }
+- for (k = 0; k <= line0->len; ++k) {
+- line0->col[k] += col1;
+- }
+- if (line0->col[line0->len] > nColumns) {
+- nColumns = line0->col[line0->len];
++ } else {
++ for (i = 0; i < nLines; ++i) {
++ line0 = lineArray[i];
++ col1 = 0;
++ for (j = 0; j < i; ++j) {
++ line1 = lineArray[j];
++ if (line1->primaryDelta(line0) >= 0) {
++ col2 = line1->col[line1->len] + 1;
++ } else {
++ k = 0; // make gcc happy
++ switch (rot) {
++ case 0:
++ for (k = 0;
++ k < line1->len &&
++ line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++ ++k) ;
++ break;
++ case 1:
++ for (k = 0;
++ k < line1->len &&
++ line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++ ++k) ;
++ break;
++ case 2:
++ for (k = 0;
++ k < line1->len &&
++ line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++ ++k) ;
++ break;
++ case 3:
++ for (k = 0;
++ k < line1->len &&
++ line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
++ ++k) ;
++ break;
++ }
++ col2 = line1->col[k];
++ }
++ if (col2 > col1) {
++ col1 = col2;
++ }
++ }
++ for (k = 0; k <= line0->len; ++k) {
++ line0->col[k] += col1;
++ }
++ if (line0->col[line0->len] > nColumns) {
++ nColumns = line0->col[line0->len];
++ }
+ }
+ }
+ gfree(lineArray);
+@@ -1744,6 +1848,9 @@
+ nest = 0;
+ nTinyChars = 0;
+ lastCharOverlap = gFalse;
++ actualText = NULL;
++ actualTextLen = 0;
++ actualTextNBytes = 0;
+ if (!rawOrder) {
+ for (rot = 0; rot < 4; ++rot) {
+ pools[rot] = new TextPool();
+@@ -1799,6 +1906,7 @@
+ delete curWord;
+ curWord = NULL;
+ }
++ gfree(actualText);
+ if (rawOrder) {
+ while (rawWords) {
+ word = rawWords;
+@@ -1817,6 +1925,8 @@
+ gfree(blocks);
+ }
+ deleteGList(fonts, TextFontInfo);
++ deleteGList(underlines, TextUnderline);
++ deleteGList(links, TextLink);
+
+ curWord = NULL;
+ charPos = 0;
+@@ -1824,6 +1934,9 @@
+ curFontSize = 0;
+ nest = 0;
+ nTinyChars = 0;
++ actualText = NULL;
++ actualTextLen = 0;
++ actualTextNBytes = 0;
+ if (!rawOrder) {
+ for (rot = 0; rot < 4; ++rot) {
+ pools[rot] = new TextPool();
+@@ -1834,6 +1947,8 @@
+ rawWords = NULL;
+ rawLastWord = NULL;
+ fonts = new GList();
++ underlines = new GList();
++ links = new GList();
+ }
+
+ void TextPage::updateFont(GfxState *state) {
+@@ -1993,7 +2124,7 @@
+ // (2) this character overlaps the previous one (duplicated text), or
+ // (3) the previous character was an overlap (we want each duplicated
+ // character to be in a word by itself at this stage),
+- // (4) the font size has changed
++ // (4) the font or font size has changed
+ if (curWord && curWord->len > 0) {
+ base = sp = delta = 0; // make gcc happy
+ switch (curWord->rot) {
+@@ -2024,6 +2155,7 @@
+ sp < -minDupBreakOverlap * curWord->fontSize ||
+ sp > minWordBreakSpace * curWord->fontSize ||
+ fabs(base - curWord->base) > 0.5 ||
++ curFont != curWord->font ||
+ curFontSize != curWord->fontSize) {
+ endWord();
+ }
+@@ -2057,15 +2189,46 @@
+ }
+ }
+ charPos += nBytes;
+ }
+
++void TextPage::incCharCount(int nChars) {
++ charPos += nChars;
++}
++
+@@ -2109,7 +2272,7 @@
+ links->append(new TextLink(xMin, yMin, xMax, yMax, link));
+ }
+
+-void TextPage::coalesce(GBool physLayout, GBool doHTML) {
++void TextPage::coalesce(GBool physLayout, double fixedPitch, GBool doHTML) {
+ UnicodeMap *uMap;
+ TextPool *pool;
+ TextWord *word0, *word1, *word2;
+@@ -2139,7 +2302,7 @@
+ blkList = NULL;
+ lastBlk = NULL;
+ nBlocks = 0;
+- primaryRot = -1;
++ primaryRot = 0;
+
+ #if 0 // for debugging
+ printf("*** initial words ***\n");
+@@ -2603,7 +2766,7 @@
+ //~ addition to primary rotation
+
+ // coalesce the block, and add it to the list
+- blk->coalesce(uMap);
++ blk->coalesce(uMap, fixedPitch);
+ if (lastBlk) {
+ lastBlk->next = blk;
+ } else {
+@@ -2611,11 +2774,12 @@
+ }
+ lastBlk = blk;
+ count[rot] += blk->charCount;
+- if (primaryRot < 0 || count[rot] > count[primaryRot]) {
+- primaryRot = rot;
+- }
+ ++nBlocks;
+ }
++
++ if (count[rot] > count[primaryRot]) {
++ primaryRot = rot;
++ }
+ }
+
+ #if 0 // for debugging
+@@ -2674,76 +2838,108 @@
+
+ //----- column assignment
+
+- // sort blocks into xy order for column assignment
+- blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
+- for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
+- blocks[i] = blk;
+- }
+- qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot);
++ if (physLayout && fixedPitch) {
+
+- // column assignment
+- for (i = 0; i < nBlocks; ++i) {
+- blk0 = blocks[i];
+- col1 = 0;
+- for (j = 0; j < i; ++j) {
+- blk1 = blocks[j];
+- col2 = 0; // make gcc happy
++ blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
++ for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
++ blocks[i] = blk;
++ col1 = 0; // make gcc happy
+ switch (primaryRot) {
+ case 0:
+- if (blk0->xMin > blk1->xMax) {
+- col2 = blk1->col + blk1->nColumns + 3;
+- } else if (blk1->xMax == blk1->xMin) {
+- col2 = blk1->col;
+- } else {
+- col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) /
+- (blk1->xMax - blk1->xMin)) *
+- blk1->nColumns);
+- }
++ col1 = (int)(blk->xMin / fixedPitch + 0.5);
+ break;
+ case 1:
+- if (blk0->yMin > blk1->yMax) {
+- col2 = blk1->col + blk1->nColumns + 3;
+- } else if (blk1->yMax == blk1->yMin) {
+- col2 = blk1->col;
+- } else {
+- col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) /
+- (blk1->yMax - blk1->yMin)) *
+- blk1->nColumns);
+- }
++ col1 = (int)(blk->yMin / fixedPitch + 0.5);
+ break;
+ case 2:
+- if (blk0->xMax < blk1->xMin) {
+- col2 = blk1->col + blk1->nColumns + 3;
+- } else if (blk1->xMin == blk1->xMax) {
+- col2 = blk1->col;
+- } else {
+- col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) /
+- (blk1->xMin - blk1->xMax)) *
+- blk1->nColumns);
+- }
++ col1 = (int)((pageWidth - blk->xMax) / fixedPitch + 0.5);
+ break;
+ case 3:
+- if (blk0->yMax < blk1->yMin) {
+- col2 = blk1->col + blk1->nColumns + 3;
+- } else if (blk1->yMin == blk1->yMax) {
+- col2 = blk1->col;
+- } else {
+- col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) /
+- (blk1->yMin - blk1->yMax)) *
+- blk1->nColumns);
+- }
++ col1 = (int)((pageHeight - blk->yMax) / fixedPitch + 0.5);
+ break;
+ }
+- if (col2 > col1) {
+- col1 = col2;
++ blk->col = col1;
++ for (line = blk->lines; line; line = line->next) {
++ for (j = 0; j <= line->len; ++j) {
++ line->col[j] += col1;
++ }
+ }
+ }
+- blk0->col = col1;
+- for (line = blk0->lines; line; line = line->next) {
+- for (j = 0; j <= line->len; ++j) {
+- line->col[j] += col1;
++
++ } else {
++
++ // sort blocks into xy order for column assignment
++ blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
++ for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
++ blocks[i] = blk;
++ }
++ qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot);
++
++ // column assignment
++ for (i = 0; i < nBlocks; ++i) {
++ blk0 = blocks[i];
++ col1 = 0;
++ for (j = 0; j < i; ++j) {
++ blk1 = blocks[j];
++ col2 = 0; // make gcc happy
++ switch (primaryRot) {
++ case 0:
++ if (blk0->xMin > blk1->xMax) {
++ col2 = blk1->col + blk1->nColumns + 3;
++ } else if (blk1->xMax == blk1->xMin) {
++ col2 = blk1->col;
++ } else {
++ col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) /
++ (blk1->xMax - blk1->xMin)) *
++ blk1->nColumns);
++ }
++ break;
++ case 1:
++ if (blk0->yMin > blk1->yMax) {
++ col2 = blk1->col + blk1->nColumns + 3;
++ } else if (blk1->yMax == blk1->yMin) {
++ col2 = blk1->col;
++ } else {
++ col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) /
++ (blk1->yMax - blk1->yMin)) *
++ blk1->nColumns);
++ }
++ break;
++ case 2:
++ if (blk0->xMax < blk1->xMin) {
++ col2 = blk1->col + blk1->nColumns + 3;
++ } else if (blk1->xMin == blk1->xMax) {
++ col2 = blk1->col;
++ } else {
++ col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) /
++ (blk1->xMin - blk1->xMax)) *
++ blk1->nColumns);
++ }
++ break;
++ case 3:
++ if (blk0->yMax < blk1->yMin) {
++ col2 = blk1->col + blk1->nColumns + 3;
++ } else if (blk1->yMin == blk1->yMax) {
++ col2 = blk1->col;
++ } else {
++ col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) /
++ (blk1->yMin - blk1->yMax)) *
++ blk1->nColumns);
++ }
++ break;
++ }
++ if (col2 > col1) {
++ col1 = col2;
++ }
++ }
++ blk0->col = col1;
++ for (line = blk0->lines; line; line = line->next) {
++ for (j = 0; j <= line->len; ++j) {
++ line->col[j] += col1;
++ }
+ }
+ }
++
+ }
+
+ #if 0 // for debugging
+@@ -2753,7 +2949,7 @@
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->col,
+ blk->nColumns);
+ for (line = blk->lines; line; line = line->next) {
+- printf(" line:\n");
++ printf(" line: col[0]=%d\n", line->col[0]);
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+@@ -2932,6 +3128,7 @@
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
++ GBool wholeWord,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ TextBlock *blk;
+@@ -2989,25 +3186,35 @@
+ blk = blocks[i];
+
+ // check: is the block above the top limit?
+- if (!startAtTop && (backward ? blk->yMin > yStart : blk->yMax < yStart)) {
++ // (this only works if the page's primary rotation is zero --
++ // otherwise the blocks won't be sorted in the useful order)
++ if (!startAtTop && primaryRot == 0 &&
++ (backward ? blk->yMin > yStart : blk->yMax < yStart)) {
+ continue;
+ }
+
+ // check: is the block below the bottom limit?
+- if (!stopAtBottom && (backward ? blk->yMax < yStop : blk->yMin > yStop)) {
++ // (this only works if the page's primary rotation is zero --
++ // otherwise the blocks won't be sorted in the useful order)
++ if (!stopAtBottom && primaryRot == 0 &&
++ (backward ? blk->yMax < yStop : blk->yMin > yStop)) {
+ break;
+ }
+
+ for (line = blk->lines; line; line = line->next) {
+
+ // check: is the line above the top limit?
+- if (!startAtTop &&
++ // (this only works if the page's primary rotation is zero --
++ // otherwise the lines won't be sorted in the useful order)
++ if (!startAtTop && primaryRot == 0 &&
+ (backward ? line->yMin > yStart : line->yMin < yStart)) {
+ continue;
+ }
+
+ // check: is the line below the bottom limit?
+- if (!stopAtBottom &&
++ // (this only works if the page's primary rotation is zero --
++ // otherwise the lines won't be sorted in the useful order)
++ if (!stopAtBottom && primaryRot == 0 &&
+ (backward ? line->yMin < yStop : line->yMin > yStop)) {
+ continue;
+ }
+@@ -3030,68 +3237,72 @@
+ j = backward ? m - len : 0;
+ p = txt + j;
+ while (backward ? j >= 0 : j <= m - len) {
+-
+- // compare the strings
+- for (k = 0; k < len; ++k) {
+- if (p[k] != s2[k]) {
+- break;
++ if (!wholeWord ||
++ ((j == 0 || !unicodeTypeAlphaNum(txt[j - 1])) &&
++ (j + len == m || !unicodeTypeAlphaNum(txt[j + len])))) {
++
++ // compare the strings
++ for (k = 0; k < len; ++k) {
++ if (p[k] != s2[k]) {
++ break;
++ }
+ }
+- }
+
+- // found it
+- if (k == len) {
+- switch (line->rot) {
+- case 0:
+- xMin1 = line->edge[j];
+- xMax1 = line->edge[j + len];
+- yMin1 = line->yMin;
+- yMax1 = line->yMax;
+- break;
+- case 1:
+- xMin1 = line->xMin;
+- xMax1 = line->xMax;
+- yMin1 = line->edge[j];
+- yMax1 = line->edge[j + len];
+- break;
+- case 2:
+- xMin1 = line->edge[j + len];
+- xMax1 = line->edge[j];
+- yMin1 = line->yMin;
+- yMax1 = line->yMax;
+- break;
+- case 3:
+- xMin1 = line->xMin;
+- xMax1 = line->xMax;
+- yMin1 = line->edge[j + len];
+- yMax1 = line->edge[j];
+- break;
+- }
+- if (backward) {
+- if ((startAtTop ||
+- yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) &&
+- (stopAtBottom ||
+- yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) {
+- if (!found ||
+- yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) {
+- xMin0 = xMin1;
+- xMax0 = xMax1;
+- yMin0 = yMin1;
+- yMax0 = yMax1;
+- found = gTrue;
+- }
++ // found it
++ if (k == len) {
++ switch (line->rot) {
++ case 0:
++ xMin1 = line->edge[j];
++ xMax1 = line->edge[j + len];
++ yMin1 = line->yMin;
++ yMax1 = line->yMax;
++ break;
++ case 1:
++ xMin1 = line->xMin;
++ xMax1 = line->xMax;
++ yMin1 = line->edge[j];
++ yMax1 = line->edge[j + len];
++ break;
++ case 2:
++ xMin1 = line->edge[j + len];
++ xMax1 = line->edge[j];
++ yMin1 = line->yMin;
++ yMax1 = line->yMax;
++ break;
++ case 3:
++ xMin1 = line->xMin;
++ xMax1 = line->xMax;
++ yMin1 = line->edge[j + len];
++ yMax1 = line->edge[j];
++ break;
+ }
+- } else {
+- if ((startAtTop ||
+- yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
+- (stopAtBottom ||
+- yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) {
+- if (!found ||
+- yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
+- xMin0 = xMin1;
+- xMax0 = xMax1;
+- yMin0 = yMin1;
+- yMax0 = yMax1;
+- found = gTrue;
++ if (backward) {
++ if ((startAtTop ||
++ yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) &&
++ (stopAtBottom ||
++ yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) {
++ if (!found ||
++ yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) {
++ xMin0 = xMin1;
++ xMax0 = xMax1;
++ yMin0 = yMin1;
++ yMax0 = yMax1;
++ found = gTrue;
++ }
++ }
++ } else {
++ if ((startAtTop ||
++ yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
++ (stopAtBottom ||
++ yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) {
++ if (!found ||
++ yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
++ xMin0 = xMin1;
++ xMax0 = xMax1;
++ yMin0 = yMin1;
++ yMax0 = yMax1;
++ found = gTrue;
++ }
+ }
+ }
+ }
+@@ -3820,10 +4038,20 @@
+ fwrite(text, 1, len, (FILE *)stream);
+ }
+
+ TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA,
+- GBool rawOrderA, GBool append) {
++ double fixedPitchA, GBool rawOrderA,
++ GBool append) {
+ text = NULL;
+ physLayout = physLayoutA;
++ fixedPitch = physLayout ? fixedPitchA : 0;
+ rawOrder = rawOrderA;
+ doHTML = gFalse;
+ ok = gTrue;
+@@ -3854,11 +4074,13 @@
+ }
+
+ TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream,
+- GBool physLayoutA, GBool rawOrderA) {
++ GBool physLayoutA, double fixedPitchA,
++ GBool rawOrderA) {
+ outputFunc = func;
+ outputStream = stream;
+ needClose = gFalse;
+ physLayout = physLayoutA;
++ fixedPitch = physLayout ? fixedPitchA : 0;
+ rawOrder = rawOrderA;
+ doHTML = gFalse;
+ text = new TextPage(rawOrderA);
+@@ -3883,12 +4105,16 @@
+
+ void TextOutputDev::endPage() {
+ text->endPage();
+- text->coalesce(physLayout, doHTML);
++ text->coalesce(physLayout, fixedPitch, doHTML);
+ if (outputStream) {
+ text->dump(outputStream, outputFunc, physLayout);
+ }
+ }
+
++void TextOutputDev::restoreState(GfxState *state) {
++ text->updateFont(state);
++}
++
+ void TextOutputDev::updateFont(GfxState *state) {
+ text->updateFont(state);
+ }
+@@ -3903,7 +4129,19 @@
+ double dx, double dy,
+ double originX, double originY,
+ CharCode c, int nBytes, Unicode *u, int uLen) {
+- text->addChar(state, x, y, dx, dy, c, nBytes, u, uLen);
++ text->addChar(state, x - originX, y - originY, dx, dy, c, nBytes, u, uLen);
++}
++
++void TextOutputDev::incCharCount(int nChars) {
++ text->incCharCount(nChars);
++}
++
+@@ -4057,10 +4295,12 @@
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
++ GBool wholeWord,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ return text->findText(s, len, startAtTop, stopAtBottom,
+- startAtLast, stopAtLast, caseSensitive, backward,
++ startAtLast, stopAtLast,
++ caseSensitive, backward, wholeWord,
+ xMin, yMin, xMax, yMax);
+ }
+
+diff -ru xpdf-3.02/xpdf/TextOutputDev.h xpdf-3.03/xpdf/TextOutputDev.h
+--- xpdf-3.02/xpdf/TextOutputDev.h 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/TextOutputDev.h 2011-08-15 23:08:53.000000000 +0200
+@@ -280,7 +281,7 @@
+
+ void addWord(TextWord *word);
+
+- void coalesce(UnicodeMap *uMap);
++ void coalesce(UnicodeMap *uMap, double fixedPitch);
+
+ // Update this block's priMin and priMax values, looking at <blk>.
+ void updatePriMinMax(TextBlock *blk);
+@@ -429,6 +430,15 @@
+ double dx, double dy,
+ CharCode c, int nBytes, Unicode *u, int uLen);
+
++ // Add <nChars> invisible characters.
++ void incCharCount(int nChars);
++
+@@ -442,7 +452,7 @@
+ void addLink(int xMin, int yMin, int xMax, int yMax, Link *link);
+
+ // Coalesce strings that look like parts of the same line.
+- void coalesce(GBool physLayout, GBool doHTML);
++ void coalesce(GBool physLayout, double fixedPitch, GBool doHTML);
+
+ // Find a string. If <startAtTop> is true, starts looking at the
+ // top of the page; else if <startAtLast> is true, starts looking
+@@ -455,6 +465,7 @@
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
++ GBool wholeWord,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+
+@@ -502,6 +513,13 @@
+ int nTinyChars; // number of "tiny" chars seen so far
+ GBool lastCharOverlap; // set if the last added char overlapped the
+ // previous char
+@@ -544,14 +562,16 @@
+ // is maintained. If <rawOrder> is true, the text is kept in
+ // content stream order.
+ TextOutputDev(char *fileName, GBool physLayoutA,
+- GBool rawOrderA, GBool append);
++ double fixedPitchA, GBool rawOrderA,
++ GBool append);
+
+ // Create a TextOutputDev which will write to a generic stream. If
+ // <physLayoutA> is true, the original physical layout of the text
+ // is maintained. If <rawOrder> is true, the text is kept in
+ // content stream order.
+ TextOutputDev(TextOutputFunc func, void *stream,
+- GBool physLayoutA, GBool rawOrderA);
++ GBool physLayoutA, double fixedPitchA,
++ GBool rawOrderA);
+
+ // Destructor.
+ virtual ~TextOutputDev();
+@@ -575,6 +595,10 @@
+ // Does this device need non-text content?
+ virtual GBool needNonText() { return gFalse; }
+
++ // Does this device require incCharCount to be called for text on
++ // non-shown layers?
++ virtual GBool needCharCount() { return gTrue; }
++
+ //----- initialization and control
+
+ // Start a page.
+@@ -583,6 +607,9 @@
+ // End a page.
+ virtual void endPage();
+
++ //----- save/restore graphics state
++ virtual void restoreState(GfxState *state);
++
+ //----- update text state
+ virtual void updateFont(GfxState *state);
+
+@@ -593,6 +620,9 @@
+ double dx, double dy,
+ double originX, double originY,
+ CharCode c, int nBytes, Unicode *u, int uLen);
++ virtual void incCharCount(int nChars);
+@@ -615,6 +645,7 @@
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
++ GBool wholeWord,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+
+@@ -653,6 +684,9 @@
+ TextPage *text; // text for the current page
+ GBool physLayout; // maintain original physical layout when
+ // dumping text
++ double fixedPitch; // if physLayout is true and this is non-zero,
++ // assume fixed-pitch characters with this
++ // width
+ GBool rawOrder; // keep text in content stream order
+ GBool doHTML; // extra processing for HTML conversion
+ GBool ok; // set up ok?
+diff -ru xpdf-3.02/xpdf/XRef.cc xpdf-3.03/xpdf/XRef.cc
+--- xpdf-3.02/xpdf/XRef.cc 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/XRef.cc 2011-08-15 23:08:53.000000000 +0200
+@@ -16,6 +16,7 @@
+ #include <stddef.h>
+ #include <string.h>
+ #include <ctype.h>
++#include <limits.h>
+ #include "gmem.h"
+ #include "Object.h"
+ #include "Stream.h"
+@@ -190,13 +202,14 @@
+ // XRef
+ //------------------------------------------------------------------------
+
+-XRef::XRef(BaseStream *strA) {
++XRef::XRef(BaseStream *strA, GBool repair) {
+ Guint pos;
+ Object obj;
+
+ ok = gTrue;
+ errCode = errNone;
+ size = 0;
++ last = -1;
+ entries = NULL;
+ streamEnds = NULL;
+ streamEndsLen = 0;
+@@ -206,30 +219,32 @@
+ permFlags = defPermFlags;
+ ownerPasswordOk = gFalse;
+
+- // read the trailer
+ str = strA;
+ start = str->getStart();
+- pos = getStartXref();
+
+- // if there was a problem with the 'startxref' position, try to
+- // reconstruct the xref table
+- if (pos == 0) {
++ // if the 'repair' flag is set, try to reconstruct the xref table
++ if (repair) {
+ if (!(ok = constructXRef())) {
+ errCode = errDamaged;
+ return;
+ }
+
+- // read the xref table
++ // if the 'repair' flag is not set, read the xref table
+ } else {
+- while (readXRef(&pos)) ;
+
+- // if there was a problem with the xref table,
+- // try to reconstruct it
++ // read the trailer
++ pos = getStartXref();
++ if (pos == 0) {
++ errCode = errDamaged;
++ ok = gFalse;
++ return;
++ }
++
++ // read the xref table
++ while (readXRef(&pos)) ;
+ if (!ok) {
+- if (!(ok = constructXRef())) {
+- errCode = errDamaged;
+- return;
+- }
++ errCode = errDamaged;
++ return;
+ }
+ }
+
+@@ -288,7 +303,7 @@
+ if (i < 0) {
+ return 0;
+ }
+- for (p = &buf[i+9]; isspace(*p); ++p) ;
++ for (p = &buf[i+9]; isspace(*p & 0xff); ++p) ;
+ lastXRefPos = strToUnsigned(p);
+
+ return lastXRefPos;
+@@ -307,7 +322,7 @@
+ new Lexer(NULL,
+ str->makeSubStream(start + *pos, gFalse, 0, &obj)),
+ gTrue);
+- parser->getObj(&obj);
++ parser->getObj(&obj, gTrue);
+
+ // parse an old-style xref table
+ if (obj.isCmd("xref")) {
+@@ -317,11 +332,11 @@
+ // parse an xref stream
+ } else if (obj.isInt()) {
+ obj.free();
+- if (!parser->getObj(&obj)->isInt()) {
++ if (!parser->getObj(&obj, gTrue)->isInt()) {
+ goto err1;
+ }
+ obj.free();
+- if (!parser->getObj(&obj)->isCmd("obj")) {
++ if (!parser->getObj(&obj, gTrue)->isCmd("obj")) {
+ goto err1;
+ }
+ obj.free();
+@@ -353,7 +368,7 @@
+ int first, n, newSize, i;
+
+ while (1) {
+- parser->getObj(&obj);
++ parser->getObj(&obj, gTrue);
+ if (obj.isCmd("trailer")) {
+ obj.free();
+ break;
+@@ -363,7 +378,7 @@
+ }
+ first = obj.getInt();
+ obj.free();
+- if (!parser->getObj(&obj)->isInt()) {
++ if (!parser->getObj(&obj, gTrue)->isInt()) {
+ goto err1;
+ }
+ n = obj.getInt();
+@@ -386,17 +401,17 @@
+ size = newSize;
+ }
+ for (i = first; i < first + n; ++i) {
+- if (!parser->getObj(&obj)->isInt()) {
++ if (!parser->getObj(&obj, gTrue)->isInt()) {
+ goto err1;
+ }
+ entry.offset = (Guint)obj.getInt();
+ obj.free();
+- if (!parser->getObj(&obj)->isInt()) {
++ if (!parser->getObj(&obj, gTrue)->isInt()) {
+ goto err1;
+ }
+ entry.gen = obj.getInt();
+ obj.free();
+- parser->getObj(&obj);
++ parser->getObj(&obj, gTrue);
+ if (obj.isCmd("n")) {
+ entry.type = xrefEntryUncompressed;
+ } else if (obj.isCmd("f")) {
+@@ -417,6 +432,9 @@
+ entries[0] = entries[1];
+ entries[1].offset = 0xffffffff;
+ }
++ if (i > last) {
++ last = i;
++ }
+ }
+ }
+ }
+@@ -429,13 +447,25 @@
+ // get the 'Prev' pointer
+ obj.getDict()->lookupNF("Prev", &obj2);
+ if (obj2.isInt()) {
+- *pos = (Guint)obj2.getInt();
+- more = gTrue;
++ pos2 = (Guint)obj2.getInt();
++ if (pos2 != *pos) {
++ *pos = pos2;
++ more = gTrue;
++ } else {
++ error(errSyntaxWarning, -1, "Infinite loop in xref table");
++ more = gFalse;
++ }
+ } else if (obj2.isRef()) {
+ // certain buggy PDF generators generate "/Prev NNN 0 R" instead
+ // of "/Prev NNN"
+- *pos = (Guint)obj2.getRefNum();
+- more = gTrue;
++ pos2 = (Guint)obj2.getRefNum();
++ if (pos2 != *pos) {
++ *pos = pos2;
++ more = gTrue;
++ } else {
++ error(errSyntaxWarning, -1, "Infinite loop in xref table");
++ more = gFalse;
++ }
+ } else {
+ more = gFalse;
+ }
+@@ -624,6 +654,9 @@
+ default:
+ return gFalse;
+ }
++ if (i > last) {
++ last = i;
++ }
+ }
+ }
+
+@@ -647,7 +680,6 @@
+ size = 0;
+ entries = NULL;
+
+- error(-1, "PDF file is damaged - attempting to reconstruct xref table....");
+ gotRoot = gFalse;
+ streamEndsLen = streamEndsSize = 0;
+
+@@ -687,30 +719,30 @@
+ delete parser;
+
+ // look for object
+- } else if (isdigit(*p)) {
++ } else if (isdigit(*p & 0xff)) {
+ num = atoi(p);
+ if (num > 0) {
+ do {
+ ++p;
+- } while (*p && isdigit(*p));
+- if (isspace(*p)) {
++ } while (*p && isdigit(*p & 0xff));
++ if (isspace(*p & 0xff)) {
+ do {
+ ++p;
+- } while (*p && isspace(*p));
+- if (isdigit(*p)) {
++ } while (*p && isspace(*p & 0xff));
++ if (isdigit(*p & 0xff)) {
+ gen = atoi(p);
+ do {
+ ++p;
+- } while (*p && isdigit(*p));
+- if (isspace(*p)) {
++ } while (*p && isdigit(*p & 0xff));
++ if (isspace(*p & 0xff)) {
+ do {
+ ++p;
+- } while (*p && isspace(*p));
++ } while (*p && isspace(*p & 0xff));
+ if (!strncmp(p, "obj", 3)) {
+ if (num >= size) {
+ newSize = (num + 1 + 255) & ~255;
+ if (newSize < 0) {
+- error(-1, "Bad object number");
++ error(errSyntaxError, -1, "Bad object number");
+ return gFalse;
+ }
+ entries = (XRefEntry *)
+@@ -726,6 +758,9 @@
+ entries[num].offset = pos - start;
+ entries[num].gen = gen;
+ entries[num].type = xrefEntryUncompressed;
++ if (num > last) {
++ last = num;
++ }
+ }
+ }
+ }
+diff -ru xpdf-3.02/xpdf/XRef.h xpdf-3.03/xpdf/XRef.h
+--- xpdf-3.02/xpdf/XRef.h 2007-02-27 23:05:52.000000000 +0100
++++ xpdf-3.03/xpdf/XRef.h 2011-08-15 23:08:53.000000000 +0200
+@@ -43,7 +43,7 @@
+ public:
+
+ // Constructor. Read xref table from stream.
+- XRef(BaseStream *strA);
++ XRef(BaseStream *strA, GBool repair);
+
+ // Destructor.
+ ~XRef();
+@@ -67,19 +67,20 @@
+ // Get catalog object.
+ Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); }
+
+ // Fetch an indirect reference.
+- Object *fetch(int num, int gen, Object *obj);
++ Object *fetch(int num, int gen, Object *obj, int recursion = 0);
+
+ // Return the document's Info dictionary (if any).
+ Object *getDocInfo(Object *obj);
+ Object *getDocInfoNF(Object *obj);
+
+ // Return the number of objects in the xref table.
+- int getNumObjects() { return size; }
++ int getNumObjects() { return last + 1; }
+
+ // Return the offset of the last xref table.
+ Guint getLastXRefPos() { return lastXRefPos; }
+@@ -104,6 +105,7 @@
+ // at beginning of file)
+ XRefEntry *entries; // xref entries
+ int size; // size of <entries> array
++ int last; // last used index in <entries>
+ int rootNum, rootGen; // catalog dict
+ GBool ok; // true if xref table is valid
+ int errCode; // error code (if <ok> is false) \ No newline at end of file