diff options
author | Albert Astals Cid <aacid@kde.org> | 2012-01-10 23:35:45 +0100 |
---|---|---|
committer | Albert Astals Cid <aacid@kde.org> | 2012-01-10 23:35:45 +0100 |
commit | 431fddbc14548cdce21d94cfa4d3779bc142839f (patch) | |
tree | 07f060b03a484f1f8ae2c831565c8e40e887c015 | |
parent | ddc9703d76b2d07674b61c74246db00aac3eb319 (diff) |
update with Thomas merges
-rw-r--r-- | ALL_DIFF | 28083 |
1 files changed, 11982 insertions, 16101 deletions
@@ -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,
-- ®Key) == 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,
-+ ®Key) == 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, +- ®Key) == 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, ++ ®Key) == 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 |