diff options
author | Albert Astals Cid <aacid@kde.org> | 2012-01-15 23:31:51 +0100 |
---|---|---|
committer | Albert Astals Cid <aacid@kde.org> | 2012-01-15 23:31:51 +0100 |
commit | c885d0cb1e470ae19642f9c03b1c668bbeda1ae9 (patch) | |
tree | c5b2db470f20320221cc4eb8a43813d15e22cd2d | |
parent | 431fddbc14548cdce21d94cfa4d3779bc142839f (diff) |
After more patches from Thomas
-rw-r--r-- | ALL_DIFF | 3613 |
1 files changed, 1 insertions, 3612 deletions
@@ -38,52 +38,6 @@ diff -ru xpdf-3.02/xpdf/Gfx.cc xpdf-3.03/xpdf/Gfx.cc #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; @@ -239,19 +193,6 @@ diff -ru xpdf-3.02/xpdf/Gfx.cc xpdf-3.03/xpdf/Gfx.cc } } 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) { @@ -471,1025 +412,7 @@ diff -ru xpdf-3.02/xpdf/Gfx.cc xpdf-3.03/xpdf/Gfx.cc } } 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; @@ -1657,102 +580,6 @@ diff -ru xpdf-3.02/xpdf/Gfx.cc xpdf-3.03/xpdf/Gfx.cc 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; @@ -1848,44 +675,6 @@ diff -ru xpdf-3.02/xpdf/Gfx.cc xpdf-3.03/xpdf/Gfx.cc 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 @@ -3151,92 +1940,6 @@ diff -ru xpdf-3.02/xpdf/GfxFont.h xpdf-3.03/xpdf/GfxFont.h + 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 @@ -3611,14 +2314,6 @@ diff -ru xpdf-3.02/xpdf/GfxState.cc xpdf-3.03/xpdf/GfxState.cc ++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; @@ -3628,83 +2323,6 @@ diff -ru xpdf-3.02/xpdf/GfxState.cc xpdf-3.03/xpdf/GfxState.cc - } } - // 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 @@ -3729,57 +2347,6 @@ diff -ru xpdf-3.02/xpdf/GfxState.h xpdf-3.03/xpdf/GfxState.h 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 @@ -4789,22 +3356,6 @@ diff -ru xpdf-3.02/xpdf/GlobalParams.cc xpdf-3.03/xpdf/GlobalParams.cc 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 //------------------------------------------------------------------------ @@ -5063,15 +3614,6 @@ diff -ru xpdf-3.02/xpdf/GlobalParams.h xpdf-3.03/xpdf/GlobalParams.h 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 @@ -5099,78 +3641,6 @@ diff -ru xpdf-3.02/xpdf/OutputDev.cc xpdf-3.03/xpdf/OutputDev.cc 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 @@ -7946,14 +6416,6 @@ diff -ru xpdf-3.02/xpdf/PSOutputDev.cc xpdf-3.03/xpdf/PSOutputDev.cc 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) { @@ -8687,17 +7149,6 @@ diff -ru xpdf-3.02/xpdf/PSOutputDev.h xpdf-3.03/xpdf/PSOutputDev.h // 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: @@ -8792,2031 +7243,6 @@ diff -ru xpdf-3.02/xpdf/PSOutputDev.h xpdf-3.03/xpdf/PSOutputDev.h 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 @@ -11108,16 +7534,6 @@ diff -ru xpdf-3.02/xpdf/TextOutputDev.cc xpdf-3.03/xpdf/TextOutputDev.cc 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)); } @@ -11569,10 +7985,6 @@ diff -ru xpdf-3.02/xpdf/TextOutputDev.cc xpdf-3.03/xpdf/TextOutputDev.cc + 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, @@ -11599,13 +8011,6 @@ diff -ru xpdf-3.02/xpdf/TextOutputDev.h xpdf-3.03/xpdf/TextOutputDev.h // 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); @@ -11646,17 +8051,6 @@ diff -ru xpdf-3.02/xpdf/TextOutputDev.h xpdf-3.03/xpdf/TextOutputDev.h // 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(); @@ -11667,11 +8061,6 @@ diff -ru xpdf-3.02/xpdf/TextOutputDev.h xpdf-3.03/xpdf/TextOutputDev.h //----- 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, |