From c885d0cb1e470ae19642f9c03b1c668bbeda1ae9 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Sun, 15 Jan 2012 23:31:51 +0100 Subject: After more patches from Thomas --- ALL_DIFF | 11827 +++++++++++++++++++++---------------------------------------- 1 file changed, 4108 insertions(+), 7719 deletions(-) diff --git a/ALL_DIFF b/ALL_DIFF index 149caaa..e63adba 100644 --- a/ALL_DIFF +++ b/ALL_DIFF @@ -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,2593 +412,1441 @@ 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 @@ + +@@ -3373,7 +3650,7 @@ + GBool maskInvert; + Stream *maskStr; + Object obj1, obj2; +- int i; ++ int i, n; + + // get info from the stream + bits = 0; +@@ -3389,19 +3666,27 @@ + obj1.free(); + dict->lookup("W", &obj1); } - 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 (!obj1.isInt()) ++ if (!obj1.isInt()) { + goto err2; + } -+ -+ if (!(pattern = state->getFillPattern())) { -+ return; + width = obj1.getInt(); + obj1.free(); ++ if (width <= 0) { ++ goto err1; + } -+ 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; + dict->lookup("Height", &obj1); + if (obj1.isNull()) { + obj1.free(); + dict->lookup("H", &obj1); } - } +- if (!obj1.isInt()) ++ if (!obj1.isInt()) { + goto err2; ++ } + height = obj1.getInt(); + obj1.free(); ++ if (height <= 0) { ++ goto err1; ++ } -+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()); - } + // image or mask? + dict->lookup("ImageMask", &obj1); +@@ -3447,16 +3732,30 @@ } - } - - // restore graphics state - err: -- restoreState(); -- state->setPath(savedPath); -+ restoreStateStack(savedState); - } + if (obj1.isArray()) { + obj1.arrayGet(0, &obj2); +- if (obj2.isInt() && obj2.getInt() == 1) +- invert = gTrue; ++ invert = obj2.isNum() && obj2.getNum() == 1; + obj2.free(); + } else if (!obj1.isNull()) { + goto err2; + } + obj1.free(); - 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(); ++ // if drawing is disabled, skip over inline image data ++ if (!ocState) { ++ str->reset(); ++ n = height * ((width + 7) / 8); ++ for (i = 0; i < n; ++i) { ++ str->getChar(); ++ } ++ str->close(); ++ + // draw it +- out->drawImageMask(state, ref, str, width, height, invert, inlineImg); ++ } else { ++ if (state->getFillColorSpace()->getMode() == csPattern) { ++ doPatternImageMask(ref, str, width, height, invert, inlineImg); ++ } else { ++ out->drawImageMask(state, ref, str, width, height, invert, inlineImg); ++ } ++ } - // 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(); + } else { - // 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); +@@ -3581,14 +3880,36 @@ + haveSoftMask = gTrue; + } else if (maskObj.isArray()) { + // color key mask ++ haveColorKeyMask = gTrue; + for (i = 0; +- i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps; +- ++i) { ++ i+1 < maskObj.arrayGetLength() && i+1 < 2*gfxColorMaxComps; ++ i += 2) { + maskObj.arrayGet(i, &obj1); ++ if (!obj1.isInt()) { ++ obj1.free(); ++ haveColorKeyMask = gFalse; ++ break; ++ } + maskColors[i] = obj1.getInt(); + obj1.free(); ++ if (maskColors[i] < 0 || maskColors[i] >= (1 << bits)) { ++ haveColorKeyMask = gFalse; ++ break; ++ } ++ maskObj.arrayGet(i+1, &obj1); ++ if (!obj1.isInt()) { ++ obj1.free(); ++ haveColorKeyMask = gFalse; ++ break; ++ } ++ maskColors[i+1] = obj1.getInt(); ++ obj1.free(); ++ if (maskColors[i+1] < 0 || maskColors[i+1] >= (1 << bits) || ++ maskColors[i] > maskColors[i+1]) { ++ haveColorKeyMask = gFalse; ++ break; ++ } + } +- haveColorKeyMask = gTrue; + } else if (maskObj.isStream()) { + // explicit mask + if (inlineImg) { +@@ -3633,9 +3954,7 @@ + } + if (obj1.isArray()) { + obj1.arrayGet(0, &obj2); +- if (obj2.isInt() && obj2.getInt() == 1) { +- maskInvert = gTrue; +- } ++ maskInvert = obj2.isNum() && obj2.getNum() == 1; + obj2.free(); + } else if (!obj1.isNull()) { + goto err2; +@@ -3644,20 +3963,32 @@ + haveExplicitMask = gTrue; } - } -- -- // 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 drawing is disabled, skip over inline image data ++ if (!ocState) { ++ str->reset(); ++ n = height * ((width * colorMap->getNumPixelComps() * ++ colorMap->getBits() + 7) / 8); ++ for (i = 0; i < n; ++i) { ++ str->getChar(); ++ } ++ str->close(); + -+#if 1 //~tmp: turn off anti-aliasing temporarily -+ out->setInShading(gTrue); - #endif + // draw it +- if (haveSoftMask) { +- out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, +- maskStr, maskWidth, maskHeight, maskColorMap); +- delete maskColorMap; +- } else if (haveExplicitMask) { +- out->drawMaskedImage(state, ref, str, width, height, colorMap, +- maskStr, maskWidth, maskHeight, maskInvert); + } else { +- out->drawImage(state, ref, str, width, height, colorMap, +- haveColorKeyMask ? maskColors : (int *)NULL, inlineImg); ++ if (haveSoftMask) { ++ out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, ++ maskStr, maskWidth, maskHeight, maskColorMap); ++ delete maskColorMap; ++ } else if (haveExplicitMask) { ++ out->drawMaskedImage(state, ref, str, width, height, colorMap, ++ maskStr, maskWidth, maskHeight, maskInvert); ++ } else { ++ out->drawImage(state, ref, str, width, height, colorMap, ++ haveColorKeyMask ? maskColors : (int *)NULL, inlineImg); ++ } + } +- delete colorMap; - // do shading type-specific operations -@@ -1890,28 +2062,28 @@ ++ delete colorMap; + maskObj.free(); + smaskObj.free(); } +@@ -3869,6 +4218,9 @@ + Stream *str; + int c1, c2; - #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; -+ } ++ // NB: this function is run even if ocState is false -- doImage() is ++ // responsible for skipping over the inline image data + - if (!(shading = res->lookupShading(args[0].getName()))) { - return; - } + // build dict/stream + str = buildImageStream(); - // save current graphics state -- savedPath = state->getPath()->copy(); -- saveState(); -+ savedState = saveStateStack(); +@@ -3921,18 +4274,23 @@ + obj.free(); - // clip to bbox - if (shading->getHasBBox()) { -@@ -1931,10 +2103,7 @@ - out->updateFillColorSpace(state); + // make stream +- str = new EmbedStream(parser->getStream(), &dict, gFalse, 0); ++ if (!(str = parser->getStream())) { ++ error(errSyntaxError, getPos(), "Invalid inline image data"); ++ dict.free(); ++ return NULL; ++ } ++ str = new EmbedStream(str, &dict, gFalse, 0); + str = str->addFilters(&dict); - #if 1 //~tmp: turn off anti-aliasing temporarily -- GBool vaa = out->getVectorAntialias(); -- if (vaa) { -- out->setVectorAntialias(gFalse); -- } -+ out->setInShading(gTrue); - #endif + return str; + } - // do shading type-specific operations -@@ -1959,14 +2128,11 @@ - } + void Gfx::opImageData(Object args[], int numArgs) { + error(errInternal, getPos(), "Got 'ID' operator"); + } - #if 1 //~tmp: turn off anti-aliasing temporarily -- if (vaa) { -- out->setVectorAntialias(gTrue); -- } -+ out->setInShading(gFalse); - #endif + void Gfx::opEndImage(Object args[], int numArgs) { + error(errInternal, getPos(), "Got 'EI' operator"); + } - // restore graphics state -- restoreState(); -- state->setPath(savedPath); -+ restoreStateStack(savedState); + //------------------------------------------------------------------------ +@@ -3967,23 +4325,88 @@ + //------------------------------------------------------------------------ - 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; + void Gfx::opBeginMarkedContent(Object args[], int numArgs) { ++ GfxMarkedContent *mc; ++ Object obj; ++ GBool ocStateNew; ++ GString *s; ++ Unicode *u; ++ int uLen, i; ++ GfxMarkedContentKind mcKind; ++ + if (printCommands) { + printf(" marked content: %s ", args[0].getName()); +- if (numArgs == 2) +- args[2].print(stdout); ++ if (numArgs == 2) { ++ args[1].print(stdout); + } -+ 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); + printf("\n"); + fflush(stdout); } - 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 ++ mcKind = gfxMCOther; ++ if (args[0].isName("OC") && numArgs == 2 && args[1].isName() && ++ res->lookupPropertiesNF(args[1].getName(), &obj)) { ++ if (doc->getOptionalContent()->evalOCObject(&obj, &ocStateNew)) { ++ ocState = ocStateNew; + } -+ // 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; ++ obj.free(); ++ mcKind = gfxMCOptionalContent; } - void Gfx::opEndText(Object args[], int numArgs) { -@@ -3028,19 +3213,23 @@ + void Gfx::opEndMarkedContent(Object args[], int numArgs) { ++ GfxMarkedContent *mc; ++ GfxMarkedContentKind mcKind; ++ ++ if (markedContentStack->getLength() > 0) { ++ mc = (GfxMarkedContent *) ++ markedContentStack->del(markedContentStack->getLength() - 1); ++ mcKind = mc->kind; ++ delete mc; ++ if (mcKind == gfxMCOptionalContent) { ++ if (markedContentStack->getLength() > 0) { ++ mc = (GfxMarkedContent *) ++ markedContentStack->get(markedContentStack->getLength() - 1); ++ ocState = mc->ocState; ++ } else { ++ ocState = gTrue; ++ } + - void Gfx::opShowText(Object args[], int numArgs) { - if (!state->getFont()) { -- error(getPos(), "No font in show"); -+ error(errSyntaxError, getPos(), "No font in show"); - return; + void Gfx::opMarkPoint(Object args[], int numArgs) { + if (printCommands) { + printf(" mark point: %s ", args[0].getName()); + if (numArgs == 2) +- args[2].print(stdout); ++ args[1].print(stdout); + printf("\n"); + fflush(stdout); } - 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()); -+ } - } +diff -ru xpdf-3.02/xpdf/GfxFont.cc xpdf-3.03/xpdf/GfxFont.cc +--- xpdf-3.02/xpdf/GfxFont.cc 2007-02-27 23:05:52.000000000 +0100 ++++ xpdf-3.03/xpdf/GfxFont.cc 2011-08-15 23:08:53.000000000 +0200 +@@ -16,6 +16,11 @@ + #include + #include + #include ++#include ++#include ++#if HAVE_STD_SORT ++#include ++#endif + #include "gmem.h" + #include "Error.h" + #include "Object.h" +@@ -25,6 +30,7 @@ + #include "CharCodeToUnicode.h" + #include "FontEncodingTables.h" + #include "BuiltinFontTables.h" ++#include "FoFiIdentifier.h" + #include "FoFiType1.h" + #include "FoFiType1C.h" + #include "FoFiTrueType.h" +@@ -93,15 +107,66 @@ + GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) { + GString *nameA; ++ Ref embFontIDA; ++ GfxFontType typeA; + GfxFont *font; + Object obj1; - 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()); -+ } - } +@@ -113,53 +178,235 @@ + } + obj1.free(); - 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()); -+ } +- // get font type ++ // get embedded font ID and font type ++ typeA = getFontType(xref, fontDict, &embFontIDA); ++ ++ // create the font object + font = NULL; +- fontDict->lookup("Subtype", &obj1); +- if (obj1.isName("Type1") || obj1.isName("MMType1")) { +- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict); +- } else if (obj1.isName("Type1C")) { +- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict); +- } else if (obj1.isName("Type3")) { +- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict); +- } else if (obj1.isName("TrueType")) { +- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict); +- } else if (obj1.isName("Type0")) { +- font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict); ++ if (typeA < fontCIDType0) { ++ font = new Gfx8BitFont(xref, tagA, idA, nameA, typeA, embFontIDA, ++ fontDict); + } else { +- error(-1, "Unknown font type: '%s'", +- obj1.isName() ? obj1.getName() : "???"); +- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict); ++ font = new GfxCIDFont(xref, tagA, idA, nameA, typeA, embFontIDA, ++ fontDict); + } +- obj1.free(); + + return font; } - void Gfx::opShowSpaceText(Object args[], int numArgs) { -@@ -3091,37 +3288,48 @@ - int i; +-GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA) { ++GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA, ++ GfxFontType typeA, Ref embFontIDA) { + ok = gFalse; + tag = new GString(tagA); + id = idA; + name = nameA; ++ type = typeA; ++ embFontID = embFontIDA; + embFontName = NULL; +- extFontFile = NULL; + } - if (!state->getFont()) { -- error(getPos(), "No font in show/space"); -+ error(errSyntaxError, getPos(), "No font in show/space"); - return; + GfxFont::~GfxFont() { + delete tag; + if (name) { + delete name; } - 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); + if (embFontName) { + delete embFontName; + } +- if (extFontFile) { +- delete extFontFile; ++} ++ ++// This function extracts three pieces of information: ++// 1. the "expected" font type, i.e., the font type implied by ++// Font.Subtype, DescendantFont.Subtype, and ++// FontDescriptor.FontFile3.Subtype ++// 2. the embedded font object ID ++// 3. the actual font type - determined by examining the embedded font ++// if there is one, otherwise equal to the expected font type ++// If the expected and actual font types don't match, a warning ++// message is printed. The expected font type is not used for ++// anything else. ++GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) { ++ GfxFontType t, expectedType; ++ FoFiIdentifierType fft; ++ Dict *fontDict2; ++ Object subtype, fontDesc, obj1, obj2, obj3, obj4; ++ GBool isType0, err; ++ ++ t = fontUnknownType; ++ embID->num = embID->gen = -1; ++ err = gFalse; ++ ++ fontDict->lookup("Subtype", &subtype); ++ expectedType = fontUnknownType; ++ isType0 = gFalse; ++ if (subtype.isName("Type1") || subtype.isName("MMType1")) { ++ expectedType = fontType1; ++ } else if (subtype.isName("Type1C")) { ++ expectedType = fontType1C; ++ } else if (subtype.isName("Type3")) { ++ expectedType = fontType3; ++ } else if (subtype.isName("TrueType")) { ++ expectedType = fontTrueType; ++ } else if (subtype.isName("Type0")) { ++ isType0 = gTrue; + } else { -+ a = args[0].getArray(); -+ for (i = 0; i < a->getLength(); ++i) { -+ a->get(i, &obj); -+ if (obj.isString()) { -+ doIncCharCount(obj.getString()); ++ error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'", ++ subtype.isName() ? subtype.getName() : "???"); ++ } ++ subtype.free(); ++ ++ fontDict2 = fontDict; ++ if (fontDict->lookup("DescendantFonts", &obj1)->isArray()) { ++ if (obj1.arrayGetLength() == 0) { ++ error(errSyntaxWarning, -1, "Empty DescendantFonts array in font"); ++ obj2.initNull(); ++ } else if (obj1.arrayGet(0, &obj2)->isDict()) { ++ if (!isType0) { ++ error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array"); + } -+ 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; ++ fontDict2 = obj2.getDict(); ++ fontDict2->lookup("Subtype", &subtype); ++ if (subtype.isName("CIDFontType0")) { ++ if (isType0) { ++ expectedType = fontCIDType0; ++ } ++ } else if (subtype.isName("CIDFontType2")) { ++ if (isType0) { ++ expectedType = fontCIDType2; ++ } ++ } ++ subtype.free(); + } -+ state->setRender(render); -+ out->updateRender(state); + } else { -+ patternFill = gFalse; ++ obj2.initNull(); + } + -+ 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; ++ if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) { ++ if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) { ++ *embID = obj3.getRef(); ++ if (expectedType != fontType1) { ++ err = gTrue; ++ } + } -+ 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; ++ obj3.free(); ++ if (embID->num == -1 && ++ fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) { ++ *embID = obj3.getRef(); ++ if (isType0) { ++ expectedType = fontCIDType2; ++ } else if (expectedType != fontTrueType) { ++ err = gTrue; ++ } + } -+ dy = fabs(dy); -+ dy2 = fabs(dy2); -+ if (dy2 > dy) { -+ dy = dy2; ++ obj3.free(); ++ if (embID->num == -1 && ++ fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) { ++ *embID = obj3.getRef(); ++ if (obj3.fetch(xref, &obj4)->isStream()) { ++ obj4.streamGetDict()->lookup("Subtype", &subtype); ++ if (subtype.isName("Type1")) { ++ if (expectedType != fontType1) { ++ err = gTrue; ++ expectedType = isType0 ? fontCIDType0 : fontType1; ++ } ++ } else if (subtype.isName("Type1C")) { ++ if (expectedType == fontType1) { ++ expectedType = fontType1C; ++ } else if (expectedType != fontType1C) { ++ err = gTrue; ++ expectedType = isType0 ? fontCIDType0C : fontType1C; ++ } ++ } else if (subtype.isName("TrueType")) { ++ if (expectedType != fontTrueType) { ++ err = gTrue; ++ expectedType = isType0 ? fontCIDType2 : fontTrueType; ++ } ++ } else if (subtype.isName("CIDFontType0C")) { ++ if (expectedType == fontCIDType0) { ++ expectedType = fontCIDType0C; ++ } else { ++ err = gTrue; ++ expectedType = isType0 ? fontCIDType0C : fontType1C; ++ } ++ } else if (subtype.isName("OpenType")) { ++ if (expectedType == fontTrueType) { ++ expectedType = fontTrueTypeOT; ++ } else if (expectedType == fontType1) { ++ expectedType = fontType1COT; ++ } else if (expectedType == fontCIDType0) { ++ expectedType = fontCIDType0COT; ++ } else if (expectedType == fontCIDType2) { ++ expectedType = fontCIDType2OT; ++ } else { ++ err = gTrue; ++ } ++ } else { ++ error(errSyntaxError, -1, "Unknown font type '{0:s}'", ++ subtype.isName() ? subtype.getName() : "???"); ++ } ++ subtype.free(); ++ } ++ obj4.free(); + } -+ 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()); ++ obj3.free(); + } -+} ++ fontDesc.free(); + - //------------------------------------------------------------------------ - // XObject operators - //------------------------------------------------------------------------ -@@ -3308,8 +3580,11 @@ - Object opiDict; - #endif - -+ if (!ocState && !out->needCharCount()) { -+ return; -+ } - name = args[0].getName(); - if (!res->lookupXObject(name, &obj1)) { - return; - } - if (!obj1.isStream()) { -@@ -3373,7 +3650,7 @@ - GBool maskInvert; - Stream *maskStr; - Object obj1, obj2; -- int i; -+ int i, n; - - // get info from the stream - bits = 0; -@@ -3389,19 +3666,27 @@ - obj1.free(); - dict->lookup("W", &obj1); - } -- if (!obj1.isInt()) -+ if (!obj1.isInt()) { - goto err2; -+ } - width = obj1.getInt(); - obj1.free(); -+ if (width <= 0) { -+ goto err1; -+ } - dict->lookup("Height", &obj1); - if (obj1.isNull()) { - obj1.free(); - dict->lookup("H", &obj1); - } -- if (!obj1.isInt()) -+ if (!obj1.isInt()) { - goto err2; -+ } - height = obj1.getInt(); - obj1.free(); -+ if (height <= 0) { -+ goto err1; -+ } - - // image or mask? - dict->lookup("ImageMask", &obj1); -@@ -3447,16 +3732,30 @@ - } - if (obj1.isArray()) { - obj1.arrayGet(0, &obj2); -- if (obj2.isInt() && obj2.getInt() == 1) -- invert = gTrue; -+ invert = obj2.isNum() && obj2.getNum() == 1; - obj2.free(); - } else if (!obj1.isNull()) { - goto err2; - } - obj1.free(); - -+ // if drawing is disabled, skip over inline image data -+ if (!ocState) { -+ str->reset(); -+ n = height * ((width + 7) / 8); -+ for (i = 0; i < n; ++i) { -+ str->getChar(); -+ } -+ str->close(); -+ - // draw it -- out->drawImageMask(state, ref, str, width, height, invert, inlineImg); -+ } else { -+ if (state->getFillColorSpace()->getMode() == csPattern) { -+ doPatternImageMask(ref, str, width, height, invert, inlineImg); -+ } else { -+ out->drawImageMask(state, ref, str, width, height, invert, inlineImg); ++ t = fontUnknownType; ++ if (embID->num >= 0) { ++ obj3.initRef(embID->num, embID->gen); ++ obj3.fetch(xref, &obj4); ++ if (obj4.isStream()) { ++ obj4.streamReset(); ++ fft = FoFiIdentifier::identifyStream(&readFromStream, obj4.getStream()); ++ obj4.streamClose(); ++ switch (fft) { ++ case fofiIdType1PFA: ++ case fofiIdType1PFB: ++ t = fontType1; ++ break; ++ case fofiIdCFF8Bit: ++ t = isType0 ? fontCIDType0C : fontType1C; ++ break; ++ case fofiIdCFFCID: ++ t = fontCIDType0C; ++ break; ++ case fofiIdTrueType: ++ case fofiIdTrueTypeCollection: ++ t = isType0 ? fontCIDType2 : fontTrueType; ++ break; ++ case fofiIdOpenTypeCFF8Bit: ++ t = isType0 ? fontCIDType0COT : fontType1COT; ++ break; ++ case fofiIdOpenTypeCFFCID: ++ t = fontCIDType0COT; ++ break; ++ default: ++ error(errSyntaxError, -1, "Embedded font file may be invalid"); ++ break; + } + } - - } else { - -@@ -3581,14 +3880,36 @@ - haveSoftMask = gTrue; - } else if (maskObj.isArray()) { - // color key mask -+ haveColorKeyMask = gTrue; - for (i = 0; -- i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps; -- ++i) { -+ i+1 < maskObj.arrayGetLength() && i+1 < 2*gfxColorMaxComps; -+ i += 2) { - maskObj.arrayGet(i, &obj1); -+ if (!obj1.isInt()) { -+ obj1.free(); -+ haveColorKeyMask = gFalse; -+ break; -+ } - maskColors[i] = obj1.getInt(); - obj1.free(); -+ if (maskColors[i] < 0 || maskColors[i] >= (1 << bits)) { -+ haveColorKeyMask = gFalse; -+ break; -+ } -+ maskObj.arrayGet(i+1, &obj1); -+ if (!obj1.isInt()) { -+ obj1.free(); -+ haveColorKeyMask = gFalse; -+ break; -+ } -+ maskColors[i+1] = obj1.getInt(); -+ obj1.free(); -+ if (maskColors[i+1] < 0 || maskColors[i+1] >= (1 << bits) || -+ maskColors[i] > maskColors[i+1]) { -+ haveColorKeyMask = gFalse; -+ break; -+ } - } -- haveColorKeyMask = gTrue; - } else if (maskObj.isStream()) { - // explicit mask - if (inlineImg) { -@@ -3633,9 +3954,7 @@ - } - if (obj1.isArray()) { - obj1.arrayGet(0, &obj2); -- if (obj2.isInt() && obj2.getInt() == 1) { -- maskInvert = gTrue; -- } -+ maskInvert = obj2.isNum() && obj2.getNum() == 1; - obj2.free(); - } else if (!obj1.isNull()) { - goto err2; -@@ -3644,20 +3963,32 @@ - haveExplicitMask = gTrue; - } - -+ // if drawing is disabled, skip over inline image data -+ if (!ocState) { -+ str->reset(); -+ n = height * ((width * colorMap->getNumPixelComps() * -+ colorMap->getBits() + 7) / 8); -+ for (i = 0; i < n; ++i) { -+ str->getChar(); -+ } -+ str->close(); ++ obj4.free(); ++ obj3.free(); ++ } + - // draw it -- if (haveSoftMask) { -- out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, -- maskStr, maskWidth, maskHeight, maskColorMap); -- delete maskColorMap; -- } else if (haveExplicitMask) { -- out->drawMaskedImage(state, ref, str, width, height, colorMap, -- maskStr, maskWidth, maskHeight, maskInvert); - } else { -- out->drawImage(state, ref, str, width, height, colorMap, -- haveColorKeyMask ? maskColors : (int *)NULL, inlineImg); -+ if (haveSoftMask) { -+ out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, -+ maskStr, maskWidth, maskHeight, maskColorMap); -+ delete maskColorMap; -+ } else if (haveExplicitMask) { -+ out->drawMaskedImage(state, ref, str, width, height, colorMap, -+ maskStr, maskWidth, maskHeight, maskInvert); -+ } else { -+ out->drawImage(state, ref, str, width, height, colorMap, -+ haveColorKeyMask ? maskColors : (int *)NULL, inlineImg); -+ } - } -- delete colorMap; - -+ delete colorMap; - maskObj.free(); - smaskObj.free(); - } -@@ -3683,11 +4014,12 @@ - double m[6], bbox[4]; - Object resObj; - Dict *resDict; -+ GBool oc, ocSaved; - Object obj1, obj2, obj3; - int i; - - // check for excessive recursion - if (formDepth > 100) { - return; ++ if (t == fontUnknownType) { ++ t = expectedType; } - -@@ -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"); ++ ++ if (t != expectedType) { ++ err = gTrue; + } -+ 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(); ++ if (err) { ++ error(errSyntaxWarning, -1, ++ "Mismatch between font type and embedded font file"); ++ } ++ ++ obj2.free(); ++ obj1.free(); + -+ ocState = ocSaved; ++ return t; } --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); + void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { +@@ -170,8 +417,6 @@ + // assume Times-Roman by default (for substitution purposes) + flags = fontSerif; - // pop resource stack - popResources(); -@@ -3869,6 +4218,9 @@ - Stream *str; - int c1, c2; +- embFontID.num = -1; +- embFontID.gen = -1; + missingWidth = 0; -+ // NB: this function is run even if ocState is false -- doImage() is -+ // responsible for skipping over the inline image data -+ - // build dict/stream - str = buildImageStream(); + if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) { +@@ -189,75 +434,6 @@ + } + obj2.free(); -@@ -3921,18 +4274,23 @@ - obj.free(); - - // make stream -- str = new EmbedStream(parser->getStream(), &dict, gFalse, 0); -+ if (!(str = parser->getStream())) { -+ error(errSyntaxError, getPos(), "Invalid inline image data"); -+ dict.free(); -+ return NULL; -+ } -+ str = new EmbedStream(str, &dict, gFalse, 0); - str = str->addFilters(&dict); - - return str; - } - - void Gfx::opImageData(Object args[], int numArgs) { - error(errInternal, getPos(), "Got 'ID' operator"); - } +- // look for embedded font file +- if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) { +- embFontID = obj2.getRef(); +- if (type != fontType1) { +- error(-1, "Mismatch between font type and embedded font file"); +- type = fontType1; +- } +- } +- obj2.free(); +- if (embFontID.num == -1 && +- obj1.dictLookupNF("FontFile2", &obj2)->isRef()) { +- embFontID = obj2.getRef(); +- if (type != fontTrueType && type != fontCIDType2) { +- error(-1, "Mismatch between font type and embedded font file"); +- type = type == fontCIDType0 ? fontCIDType2 : fontTrueType; +- } +- } +- obj2.free(); +- if (embFontID.num == -1 && +- obj1.dictLookupNF("FontFile3", &obj2)->isRef()) { +- if (obj2.fetch(xref, &obj3)->isStream()) { +- obj3.streamGetDict()->lookup("Subtype", &obj4); +- if (obj4.isName("Type1")) { +- embFontID = obj2.getRef(); +- if (type != fontType1) { +- error(-1, "Mismatch between font type and embedded font file"); +- type = fontType1; +- } +- } else if (obj4.isName("Type1C")) { +- embFontID = obj2.getRef(); +- if (type != fontType1 && type != fontType1C) { +- error(-1, "Mismatch between font type and embedded font file"); +- } +- type = fontType1C; +- } else if (obj4.isName("TrueType")) { +- embFontID = obj2.getRef(); +- if (type != fontTrueType) { +- error(-1, "Mismatch between font type and embedded font file"); +- type = fontTrueType; +- } +- } else if (obj4.isName("CIDFontType0C")) { +- embFontID = obj2.getRef(); +- if (type != fontCIDType0) { +- error(-1, "Mismatch between font type and embedded font file"); +- } +- type = fontCIDType0C; +- } else if (obj4.isName("OpenType")) { +- embFontID = obj2.getRef(); +- if (type == fontTrueType) { +- type = fontTrueTypeOT; +- } else if (type == fontType1) { +- type = fontType1COT; +- } else if (type == fontCIDType0) { +- type = fontCIDType0COT; +- } else if (type == fontCIDType2) { +- type = fontCIDType2OT; +- } else { +- error(-1, "Mismatch between font type and embedded font file"); +- } +- } else { +- error(-1, "Unknown embedded font type '%s'", +- obj4.isName() ? obj4.getName() : "???"); +- } +- obj4.free(); +- } +- obj3.free(); +- } +- obj2.free(); +- + // look for MissingWidth + obj1.dictLookup("MissingWidth", &obj2); + if (obj2.isNum()) { +@@ -269,8 +445,13 @@ + obj1.dictLookup("Ascent", &obj2); + if (obj2.isNum()) { + t = 0.001 * obj2.getNum(); +- // some broken font descriptors set ascent and descent to 0 +- if (t != 0) { ++ // some broken font descriptors specify a negative ascent ++ if (t < 0) { ++ t = -t; ++ } ++ // some broken font descriptors set ascent and descent to 0; ++ // others set it to ridiculous values (e.g., 32768) ++ if (t != 0 && t < 3) { + ascent = t; + } + } +@@ -278,14 +459,14 @@ + obj1.dictLookup("Descent", &obj2); + if (obj2.isNum()) { + t = 0.001 * obj2.getNum(); ++ // some broken font descriptors specify a positive descent ++ if (t > 0) { ++ t = -t; ++ } + // some broken font descriptors set ascent and descent to 0 +- if (t != 0) { ++ if (t != 0 && t > -3) { + descent = t; + } +- // some broken font descriptors specify a positive descent +- if (descent > 0) { +- descent = -descent; +- } + } + obj2.free(); - void Gfx::opEndImage(Object args[], int numArgs) { - error(errInternal, getPos(), "Got 'EI' operator"); +@@ -330,37 +511,280 @@ + return ctu; } - //------------------------------------------------------------------------ -@@ -3967,23 +4325,88 @@ - //------------------------------------------------------------------------ +-void GfxFont::findExtFontFile() { +- static char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL }; +- static char *ttExts[] = { ".ttf", NULL }; ++GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) { ++ GfxFontLoc *fontLoc; ++ SysFontType sysFontType; ++ GString *path, *base14Name, *substName; ++ PSFontParam16 *psFont16; ++ Object refObj, embFontObj; ++ int substIdx, fontNum; ++ GBool embed; - void Gfx::opBeginMarkedContent(Object args[], int numArgs) { -+ GfxMarkedContent *mc; -+ Object obj; -+ GBool ocStateNew; -+ GString *s; -+ Unicode *u; -+ int uLen, i; -+ GfxMarkedContentKind mcKind; +- if (name) { +- if (type == fontType1) { +- extFontFile = globalParams->findFontFile(name, type1Exts); +- } else if (type == fontTrueType) { +- extFontFile = globalParams->findFontFile(name, ttExts); ++ if (type == fontType3) { ++ return NULL; ++ } + - if (printCommands) { - printf(" marked content: %s ", args[0].getName()); -- if (numArgs == 2) -- args[2].print(stdout); -+ if (numArgs == 2) { -+ args[1].print(stdout); -+ } - printf("\n"); - fflush(stdout); - } -+ mcKind = gfxMCOther; -+ if (args[0].isName("OC") && numArgs == 2 && args[1].isName() && -+ res->lookupPropertiesNF(args[1].getName(), &obj)) { -+ if (doc->getOptionalContent()->evalOCObject(&obj, &ocStateNew)) { -+ ocState = ocStateNew; ++ //----- embedded font ++ if (embFontID.num >= 0) { ++ embed = gTrue; ++ refObj.initRef(embFontID.num, embFontID.gen); ++ refObj.fetch(xref, &embFontObj); ++ if (!embFontObj.isStream()) { ++ error(errSyntaxError, -1, "Embedded font object is wrong type"); ++ embed = gFalse; + } -+ obj.free(); -+ mcKind = gfxMCOptionalContent; - } - - void Gfx::opEndMarkedContent(Object args[], int numArgs) { -+ GfxMarkedContent *mc; -+ GfxMarkedContentKind mcKind; -+ -+ if (markedContentStack->getLength() > 0) { -+ mc = (GfxMarkedContent *) -+ markedContentStack->del(markedContentStack->getLength() - 1); -+ mcKind = mc->kind; -+ delete mc; -+ if (mcKind == gfxMCOptionalContent) { -+ if (markedContentStack->getLength() > 0) { -+ mc = (GfxMarkedContent *) -+ markedContentStack->get(markedContentStack->getLength() - 1); -+ ocState = mc->ocState; -+ } else { -+ ocState = gTrue; ++ embFontObj.free(); ++ refObj.free(); ++ if (embed) { ++ if (ps) { ++ switch (type) { ++ case fontType1: ++ case fontType1C: ++ case fontType1COT: ++ embed = globalParams->getPSEmbedType1(); ++ break; ++ case fontTrueType: ++ case fontTrueTypeOT: ++ embed = globalParams->getPSEmbedTrueType(); ++ break; ++ case fontCIDType0C: ++ case fontCIDType0COT: ++ embed = globalParams->getPSEmbedCIDPostScript(); ++ break; ++ case fontCIDType2: ++ case fontCIDType2OT: ++ embed = globalParams->getPSEmbedCIDTrueType(); ++ break; ++ default: ++ break; ++ } + } - - - void Gfx::opMarkPoint(Object args[], int numArgs) { - if (printCommands) { - printf(" mark point: %s ", args[0].getName()); - if (numArgs == 2) -- args[2].print(stdout); -+ args[1].print(stdout); - printf("\n"); - fflush(stdout); - } -@@ -3996,45 +4419,23 @@ - dict->lookup("Resources", &resObj); - resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; - - // draw it -- doForm1(str, resDict, m, bbox); -+ drawForm(str, resDict, m, bbox); - - resObj.free(); - } -@@ -4168,6 +4598,27 @@ - out->restoreState(state); - } - -+// Create a new state stack, and initialize it with a copy of the -+// current state. -+GfxState *Gfx::saveStateStack() { -+ GfxState *oldState; -+ -+ out->saveState(state); -+ oldState = state; -+ state = state->copy(gTrue); -+ return oldState; -+} -+ -+// Switch back to the previous state stack. -+void Gfx::restoreStateStack(GfxState *oldState) { -+ while (state->hasSaves()) { -+ restoreState(); ++ if (embed) { ++ fontLoc = new GfxFontLoc(); ++ fontLoc->locType = gfxFontLocEmbedded; ++ fontLoc->fontType = type; ++ fontLoc->embFontID = embFontID; ++ return fontLoc; ++ } ++ } + } -+ delete state; -+ state = oldState; -+ out->restoreState(state); -+} -+ - void Gfx::pushResources(Dict *resDict) { - res = new GfxResources(xref, resDict, res); - } -diff -ru xpdf-3.02/xpdf/GfxFont.cc xpdf-3.03/xpdf/GfxFont.cc ---- xpdf-3.02/xpdf/GfxFont.cc 2007-02-27 23:05:52.000000000 +0100 -+++ xpdf-3.03/xpdf/GfxFont.cc 2011-08-15 23:08:53.000000000 +0200 -@@ -16,6 +16,11 @@ - #include - #include - #include -+#include -+#include -+#if HAVE_STD_SORT -+#include -+#endif - #include "gmem.h" - #include "Error.h" - #include "Object.h" -@@ -25,6 +30,7 @@ - #include "CharCodeToUnicode.h" - #include "FontEncodingTables.h" - #include "BuiltinFontTables.h" -+#include "FoFiIdentifier.h" - #include "FoFiType1.h" - #include "FoFiType1C.h" - #include "FoFiTrueType.h" -@@ -93,15 +107,66 @@ - GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) { - GString *nameA; -+ Ref embFontIDA; -+ GfxFontType typeA; - GfxFont *font; - Object obj1; - -@@ -113,53 +178,235 @@ - } - obj1.free(); - -- // get font type -+ // get embedded font ID and font type -+ typeA = getFontType(xref, fontDict, &embFontIDA); + -+ // create the font object - font = NULL; -- fontDict->lookup("Subtype", &obj1); -- if (obj1.isName("Type1") || obj1.isName("MMType1")) { -- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict); -- } else if (obj1.isName("Type1C")) { -- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict); -- } else if (obj1.isName("Type3")) { -- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict); -- } else if (obj1.isName("TrueType")) { -- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict); -- } else if (obj1.isName("Type0")) { -- font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict); -+ if (typeA < fontCIDType0) { -+ font = new Gfx8BitFont(xref, tagA, idA, nameA, typeA, embFontIDA, -+ fontDict); - } else { -- error(-1, "Unknown font type: '%s'", -- obj1.isName() ? obj1.getName() : "???"); -- font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict); -+ font = new GfxCIDFont(xref, tagA, idA, nameA, typeA, embFontIDA, -+ fontDict); - } -- obj1.free(); - - return font; - } - --GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA) { -+GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA, -+ GfxFontType typeA, Ref embFontIDA) { - ok = gFalse; - tag = new GString(tagA); - id = idA; - name = nameA; -+ type = typeA; -+ embFontID = embFontIDA; - embFontName = NULL; -- extFontFile = NULL; - } - - GfxFont::~GfxFont() { - delete tag; - if (name) { - delete name; - } - if (embFontName) { - delete embFontName; - } -- if (extFontFile) { -- delete extFontFile; -+} ++ //----- PS passthrough ++ if (ps && !isCIDFont() && globalParams->getPSFontPassthrough()) { ++ fontLoc = new GfxFontLoc(); ++ fontLoc->locType = gfxFontLocResident; ++ fontLoc->fontType = fontType1; ++ fontLoc->path = name->copy(); ++ return fontLoc; ++ } + -+// This function extracts three pieces of information: -+// 1. the "expected" font type, i.e., the font type implied by -+// Font.Subtype, DescendantFont.Subtype, and -+// FontDescriptor.FontFile3.Subtype -+// 2. the embedded font object ID -+// 3. the actual font type - determined by examining the embedded font -+// if there is one, otherwise equal to the expected font type -+// If the expected and actual font types don't match, a warning -+// message is printed. The expected font type is not used for -+// anything else. -+GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) { -+ GfxFontType t, expectedType; -+ FoFiIdentifierType fft; -+ Dict *fontDict2; -+ Object subtype, fontDesc, obj1, obj2, obj3, obj4; -+ GBool isType0, err; ++ //----- PS resident Base-14 font ++ if (ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) { ++ fontLoc = new GfxFontLoc(); ++ fontLoc->locType = gfxFontLocResident; ++ fontLoc->fontType = fontType1; ++ fontLoc->path = new GString(((Gfx8BitFont *)this)->base14->base14Name); ++ return fontLoc; ++ } + -+ t = fontUnknownType; -+ embID->num = embID->gen = -1; -+ err = gFalse; ++ //----- external font file (fontFile, fontDir) ++ if ((path = globalParams->findFontFile(name))) { ++ if ((fontLoc = getExternalFont(path, isCIDFont()))) { ++ return fontLoc; ++ } ++ } + -+ fontDict->lookup("Subtype", &subtype); -+ expectedType = fontUnknownType; -+ isType0 = gFalse; -+ if (subtype.isName("Type1") || subtype.isName("MMType1")) { -+ expectedType = fontType1; -+ } else if (subtype.isName("Type1C")) { -+ expectedType = fontType1C; -+ } else if (subtype.isName("Type3")) { -+ expectedType = fontType3; -+ } else if (subtype.isName("TrueType")) { -+ expectedType = fontTrueType; -+ } else if (subtype.isName("Type0")) { -+ isType0 = gTrue; -+ } else { -+ error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'", -+ subtype.isName() ? subtype.getName() : "???"); ++ //----- external font file for Base-14 font ++ if (!ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) { ++ base14Name = new GString(((Gfx8BitFont *)this)->base14->base14Name); ++ if ((path = globalParams->findFontFile(base14Name))) { ++ if ((fontLoc = getExternalFont(path, gFalse))) { ++ delete base14Name; ++ return fontLoc; ++ } ++ } ++ delete base14Name; + } -+ subtype.free(); + -+ fontDict2 = fontDict; -+ if (fontDict->lookup("DescendantFonts", &obj1)->isArray()) { -+ if (obj1.arrayGetLength() == 0) { -+ error(errSyntaxWarning, -1, "Empty DescendantFonts array in font"); -+ obj2.initNull(); -+ } else if (obj1.arrayGet(0, &obj2)->isDict()) { -+ if (!isType0) { -+ error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array"); ++ //----- system font ++ if ((path = globalParams->findSystemFontFile(name, &sysFontType, ++ &fontNum))) { ++ if (isCIDFont()) { ++ if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) { ++ fontLoc = new GfxFontLoc(); ++ fontLoc->locType = gfxFontLocExternal; ++ fontLoc->fontType = fontCIDType2; ++ fontLoc->path = path; ++ fontLoc->fontNum = fontNum; ++ return fontLoc; + } -+ fontDict2 = obj2.getDict(); -+ fontDict2->lookup("Subtype", &subtype); -+ if (subtype.isName("CIDFontType0")) { -+ if (isType0) { -+ expectedType = fontCIDType0; -+ } -+ } else if (subtype.isName("CIDFontType2")) { -+ if (isType0) { -+ expectedType = fontCIDType2; -+ } ++ } else { ++ if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) { ++ fontLoc = new GfxFontLoc(); ++ fontLoc->locType = gfxFontLocExternal; ++ fontLoc->fontType = fontTrueType; ++ fontLoc->path = path; ++ return fontLoc; ++ } else if (sysFontType == sysFontPFA || sysFontType == sysFontPFB) { ++ fontLoc = new GfxFontLoc(); ++ fontLoc->locType = gfxFontLocExternal; ++ fontLoc->fontType = fontType1; ++ fontLoc->path = path; ++ fontLoc->fontNum = fontNum; ++ return fontLoc; + } -+ subtype.free(); + } -+ } else { -+ obj2.initNull(); ++ delete path; + } + -+ if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) { -+ if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) { -+ *embID = obj3.getRef(); -+ if (expectedType != fontType1) { -+ err = gTrue; ++ if (!isCIDFont()) { ++ ++ //----- 8-bit PS resident font ++ if (ps) { ++ if ((path = globalParams->getPSResidentFont(name))) { ++ fontLoc = new GfxFontLoc(); ++ fontLoc->locType = gfxFontLocResident; ++ fontLoc->fontType = fontType1; ++ fontLoc->path = path; ++ return fontLoc; + } + } -+ obj3.free(); -+ if (embID->num == -1 && -+ fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) { -+ *embID = obj3.getRef(); -+ if (isType0) { -+ expectedType = fontCIDType2; -+ } else if (expectedType != fontTrueType) { -+ err = gTrue; -+ } ++ ++ //----- 8-bit font substitution ++ if (flags & fontFixedWidth) { ++ substIdx = 0; ++ } else if (flags & fontSerif) { ++ substIdx = 8; ++ } else { ++ substIdx = 4; + } -+ obj3.free(); -+ if (embID->num == -1 && -+ fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) { -+ *embID = obj3.getRef(); -+ if (obj3.fetch(xref, &obj4)->isStream()) { -+ obj4.streamGetDict()->lookup("Subtype", &subtype); -+ if (subtype.isName("Type1")) { -+ if (expectedType != fontType1) { -+ err = gTrue; -+ expectedType = isType0 ? fontCIDType0 : fontType1; -+ } -+ } else if (subtype.isName("Type1C")) { -+ if (expectedType == fontType1) { -+ expectedType = fontType1C; -+ } else if (expectedType != fontType1C) { -+ err = gTrue; -+ expectedType = isType0 ? fontCIDType0C : fontType1C; -+ } -+ } else if (subtype.isName("TrueType")) { -+ if (expectedType != fontTrueType) { -+ err = gTrue; -+ expectedType = isType0 ? fontCIDType2 : fontTrueType; -+ } -+ } else if (subtype.isName("CIDFontType0C")) { -+ if (expectedType == fontCIDType0) { -+ expectedType = fontCIDType0C; -+ } else { -+ err = gTrue; -+ expectedType = isType0 ? fontCIDType0C : fontType1C; -+ } -+ } else if (subtype.isName("OpenType")) { -+ if (expectedType == fontTrueType) { -+ expectedType = fontTrueTypeOT; -+ } else if (expectedType == fontType1) { -+ expectedType = fontType1COT; -+ } else if (expectedType == fontCIDType0) { -+ expectedType = fontCIDType0COT; -+ } else if (expectedType == fontCIDType2) { -+ expectedType = fontCIDType2OT; -+ } else { -+ err = gTrue; -+ } -+ } else { -+ error(errSyntaxError, -1, "Unknown font type '{0:s}'", -+ subtype.isName() ? subtype.getName() : "???"); ++ if (isBold()) { ++ substIdx += 2; ++ } ++ if (isItalic()) { ++ substIdx += 1; ++ } ++ substName = new GString(base14SubstFonts[substIdx]); ++ if (ps) { ++ error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'", ++ base14SubstFonts[substIdx], name); ++ fontLoc = new GfxFontLoc(); ++ fontLoc->locType = gfxFontLocResident; ++ fontLoc->fontType = fontType1; ++ fontLoc->path = substName; ++ fontLoc->substIdx = substIdx; ++ return fontLoc; ++ } else { ++ path = globalParams->findFontFile(substName); ++ delete substName; ++ if (path) { ++ if ((fontLoc = getExternalFont(path, gFalse))) { ++ error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'", ++ base14SubstFonts[substIdx], name); ++ fontLoc->substIdx = substIdx; ++ return fontLoc; + } -+ subtype.free(); + } -+ obj4.free(); + } -+ obj3.free(); -+ } -+ fontDesc.free(); + -+ t = fontUnknownType; -+ if (embID->num >= 0) { -+ obj3.initRef(embID->num, embID->gen); -+ obj3.fetch(xref, &obj4); -+ if (obj4.isStream()) { -+ obj4.streamReset(); -+ fft = FoFiIdentifier::identifyStream(&readFromStream, obj4.getStream()); -+ obj4.streamClose(); -+ switch (fft) { -+ case fofiIdType1PFA: -+ case fofiIdType1PFB: -+ t = fontType1; -+ break; -+ case fofiIdCFF8Bit: -+ t = isType0 ? fontCIDType0C : fontType1C; -+ break; -+ case fofiIdCFFCID: -+ t = fontCIDType0C; -+ break; -+ case fofiIdTrueType: -+ case fofiIdTrueTypeCollection: -+ t = isType0 ? fontCIDType2 : fontTrueType; -+ break; -+ case fofiIdOpenTypeCFF8Bit: -+ t = isType0 ? fontCIDType0COT : fontType1COT; -+ break; -+ case fofiIdOpenTypeCFFCID: -+ t = fontCIDType0COT; -+ break; -+ default: -+ error(errSyntaxError, -1, "Embedded font file may be invalid"); -+ break; -+ } -+ } -+ obj4.free(); -+ obj3.free(); ++ // failed to find a substitute font ++ return NULL; + } + -+ if (t == fontUnknownType) { -+ t = expectedType; - } -+ -+ if (t != expectedType) { -+ err = gTrue; ++ //----- 16-bit PS resident font ++ if (ps && ((psFont16 = globalParams->getPSResidentFont16( ++ name, ++ ((GfxCIDFont *)this)->getWMode())))) { ++ fontLoc = new GfxFontLoc(); ++ fontLoc->locType = gfxFontLocResident; ++ fontLoc->fontType = fontCIDType0; // this is not used ++ fontLoc->path = psFont16->psFontName->copy(); ++ fontLoc->encoding = psFont16->encoding->copy(); ++ fontLoc->wMode = psFont16->wMode; ++ return fontLoc; + } -+ -+ if (err) { -+ error(errSyntaxWarning, -1, -+ "Mismatch between font type and embedded font file"); ++ if (ps && ((psFont16 = globalParams->getPSResidentFontCC( ++ ((GfxCIDFont *)this)->getCollection(), ++ ((GfxCIDFont *)this)->getWMode())))) { ++ error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'", ++ psFont16->psFontName, name); ++ fontLoc = new GfxFontLoc(); ++ fontLoc->locType = gfxFontLocResident; ++ fontLoc->fontType = fontCIDType0; // this is not used ++ fontLoc->path = psFont16->psFontName->copy(); ++ fontLoc->encoding = psFont16->encoding->copy(); ++ fontLoc->wMode = psFont16->wMode; ++ return fontLoc; + } + -+ obj2.free(); -+ obj1.free(); ++ //----- CID font substitution ++ if ((path = globalParams->findCCFontFile( ++ ((GfxCIDFont *)this)->getCollection()))) { ++ if ((fontLoc = getExternalFont(path, gTrue))) { ++ error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'", ++ fontLoc->path, name); ++ return fontLoc; + } + } + -+ return t; ++ // failed to find a substitute font ++ return NULL; } - void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { -@@ -170,8 +417,6 @@ - // assume Times-Roman by default (for substitution purposes) - flags = fontSerif; +-char *GfxFont::readExtFontFile(int *len) { +- FILE *f; +- char *buf; ++GfxFontLoc *GfxFont::locateBase14Font(GString *base14Name) { ++ GString *path; -- embFontID.num = -1; -- embFontID.gen = -1; - missingWidth = 0; +- if (!(f = fopen(extFontFile->getCString(), "rb"))) { +- error(-1, "External font file '%s' vanished", extFontFile->getCString()); ++ path = globalParams->findFontFile(base14Name); ++ if (!path) { + return NULL; + } +- fseek(f, 0, SEEK_END); +- *len = (int)ftell(f); +- fseek(f, 0, SEEK_SET); +- buf = (char *)gmalloc(*len); +- if ((int)fread(buf, 1, *len, f) != *len) { +- error(-1, "Error reading external font file '%s'", +- extFontFile->getCString()); ++ return getExternalFont(path, gFalse); ++} ++ ++GfxFontLoc *GfxFont::getExternalFont(GString *path, GBool cid) { ++ FoFiIdentifierType fft; ++ GfxFontType fontType; ++ GfxFontLoc *fontLoc; ++ ++ fft = FoFiIdentifier::identifyFile(path->getCString()); ++ switch (fft) { ++ case fofiIdType1PFA: ++ case fofiIdType1PFB: ++ fontType = fontType1; ++ break; ++ case fofiIdCFF8Bit: ++ fontType = fontType1C; ++ break; ++ case fofiIdCFFCID: ++ fontType = fontCIDType0C; ++ break; ++ case fofiIdTrueType: ++ case fofiIdTrueTypeCollection: ++ fontType = cid ? fontCIDType2 : fontTrueType; ++ break; ++ case fofiIdOpenTypeCFF8Bit: ++ fontType = fontType1COT; ++ break; ++ case fofiIdOpenTypeCFFCID: ++ fontType = fontCIDType0COT; ++ break; ++ case fofiIdUnknown: ++ case fofiIdError: ++ default: ++ fontType = fontUnknownType; ++ break; ++ } ++ if (fontType == fontUnknownType || ++ (cid ? (fontType < fontCIDType0) ++ : (fontType >= fontCIDType0))) { ++ delete path; ++ return NULL; + } +- fclose(f); +- return buf; ++ fontLoc = new GfxFontLoc(); ++ fontLoc->locType = gfxFontLocExternal; ++ fontLoc->fontType = fontType; ++ fontLoc->path = path; ++ return fontLoc; + } - if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) { -@@ -189,75 +434,6 @@ + char *GfxFont::readEmbFontFile(XRef *xref, int *len) { +@@ -386,6 +810,10 @@ + str->reset(); + while ((c = str->getChar()) != EOF) { + if (i == size) { ++ if (size > INT_MAX - 4096) { ++ error(errSyntaxError, -1, "Embedded font file is too large"); ++ break; ++ } + size += 4096; + buf = (char *)grealloc(buf, size); } - obj2.free(); +@@ -405,8 +833,8 @@ + //------------------------------------------------------------------------ -- // look for embedded font file -- if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) { -- embFontID = obj2.getRef(); -- if (type != fontType1) { -- error(-1, "Mismatch between font type and embedded font file"); -- type = fontType1; -- } -- } -- obj2.free(); -- if (embFontID.num == -1 && -- obj1.dictLookupNF("FontFile2", &obj2)->isRef()) { -- embFontID = obj2.getRef(); -- if (type != fontTrueType && type != fontCIDType2) { -- error(-1, "Mismatch between font type and embedded font file"); -- type = type == fontCIDType0 ? fontCIDType2 : fontTrueType; -- } -- } -- obj2.free(); -- if (embFontID.num == -1 && -- obj1.dictLookupNF("FontFile3", &obj2)->isRef()) { -- if (obj2.fetch(xref, &obj3)->isStream()) { -- obj3.streamGetDict()->lookup("Subtype", &obj4); -- if (obj4.isName("Type1")) { -- embFontID = obj2.getRef(); -- if (type != fontType1) { -- error(-1, "Mismatch between font type and embedded font file"); -- type = fontType1; -- } -- } else if (obj4.isName("Type1C")) { -- embFontID = obj2.getRef(); -- if (type != fontType1 && type != fontType1C) { -- error(-1, "Mismatch between font type and embedded font file"); -- } -- type = fontType1C; -- } else if (obj4.isName("TrueType")) { -- embFontID = obj2.getRef(); -- if (type != fontTrueType) { -- error(-1, "Mismatch between font type and embedded font file"); -- type = fontTrueType; -- } -- } else if (obj4.isName("CIDFontType0C")) { -- embFontID = obj2.getRef(); -- if (type != fontCIDType0) { -- error(-1, "Mismatch between font type and embedded font file"); -- } -- type = fontCIDType0C; -- } else if (obj4.isName("OpenType")) { -- embFontID = obj2.getRef(); -- if (type == fontTrueType) { -- type = fontTrueTypeOT; -- } else if (type == fontType1) { -- type = fontType1COT; -- } else if (type == fontCIDType0) { -- type = fontCIDType0COT; -- } else if (type == fontCIDType2) { -- type = fontCIDType2OT; -- } else { -- error(-1, "Mismatch between font type and embedded font file"); -- } -- } else { -- error(-1, "Unknown embedded font type '%s'", -- obj4.isName() ? obj4.getName() : "???"); -- } -- obj4.free(); -- } -- obj3.free(); -- } -- obj2.free(); + Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, +- GfxFontType typeA, Dict *fontDict): +- GfxFont(tagA, idA, nameA) ++ GfxFontType typeA, Ref embFontIDA, Dict *fontDict): ++ GfxFont(tagA, idA, nameA, typeA, embFontIDA) + { + GString *name2; + BuiltinFont *builtinFont; +@@ -428,11 +856,11 @@ + Object obj1, obj2, obj3; + int n, i, a, b, m; + +- type = typeA; + ctu = NULL; + + // do font name substitution for various aliases of the Base 14 font + // names + base14 = NULL; + if (name) { + name2 = name->copy(); + i = 0; +@@ -499,9 +927,6 @@ + fontBBox[3] = 0.001 * builtinFont->bbox[3]; + } + +- // look for an external font file +- findExtFontFile(); - - // look for MissingWidth - obj1.dictLookup("MissingWidth", &obj2); - if (obj2.isNum()) { -@@ -269,8 +445,13 @@ - obj1.dictLookup("Ascent", &obj2); - if (obj2.isNum()) { - t = 0.001 * obj2.getNum(); -- // some broken font descriptors set ascent and descent to 0 -- if (t != 0) { -+ // some broken font descriptors specify a negative ascent -+ if (t < 0) { -+ t = -t; -+ } -+ // some broken font descriptors set ascent and descent to 0; -+ // others set it to ridiculous values (e.g., 32768) -+ if (t != 0 && t < 3) { - ascent = t; + // get font matrix + fontMat[0] = fontMat[3] = 1; + fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0; +@@ -581,54 +1007,45 @@ + baseEnc = winAnsiEncoding; + } + +- // check embedded or external font file for base encoding ++ // check embedded font file for base encoding + // (only for Type 1 fonts - trying to get an encoding out of a + // TrueType font is a losing proposition) + ffT1 = NULL; + ffT1C = NULL; + buf = NULL; +- if (type == fontType1 && (extFontFile || embFontID.num >= 0)) { +- if (extFontFile) { +- ffT1 = FoFiType1::load(extFontFile->getCString()); +- } else { +- buf = readEmbFontFile(xref, &len); +- ffT1 = FoFiType1::make(buf, len); +- } +- if (ffT1) { +- if (ffT1->getName()) { +- if (embFontName) { +- delete embFontName; ++ if (type == fontType1 && embFontID.num >= 0) { ++ if ((buf = readEmbFontFile(xref, &len))) { ++ if ((ffT1 = FoFiType1::make(buf, len))) { ++ if (ffT1->getName()) { ++ if (embFontName) { ++ delete embFontName; ++ } ++ embFontName = new GString(ffT1->getName()); ++ } ++ if (!baseEnc) { ++ baseEnc = (const char **)ffT1->getEncoding(); ++ baseEncFromFontFile = gTrue; + } +- embFontName = new GString(ffT1->getName()); +- } +- if (!baseEnc) { +- baseEnc = (const char **)ffT1->getEncoding(); +- baseEncFromFontFile = gTrue; } ++ gfree(buf); } -@@ -278,14 +459,14 @@ - obj1.dictLookup("Descent", &obj2); - if (obj2.isNum()) { - t = 0.001 * obj2.getNum(); -+ // some broken font descriptors specify a positive descent -+ if (t > 0) { -+ t = -t; -+ } - // some broken font descriptors set ascent and descent to 0 -- if (t != 0) { -+ if (t != 0 && t > -3) { - descent = t; - } -- // some broken font descriptors specify a positive descent -- if (descent > 0) { -- descent = -descent; +- } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) { +- if (extFontFile) { +- ffT1C = FoFiType1C::load(extFontFile->getCString()); +- } else { +- buf = readEmbFontFile(xref, &len); +- ffT1C = FoFiType1C::make(buf, len); +- } +- if (ffT1C) { +- if (ffT1C->getName()) { +- if (embFontName) { +- delete embFontName; ++ } else if (type == fontType1C && embFontID.num >= 0) { ++ if ((buf = readEmbFontFile(xref, &len))) { ++ if ((ffT1C = FoFiType1C::make(buf, len))) { ++ if (ffT1C->getName()) { ++ if (embFontName) { ++ delete embFontName; ++ } ++ embFontName = new GString(ffT1C->getName()); ++ } ++ if (!baseEnc) { ++ baseEnc = (const char **)ffT1C->getEncoding(); ++ baseEncFromFontFile = gTrue; + } +- embFontName = new GString(ffT1C->getName()); - } +- if (!baseEnc) { +- baseEnc = (const char **)ffT1C->getEncoding(); +- baseEncFromFontFile = gTrue; + } ++ gfree(buf); } - obj2.free(); + } +- if (buf) { +- gfree(buf); +- } -@@ -330,37 +511,280 @@ - return ctu; - } + // get default base encoding + if (!baseEnc) { +@@ -644,7 +1061,7 @@ --void GfxFont::findExtFontFile() { -- static char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL }; -- static char *ttExts[] = { ".ttf", NULL }; -+GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) { -+ GfxFontLoc *fontLoc; -+ SysFontType sysFontType; -+ GString *path, *base14Name, *substName; -+ PSFontParam16 *psFont16; -+ Object refObj, embFontObj; -+ int substIdx, fontNum; -+ GBool embed; + // copy the base encoding + for (i = 0; i < 256; ++i) { +- enc[i] = baseEnc[i]; ++ enc[i] = (char *)baseEnc[i]; + if ((encFree[i] = baseEncFromFontFile) && enc[i]) { + enc[i] = copyString(baseEnc[i]); + } +@@ -654,11 +1071,10 @@ + // T1C->T1 conversion (since the 'seac' operator depends on having + // the accents in the encoding), so we fill in any gaps from + // StandardEncoding +- if (type == fontType1C && (extFontFile || embFontID.num >= 0) && +- baseEncFromFontFile) { ++ if (type == fontType1C && embFontID.num >= 0 && baseEncFromFontFile) { + for (i = 0; i < 256; ++i) { + if (!enc[i] && standardEncoding[i]) { + enc[i] = (char *)standardEncoding[i]; + encFree[i] = gFalse; + } + } +@@ -734,14 +1151,21 @@ + } -- if (name) { -- if (type == fontType1) { -- extFontFile = globalParams->findFontFile(name, type1Exts); -- } else if (type == fontTrueType) { -- extFontFile = globalParams->findFontFile(name, ttExts); -+ if (type == fontType3) { -+ return NULL; -+ } -+ -+ //----- embedded font -+ if (embFontID.num >= 0) { -+ embed = gTrue; -+ refObj.initRef(embFontID.num, embFontID.gen); -+ refObj.fetch(xref, &embFontObj); -+ if (!embFontObj.isStream()) { -+ error(errSyntaxError, -1, "Embedded font object is wrong type"); -+ embed = gFalse; -+ } -+ embFontObj.free(); -+ refObj.free(); -+ if (embed) { -+ if (ps) { -+ switch (type) { -+ case fontType1: -+ case fontType1C: -+ case fontType1COT: -+ embed = globalParams->getPSEmbedType1(); -+ break; -+ case fontTrueType: -+ case fontTrueTypeOT: -+ embed = globalParams->getPSEmbedTrueType(); -+ break; -+ case fontCIDType0C: -+ case fontCIDType0COT: -+ embed = globalParams->getPSEmbedCIDPostScript(); -+ break; -+ case fontCIDType2: -+ case fontCIDType2OT: -+ embed = globalParams->getPSEmbedCIDTrueType(); -+ break; -+ default: -+ break; -+ } -+ } -+ if (embed) { -+ fontLoc = new GfxFontLoc(); -+ fontLoc->locType = gfxFontLocEmbedded; -+ fontLoc->fontType = type; -+ fontLoc->embFontID = embFontID; -+ return fontLoc; -+ } -+ } -+ } -+ -+ //----- PS passthrough -+ if (ps && !isCIDFont() && globalParams->getPSFontPassthrough()) { -+ fontLoc = new GfxFontLoc(); -+ fontLoc->locType = gfxFontLocResident; -+ fontLoc->fontType = fontType1; -+ fontLoc->path = name->copy(); -+ return fontLoc; -+ } -+ -+ //----- PS resident Base-14 font -+ if (ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) { -+ fontLoc = new GfxFontLoc(); -+ fontLoc->locType = gfxFontLocResident; -+ fontLoc->fontType = fontType1; -+ fontLoc->path = new GString(((Gfx8BitFont *)this)->base14->base14Name); -+ return fontLoc; -+ } + // pass 2: try to fill in the missing chars, looking for names of +- // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B' +- // are any letters, 'xx' is two hex digits, and 'nn' is 2-4 +- // decimal digits ++ // any of the following forms: ++ // - 'xx' ++ // - 'Axx' ++ // - 'nn' ++ // - 'Ann' ++ // - 'ABnn' ++ // - 'unixxxx' (possibly followed by garbage - some Arabic files ++ // use 'uni0628.medi', etc.) ++ // where 'A' and 'B' are any letters, 'xx' is two hex digits, 'xxxx' ++ // is four hex digits, and 'nn' is 2-4 decimal digits + if (missing && globalParams->getMapNumericCharNames()) { + for (code = 0; code < 256; ++code) { + if ((charName = enc[code]) && !toUnicode[code] && + strcmp(charName, ".notdef")) { + n = strlen(charName); + code2 = -1; + if (hex && n == 3 && isalpha(charName[0]) && + isxdigit(charName[1]) && isxdigit(charName[2])) { +@@ -758,8 +1182,13 @@ + } else if (n >= 4 && n <= 6 && + isdigit(charName[2]) && isdigit(charName[3])) { + code2 = atoi(charName+2); ++ } else if (n >= 7 && charName[0] == 'u' && charName[1] == 'n' && ++ charName[2] == 'i' && ++ isxdigit(charName[3]) && isxdigit(charName[4]) && ++ isxdigit(charName[5]) && isxdigit(charName[6])) { ++ sscanf(charName + 3, "%x", &code2); + } +- if (code2 >= 0 && code2 <= 0xff) { ++ if (code2 >= 0 && code2 <= 0xffff) { + toUnicode[code] = (Unicode)code2; + } + } +@@ -835,7 +1264,7 @@ + obj1.arrayGet(code - firstChar, &obj2); + if (obj2.isNum()) { + widths[code] = obj2.getNum() * mul; +- if (widths[code] != widths[firstChar]) { ++ if (fabs(widths[code] - widths[firstChar]) > 0.00001) { + flags &= ~fontFixedWidth; + } + } +@@ -945,9 +1374,10 @@ + // TrueType font has a Macintosh Roman cmap, use it, and + // reverse map the char names through MacRomanEncoding to + // get char codes. +- // 1b. If the TrueType font has a Microsoft Unicode cmap or a +- // non-Microsoft Unicode cmap, use it, and use the Unicode +- // indexes, not the char codes. ++ // 1b. If the PDF font is not symbolic or the PDF font is not ++ // embedded, and the TrueType font has a Microsoft Unicode ++ // cmap or a non-Microsoft Unicode cmap, use it, and use the ++ // Unicode indexes, not the char codes. + // 1c. If the PDF font is symbolic and the TrueType font has a + // Microsoft Symbol cmap, use it, and use char codes + // directly (possibly with an offset of 0xf000). +@@ -983,7 +1413,8 @@ + if (usesMacRomanEnc && macRomanCmap >= 0) { + cmap = macRomanCmap; + useMacRoman = gTrue; +- } else if (unicodeCmap >= 0) { ++ } else if ((!(flags & fontSymbolic) || embFontID.num < 0) && ++ unicodeCmap >= 0) { + cmap = unicodeCmap; + useUnicode = gTrue; + } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) { +@@ -1010,6 +1441,8 @@ + if ((code = globalParams->getMacRomanCharCode(charName))) { + map[i] = ff->mapCodeToGID(cmap, code); + } ++ } else { ++ map[i] = -1; + } + } + +@@ -1020,6 +1453,8 @@ + (u = globalParams->mapNameToUnicode(charName))) || + (n = ctu->mapToUnicode((CharCode)i, &u, 1))) { + map[i] = ff->mapCodeToGID(cmap, u); ++ } else { ++ map[i] = -1; + } + } + +@@ -1035,8 +1470,8 @@ + + // try the TrueType 'post' table to handle any unmapped characters + for (i = 0; i < 256; ++i) { +- if (!map[i] && (charName = enc[i])) { ++ if (map[i] <= 0 && (charName = enc[i])) { + map[i] = ff->mapNameToGID(charName); + } + } + +@@ -1077,12 +1530,11 @@ + GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, +- Dict *fontDict): +- GfxFont(tagA, idA, nameA) ++ GfxFontType typeA, Ref embFontIDA, Dict *fontDict): ++ GfxFont(tagA, idA, nameA, typeA, embFontIDA) + { + Dict *desFontDict; +- GString *collection, *cMapName; + Object desFontDictObj; + Object obj1, obj2, obj3, obj4, obj5, obj6; + CharCodeToUnicode *utu; +@@ -1091,8 +1545,10 @@ + ascent = 0.95; + descent = -0.35; + fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; ++ collection = NULL; + cMap = NULL; + ctu = NULL; ++ ctuUsesCharCode = gTrue; + widths.defWidth = 1.0; + widths.defHeight = -1.0; + widths.defVY = 0.880; +@@ -1104,52 +1560,38 @@ + cidToGIDLen = 0; + + // get the descendant font +- if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) { +- error(-1, "Missing DescendantFonts entry in Type 0 font"); ++ if (!fontDict->lookup("DescendantFonts", &obj1)->isArray() || ++ obj1.arrayGetLength() == 0) { ++ error(errSyntaxError, -1, ++ "Missing or empty DescendantFonts entry in Type 0 font"); + obj1.free(); + -+ //----- external font file (fontFile, fontDir) -+ if ((path = globalParams->findFontFile(name))) { -+ if ((fontLoc = getExternalFont(path, isCIDFont()))) { -+ return fontLoc; -+ } -+ } + goto err1; + } + if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) { +- error(-1, "Bad descendant font in Type 0 font"); +- goto err3; ++ error(errSyntaxError, -1, "Bad descendant font in Type 0 font"); ++ goto err2; + } + obj1.free(); + desFontDict = desFontDictObj.getDict(); + +- // font type +- if (!desFontDict->lookup("Subtype", &obj1)) { +- error(-1, "Missing Subtype entry in Type 0 descendant font"); +- goto err3; +- } +- if (obj1.isName("CIDFontType0")) { +- type = fontCIDType0; +- } else if (obj1.isName("CIDFontType2")) { +- type = fontCIDType2; +- } else { +- error(-1, "Unknown Type 0 descendant font type '%s'", +- obj1.isName() ? obj1.getName() : "???"); +- goto err3; +- } +- obj1.free(); +- + // get info from font descriptor + readFontDescriptor(xref, desFontDict); + +- // look for an external font file +- findExtFontFile(); +- + //----- encoding info ----- + + // char collection + if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) { +- error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font"); +- goto err3; ++ error(errSyntaxError, -1, ++ "Missing CIDSystemInfo dictionary in Type 0 descendant font"); ++ goto err2; + } + obj1.dictLookup("Registry", &obj2); + obj1.dictLookup("Ordering", &obj3); + if (!obj2.isString() || !obj3.isString()) { +- error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font"); +- goto err4; ++ error(errSyntaxError, -1, ++ "Invalid CIDSystemInfo dictionary in Type 0 descendant font"); ++ goto err3; + } + collection = obj2.getString()->copy()->append('-')->append(obj3.getString()); + obj3.free(); +@@ -1158,19 +1600,18 @@ + + // look for a ToUnicode CMap + if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) { ++ ctuUsesCharCode = gFalse; + +- // the "Adobe-Identity" and "Adobe-UCS" collections don't have +- // cidToUnicode files +- if (collection->cmp("Adobe-Identity") && +- collection->cmp("Adobe-UCS")) { +- +- // look for a user-supplied .cidToUnicode file +- if (!(ctu = globalParams->getCIDToUnicode(collection))) { +- error(-1, "Unknown character collection '%s'", +- collection->getCString()); +- // fall-through, assuming the Identity mapping -- this appears +- // to match Adobe's behavior +- } ++ // use an identity mapping for the "Adobe-Identity" and ++ // "Adobe-UCS" collections ++ if (!collection->cmp("Adobe-Identity") || ++ !collection->cmp("Adobe-UCS")) { ++ ctu = CharCodeToUnicode::makeIdentityMapping(); + -+ //----- external font file for Base-14 font -+ if (!ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) { -+ base14Name = new GString(((Gfx8BitFont *)this)->base14->base14Name); -+ if ((path = globalParams->findFontFile(base14Name))) { -+ if ((fontLoc = getExternalFont(path, gFalse))) { -+ delete base14Name; -+ return fontLoc; -+ } -+ } -+ delete base14Name; -+ } -+ -+ //----- system font -+ if ((path = globalParams->findSystemFontFile(name, &sysFontType, -+ &fontNum))) { -+ if (isCIDFont()) { -+ if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) { -+ fontLoc = new GfxFontLoc(); -+ fontLoc->locType = gfxFontLocExternal; -+ fontLoc->fontType = fontCIDType2; -+ fontLoc->path = path; -+ fontLoc->fontNum = fontNum; -+ return fontLoc; -+ } -+ } else { -+ if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) { -+ fontLoc = new GfxFontLoc(); -+ fontLoc->locType = gfxFontLocExternal; -+ fontLoc->fontType = fontTrueType; -+ fontLoc->path = path; -+ return fontLoc; -+ } else if (sysFontType == sysFontPFA || sysFontType == sysFontPFB) { -+ fontLoc = new GfxFontLoc(); -+ fontLoc->locType = gfxFontLocExternal; -+ fontLoc->fontType = fontType1; -+ fontLoc->path = path; -+ fontLoc->fontNum = fontNum; -+ return fontLoc; -+ } -+ } -+ delete path; -+ } -+ -+ if (!isCIDFont()) { -+ -+ //----- 8-bit PS resident font -+ if (ps) { -+ if ((path = globalParams->getPSResidentFont(name))) { -+ fontLoc = new GfxFontLoc(); -+ fontLoc->locType = gfxFontLocResident; -+ fontLoc->fontType = fontType1; -+ fontLoc->path = path; -+ return fontLoc; -+ } -+ } -+ -+ //----- 8-bit font substitution -+ if (flags & fontFixedWidth) { -+ substIdx = 0; -+ } else if (flags & fontSerif) { -+ substIdx = 8; -+ } else { -+ substIdx = 4; -+ } -+ if (isBold()) { -+ substIdx += 2; -+ } -+ if (isItalic()) { -+ substIdx += 1; -+ } -+ substName = new GString(base14SubstFonts[substIdx]); -+ if (ps) { -+ error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'", -+ base14SubstFonts[substIdx], name); -+ fontLoc = new GfxFontLoc(); -+ fontLoc->locType = gfxFontLocResident; -+ fontLoc->fontType = fontType1; -+ fontLoc->path = substName; -+ fontLoc->substIdx = substIdx; -+ return fontLoc; -+ } else { -+ path = globalParams->findFontFile(substName); -+ delete substName; -+ if (path) { -+ if ((fontLoc = getExternalFont(path, gFalse))) { -+ error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'", -+ base14SubstFonts[substIdx], name); -+ fontLoc->substIdx = substIdx; -+ return fontLoc; -+ } -+ } -+ } -+ -+ // failed to find a substitute font -+ return NULL; -+ } -+ -+ //----- 16-bit PS resident font -+ if (ps && ((psFont16 = globalParams->getPSResidentFont16( -+ name, -+ ((GfxCIDFont *)this)->getWMode())))) { -+ fontLoc = new GfxFontLoc(); -+ fontLoc->locType = gfxFontLocResident; -+ fontLoc->fontType = fontCIDType0; // this is not used -+ fontLoc->path = psFont16->psFontName->copy(); -+ fontLoc->encoding = psFont16->encoding->copy(); -+ fontLoc->wMode = psFont16->wMode; -+ return fontLoc; -+ } -+ if (ps && ((psFont16 = globalParams->getPSResidentFontCC( -+ ((GfxCIDFont *)this)->getCollection(), -+ ((GfxCIDFont *)this)->getWMode())))) { -+ error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'", -+ psFont16->psFontName, name); -+ fontLoc = new GfxFontLoc(); -+ fontLoc->locType = gfxFontLocResident; -+ fontLoc->fontType = fontCIDType0; // this is not used -+ fontLoc->path = psFont16->psFontName->copy(); -+ fontLoc->encoding = psFont16->encoding->copy(); -+ fontLoc->wMode = psFont16->wMode; -+ return fontLoc; -+ } -+ -+ //----- CID font substitution -+ if ((path = globalParams->findCCFontFile( -+ ((GfxCIDFont *)this)->getCollection()))) { -+ if ((fontLoc = getExternalFont(path, gTrue))) { -+ error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'", -+ fontLoc->path, name); -+ return fontLoc; ++ // look for a user-supplied .cidToUnicode file ++ } else if (!(ctu = globalParams->getCIDToUnicode(collection))) { ++ error(errSyntaxError, -1, ++ "Unknown character collection '{0:t}'", collection); } } -+ -+ // failed to find a substitute font -+ return NULL; - } --char *GfxFont::readExtFontFile(int *len) { -- FILE *f; -- char *buf; -+GfxFontLoc *GfxFont::locateBase14Font(GString *base14Name) { -+ GString *path; +@@ -1193,43 +1634,35 @@ + } -- if (!(f = fopen(extFontFile->getCString(), "rb"))) { -- error(-1, "External font file '%s' vanished", extFontFile->getCString()); -+ path = globalParams->findFontFile(base14Name); -+ if (!path) { - return NULL; + // encoding (i.e., CMap) +- //~ need to handle a CMap stream here +- //~ also need to deal with the UseCMap entry in the stream dict +- if (!fontDict->lookup("Encoding", &obj1)->isName()) { +- error(-1, "Missing or invalid Encoding entry in Type 0 font"); +- delete collection; +- goto err3; ++ if (fontDict->lookup("Encoding", &obj1)->isNull()) { ++ error(errSyntaxError, -1, "Missing Encoding entry in Type 0 font"); ++ goto err2; } -- fseek(f, 0, SEEK_END); -- *len = (int)ftell(f); -- fseek(f, 0, SEEK_SET); -- buf = (char *)gmalloc(*len); -- if ((int)fread(buf, 1, *len, f) != *len) { -- error(-1, "Error reading external font file '%s'", -- extFontFile->getCString()); -+ return getExternalFont(path, gFalse); -+} -+ -+GfxFontLoc *GfxFont::getExternalFont(GString *path, GBool cid) { -+ FoFiIdentifierType fft; -+ GfxFontType fontType; -+ GfxFontLoc *fontLoc; -+ -+ fft = FoFiIdentifier::identifyFile(path->getCString()); -+ switch (fft) { -+ case fofiIdType1PFA: -+ case fofiIdType1PFB: -+ fontType = fontType1; -+ break; -+ case fofiIdCFF8Bit: -+ fontType = fontType1C; -+ break; -+ case fofiIdCFFCID: -+ fontType = fontCIDType0C; -+ break; -+ case fofiIdTrueType: -+ case fofiIdTrueTypeCollection: -+ fontType = cid ? fontCIDType2 : fontTrueType; -+ break; -+ case fofiIdOpenTypeCFF8Bit: -+ fontType = fontType1COT; -+ break; -+ case fofiIdOpenTypeCFFCID: -+ fontType = fontCIDType0COT; -+ break; -+ case fofiIdUnknown: -+ case fofiIdError: -+ default: -+ fontType = fontUnknownType; -+ break; -+ } -+ if (fontType == fontUnknownType || -+ (cid ? (fontType < fontCIDType0) -+ : (fontType >= fontCIDType0))) { -+ delete path; -+ return NULL; +- cMapName = new GString(obj1.getName()); +- obj1.free(); +- if (!(cMap = globalParams->getCMap(collection, cMapName))) { +- error(-1, "Unknown CMap '%s' for character collection '%s'", +- cMapName->getCString(), collection->getCString()); +- delete collection; +- delete cMapName; ++ if (!(cMap = CMap::parse(NULL, collection, &obj1))) { + goto err2; } -- fclose(f); -- return buf; -+ fontLoc = new GfxFontLoc(); -+ fontLoc->locType = gfxFontLocExternal; -+ fontLoc->fontType = fontType; -+ fontLoc->path = path; -+ return fontLoc; - } +- delete collection; +- delete cMapName; ++ obj1.free(); - char *GfxFont::readEmbFontFile(XRef *xref, int *len) { -@@ -386,6 +810,10 @@ - str->reset(); - while ((c = str->getChar()) != EOF) { - if (i == size) { -+ if (size > INT_MAX - 4096) { -+ error(errSyntaxError, -1, "Embedded font file is too large"); -+ break; -+ } - size += 4096; - buf = (char *)grealloc(buf, size); - } -@@ -405,8 +833,8 @@ - //------------------------------------------------------------------------ +- // CIDToGIDMap (for embedded TrueType fonts) +- if (type == fontCIDType2) { ++ // CIDToGIDMap ++ // (the PDF spec only allows these for TrueType fonts, but Acrobat ++ // apparently also allows them for OpenType CFF fonts) ++ if (type == fontCIDType2 || type == fontCIDType0COT) { + desFontDict->lookup("CIDToGIDMap", &obj1); + if (obj1.isStream()) { + cidToGIDLen = 0; + i = 64; +@@ -1387,17 +1830,19 @@ + ok = gTrue; + return; - Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, -- GfxFontType typeA, Dict *fontDict): -- GfxFont(tagA, idA, nameA) -+ GfxFontType typeA, Ref embFontIDA, Dict *fontDict): -+ GfxFont(tagA, idA, nameA, typeA, embFontIDA) - { - GString *name2; - BuiltinFont *builtinFont; -@@ -428,11 +856,11 @@ - Object obj1, obj2, obj3; - int n, i, a, b, m; - -- type = typeA; - ctu = NULL; +- err4: ++ err3: + obj3.free(); + obj2.free(); +- err3: +- obj1.free(); + err2: ++ obj1.free(); + desFontDictObj.free(); + err1:; + } - // do font name substitution for various aliases of the Base 14 font - // names - base14 = NULL; - if (name) { - name2 = name->copy(); - i = 0; -@@ -499,9 +927,6 @@ - fontBBox[3] = 0.001 * builtinFont->bbox[3]; + GfxCIDFont::~GfxCIDFont() { ++ if (collection) { ++ delete collection; ++ } + if (cMap) { + cMap->decRefCnt(); } - -- // look for an external font file -- findExtFontFile(); -- - // get font matrix - fontMat[0] = fontMat[3] = 1; - fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0; -@@ -581,54 +1007,45 @@ - baseEnc = winAnsiEncoding; +@@ -1425,12 +1871,16 @@ + return 1; } -- // check embedded or external font file for base encoding -+ // check embedded font file for base encoding - // (only for Type 1 fonts - trying to get an encoding out of a - // TrueType font is a losing proposition) - ffT1 = NULL; - ffT1C = NULL; - buf = NULL; -- if (type == fontType1 && (extFontFile || embFontID.num >= 0)) { -- if (extFontFile) { -- ffT1 = FoFiType1::load(extFontFile->getCString()); -- } else { -- buf = readEmbFontFile(xref, &len); -- ffT1 = FoFiType1::make(buf, len); -- } -- if (ffT1) { -- if (ffT1->getName()) { -- if (embFontName) { -- delete embFontName; -+ if (type == fontType1 && embFontID.num >= 0) { -+ if ((buf = readEmbFontFile(xref, &len))) { -+ if ((ffT1 = FoFiType1::make(buf, len))) { -+ if (ffT1->getName()) { -+ if (embFontName) { -+ delete embFontName; -+ } -+ embFontName = new GString(ffT1->getName()); -+ } -+ if (!baseEnc) { -+ baseEnc = (const char **)ffT1->getEncoding(); -+ baseEncFromFontFile = gTrue; - } -- embFontName = new GString(ffT1->getName()); -- } -- if (!baseEnc) { -- baseEnc = (const char **)ffT1->getEncoding(); -- baseEncFromFontFile = gTrue; - } -+ gfree(buf); - } -- } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) { -- if (extFontFile) { -- ffT1C = FoFiType1C::load(extFontFile->getCString()); -- } else { -- buf = readEmbFontFile(xref, &len); -- ffT1C = FoFiType1C::make(buf, len); -- } -- if (ffT1C) { -- if (ffT1C->getName()) { -- if (embFontName) { -- delete embFontName; -+ } else if (type == fontType1C && embFontID.num >= 0) { -+ if ((buf = readEmbFontFile(xref, &len))) { -+ if ((ffT1C = FoFiType1C::make(buf, len))) { -+ if (ffT1C->getName()) { -+ if (embFontName) { -+ delete embFontName; -+ } -+ embFontName = new GString(ffT1C->getName()); -+ } -+ if (!baseEnc) { -+ baseEnc = (const char **)ffT1C->getEncoding(); -+ baseEncFromFontFile = gTrue; - } -- embFontName = new GString(ffT1C->getName()); -- } -- if (!baseEnc) { -- baseEnc = (const char **)ffT1C->getEncoding(); -- baseEncFromFontFile = gTrue; - } -+ gfree(buf); - } + *code = (CharCode)(cid = cMap->getCID(s, len, &c, &n)); + if (ctu) { +- *uLen = ctu->mapToUnicode(cid, u, uSize); ++ *uLen = ctu->mapToUnicode(ctuUsesCharCode ? c : cid, u, uSize); + } else { + *uLen = 0; } -- if (buf) { -- gfree(buf); -- } - - // get default base encoding - if (!baseEnc) { -@@ -644,7 +1061,7 @@ ++ if (!*uLen && uSize >= 1 && globalParams->getMapUnknownCharNames()) { ++ u[0] = *code; ++ *uLen = 1; ++ } - // copy the base encoding - for (i = 0; i < 256; ++i) { -- enc[i] = baseEnc[i]; -+ enc[i] = (char *)baseEnc[i]; - if ((encFree[i] = baseEncFromFontFile) && enc[i]) { - enc[i] = copyString(baseEnc[i]); - } -@@ -654,11 +1071,10 @@ - // T1C->T1 conversion (since the 'seac' operator depends on having - // the accents in the encoding), so we fill in any gaps from - // StandardEncoding -- if (type == fontType1C && (extFontFile || embFontID.num >= 0) && -- baseEncFromFontFile) { -+ if (type == fontType1C && embFontID.num >= 0 && baseEncFromFontFile) { - for (i = 0; i < 256; ++i) { - if (!enc[i] && standardEncoding[i]) { - enc[i] = (char *)standardEncoding[i]; - encFree[i] = gFalse; - } - } -@@ -734,14 +1151,21 @@ - } + // horizontal + if (cMap->getWMode() == 0) { +diff -ru xpdf-3.02/xpdf/GfxFont.h xpdf-3.03/xpdf/GfxFont.h +--- xpdf-3.02/xpdf/GfxFont.h 2007-02-27 23:05:52.000000000 +0100 ++++ xpdf-3.03/xpdf/GfxFont.h 2011-08-15 23:08:53.000000000 +0200 +@@ -91,7 +127,8 @@ + // Build a GfxFont object. + static GfxFont *makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict); - // pass 2: try to fill in the missing chars, looking for names of -- // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B' -- // are any letters, 'xx' is two hex digits, and 'nn' is 2-4 -- // decimal digits -+ // any of the following forms: -+ // - 'xx' -+ // - 'Axx' -+ // - 'nn' -+ // - 'Ann' -+ // - 'ABnn' -+ // - 'unixxxx' (possibly followed by garbage - some Arabic files -+ // use 'uni0628.medi', etc.) -+ // where 'A' and 'B' are any letters, 'xx' is two hex digits, 'xxxx' -+ // is four hex digits, and 'nn' is 2-4 decimal digits - if (missing && globalParams->getMapNumericCharNames()) { - for (code = 0; code < 256; ++code) { - if ((charName = enc[code]) && !toUnicode[code] && - strcmp(charName, ".notdef")) { - n = strlen(charName); - code2 = -1; - if (hex && n == 3 && isalpha(charName[0]) && - isxdigit(charName[1]) && isxdigit(charName[2])) { -@@ -758,8 +1182,13 @@ - } else if (n >= 4 && n <= 6 && - isdigit(charName[2]) && isdigit(charName[3])) { - code2 = atoi(charName+2); -+ } else if (n >= 7 && charName[0] == 'u' && charName[1] == 'n' && -+ charName[2] == 'i' && -+ isxdigit(charName[3]) && isxdigit(charName[4]) && -+ isxdigit(charName[5]) && isxdigit(charName[6])) { -+ sscanf(charName + 3, "%x", &code2); - } -- if (code2 >= 0 && code2 <= 0xff) { -+ if (code2 >= 0 && code2 <= 0xffff) { - toUnicode[code] = (Unicode)code2; - } - } -@@ -835,7 +1264,7 @@ - obj1.arrayGet(code - firstChar, &obj2); - if (obj2.isNum()) { - widths[code] = obj2.getNum() * mul; -- if (widths[code] != widths[firstChar]) { -+ if (fabs(widths[code] - widths[firstChar]) > 0.00001) { - flags &= ~fontFixedWidth; - } - } -@@ -945,9 +1374,10 @@ - // TrueType font has a Macintosh Roman cmap, use it, and - // reverse map the char names through MacRomanEncoding to - // get char codes. -- // 1b. If the TrueType font has a Microsoft Unicode cmap or a -- // non-Microsoft Unicode cmap, use it, and use the Unicode -- // indexes, not the char codes. -+ // 1b. If the PDF font is not symbolic or the PDF font is not -+ // embedded, and the TrueType font has a Microsoft Unicode -+ // cmap or a non-Microsoft Unicode cmap, use it, and use the -+ // Unicode indexes, not the char codes. - // 1c. If the PDF font is symbolic and the TrueType font has a - // Microsoft Symbol cmap, use it, and use char codes - // directly (possibly with an offset of 0xf000). -@@ -983,7 +1413,8 @@ - if (usesMacRomanEnc && macRomanCmap >= 0) { - cmap = macRomanCmap; - useMacRoman = gTrue; -- } else if (unicodeCmap >= 0) { -+ } else if ((!(flags & fontSymbolic) || embFontID.num < 0) && -+ unicodeCmap >= 0) { - cmap = unicodeCmap; - useUnicode = gTrue; - } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) { -@@ -1010,6 +1441,8 @@ - if ((code = globalParams->getMacRomanCharCode(charName))) { - map[i] = ff->mapCodeToGID(cmap, code); - } -+ } else { -+ map[i] = -1; - } - } +- GfxFont(char *tagA, Ref idA, GString *nameA); ++ GfxFont(char *tagA, Ref idA, GString *nameA, ++ GfxFontType typeA, Ref embFontIDA); -@@ -1020,6 +1453,8 @@ - (u = globalParams->mapNameToUnicode(charName))) || - (n = ctu->mapToUnicode((CharCode)i, &u, 1))) { - map[i] = ff->mapCodeToGID(cmap, u); -+ } else { -+ map[i] = -1; - } - } - -@@ -1035,8 +1470,8 @@ - - // try the TrueType 'post' table to handle any unmapped characters - for (i = 0; i < 256; ++i) { -- if (!map[i] && (charName = enc[i])) { -+ if (map[i] <= 0 && (charName = enc[i])) { - map[i] = ff->mapNameToGID(charName); - } - } - -@@ -1077,12 +1530,11 @@ - GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, -- Dict *fontDict): -- GfxFont(tagA, idA, nameA) -+ GfxFontType typeA, Ref embFontIDA, Dict *fontDict): -+ GfxFont(tagA, idA, nameA, typeA, embFontIDA) - { - Dict *desFontDict; -- GString *collection, *cMapName; - Object desFontDictObj; - Object obj1, obj2, obj3, obj4, obj5, obj6; - CharCodeToUnicode *utu; -@@ -1091,8 +1545,10 @@ - ascent = 0.95; - descent = -0.35; - fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; -+ collection = NULL; - cMap = NULL; - ctu = NULL; -+ ctuUsesCharCode = gTrue; - widths.defWidth = 1.0; - widths.defHeight = -1.0; - widths.defVY = 0.880; -@@ -1104,52 +1560,38 @@ - cidToGIDLen = 0; - - // get the descendant font -- if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) { -- error(-1, "Missing DescendantFonts entry in Type 0 font"); -+ if (!fontDict->lookup("DescendantFonts", &obj1)->isArray() || -+ obj1.arrayGetLength() == 0) { -+ error(errSyntaxError, -1, -+ "Missing or empty DescendantFonts entry in Type 0 font"); - obj1.free(); -+ - goto err1; - } - if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) { -- error(-1, "Bad descendant font in Type 0 font"); -- goto err3; -+ error(errSyntaxError, -1, "Bad descendant font in Type 0 font"); -+ goto err2; - } - obj1.free(); - desFontDict = desFontDictObj.getDict(); - -- // font type -- if (!desFontDict->lookup("Subtype", &obj1)) { -- error(-1, "Missing Subtype entry in Type 0 descendant font"); -- goto err3; -- } -- if (obj1.isName("CIDFontType0")) { -- type = fontCIDType0; -- } else if (obj1.isName("CIDFontType2")) { -- type = fontCIDType2; -- } else { -- error(-1, "Unknown Type 0 descendant font type '%s'", -- obj1.isName() ? obj1.getName() : "???"); -- goto err3; -- } -- obj1.free(); -- - // get info from font descriptor - readFontDescriptor(xref, desFontDict); - -- // look for an external font file -- findExtFontFile(); -- - //----- encoding info ----- - - // char collection - if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) { -- error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font"); -- goto err3; -+ error(errSyntaxError, -1, -+ "Missing CIDSystemInfo dictionary in Type 0 descendant font"); -+ goto err2; - } - obj1.dictLookup("Registry", &obj2); - obj1.dictLookup("Ordering", &obj3); - if (!obj2.isString() || !obj3.isString()) { -- error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font"); -- goto err4; -+ error(errSyntaxError, -1, -+ "Invalid CIDSystemInfo dictionary in Type 0 descendant font"); -+ goto err3; - } - collection = obj2.getString()->copy()->append('-')->append(obj3.getString()); - obj3.free(); -@@ -1158,19 +1600,18 @@ - - // look for a ToUnicode CMap - if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) { -+ ctuUsesCharCode = gFalse; - -- // the "Adobe-Identity" and "Adobe-UCS" collections don't have -- // cidToUnicode files -- if (collection->cmp("Adobe-Identity") && -- collection->cmp("Adobe-UCS")) { -- -- // look for a user-supplied .cidToUnicode file -- if (!(ctu = globalParams->getCIDToUnicode(collection))) { -- error(-1, "Unknown character collection '%s'", -- collection->getCString()); -- // fall-through, assuming the Identity mapping -- this appears -- // to match Adobe's behavior -- } -+ // use an identity mapping for the "Adobe-Identity" and -+ // "Adobe-UCS" collections -+ if (!collection->cmp("Adobe-Identity") || -+ !collection->cmp("Adobe-UCS")) { -+ ctu = CharCodeToUnicode::makeIdentityMapping(); -+ -+ // look for a user-supplied .cidToUnicode file -+ } else if (!(ctu = globalParams->getCIDToUnicode(collection))) { -+ error(errSyntaxError, -1, -+ "Unknown character collection '{0:t}'", collection); - } - } - -@@ -1193,43 +1634,35 @@ - } - - // encoding (i.e., CMap) -- //~ need to handle a CMap stream here -- //~ also need to deal with the UseCMap entry in the stream dict -- if (!fontDict->lookup("Encoding", &obj1)->isName()) { -- error(-1, "Missing or invalid Encoding entry in Type 0 font"); -- delete collection; -- goto err3; -+ if (fontDict->lookup("Encoding", &obj1)->isNull()) { -+ error(errSyntaxError, -1, "Missing Encoding entry in Type 0 font"); -+ goto err2; - } -- cMapName = new GString(obj1.getName()); -- obj1.free(); -- if (!(cMap = globalParams->getCMap(collection, cMapName))) { -- error(-1, "Unknown CMap '%s' for character collection '%s'", -- cMapName->getCString(), collection->getCString()); -- delete collection; -- delete cMapName; -+ if (!(cMap = CMap::parse(NULL, collection, &obj1))) { - goto err2; - } -- delete collection; -- delete cMapName; -+ obj1.free(); - -- // CIDToGIDMap (for embedded TrueType fonts) -- if (type == fontCIDType2) { -+ // CIDToGIDMap -+ // (the PDF spec only allows these for TrueType fonts, but Acrobat -+ // apparently also allows them for OpenType CFF fonts) -+ if (type == fontCIDType2 || type == fontCIDType0COT) { - desFontDict->lookup("CIDToGIDMap", &obj1); - if (obj1.isStream()) { - cidToGIDLen = 0; - i = 64; -@@ -1387,17 +1830,19 @@ - ok = gTrue; - return; - -- err4: -+ err3: - obj3.free(); - obj2.free(); -- err3: -- obj1.free(); - err2: -+ obj1.free(); - desFontDictObj.free(); - err1:; - } - - GfxCIDFont::~GfxCIDFont() { -+ if (collection) { -+ delete collection; -+ } - if (cMap) { - cMap->decRefCnt(); - } -@@ -1425,12 +1871,16 @@ - return 1; - } - - *code = (CharCode)(cid = cMap->getCID(s, len, &c, &n)); - if (ctu) { -- *uLen = ctu->mapToUnicode(cid, u, uSize); -+ *uLen = ctu->mapToUnicode(ctuUsesCharCode ? c : cid, u, uSize); - } else { - *uLen = 0; - } -+ if (!*uLen && uSize >= 1 && globalParams->getMapUnknownCharNames()) { -+ u[0] = *code; -+ *uLen = 1; -+ } - - // horizontal - if (cMap->getWMode() == 0) { -diff -ru xpdf-3.02/xpdf/GfxFont.h xpdf-3.03/xpdf/GfxFont.h ---- xpdf-3.02/xpdf/GfxFont.h 2007-02-27 23:05:52.000000000 +0100 -+++ xpdf-3.03/xpdf/GfxFont.h 2011-08-15 23:08:53.000000000 +0200 -@@ -91,7 +127,8 @@ - // Build a GfxFont object. - static GfxFont *makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict); - -- GfxFont(char *tagA, Ref idA, GString *nameA); -+ GfxFont(char *tagA, Ref idA, GString *nameA, -+ GfxFontType typeA, Ref embFontIDA); - - virtual ~GfxFont(); + virtual ~GfxFont(); @@ -126,10 +160,6 @@ // NULL if there is no embedded font. @@ -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 @@ -5810,5013 +4280,2969 @@ diff -ru xpdf-3.02/xpdf/PSOutputDev.cc xpdf-3.03/xpdf/PSOutputDev.cc + "/pdfImStr {", + " 2 copy exch length lt {", + " 2 copy get exch 1 add exch", -+ " } {", -+ " ()", -+ " } ifelse", -+ "} def", - "/pdfImM1a {", -- " { 2 copy get exch 1 add exch } imagemask", -+ " { pdfImStr } imagemask", - " pop pop", - "} def", - "~23sn", -- "% Level 2 image operators", -+ "% Level 2/3 image operators", - "/pdfImBuf 100 string def", -- "/pdfIm {", -- " image", -+ "/pdfImStr {", -+ " 2 copy exch length lt {", -+ " 2 copy get exch 1 add exch", -+ " } {", -+ " ()", -+ " } ifelse", -+ "} def", -+ "/skipEOD {", - " { currentfile pdfImBuf readline", - " not { pop exit } if", - " (%-EOD-) eq { exit } if } loop", - "} def", -+ "/pdfIm { image skipEOD } def", -+ "~3sn", -+ "/pdfMask {", -+ " /ReusableStreamDecode filter", -+ " skipEOD", -+ " /maskStream exch def", -+ "} def", -+ "/pdfMaskEnd { maskStream closefile } def", -+ "/pdfMaskInit {", -+ " /maskArray exch def", -+ " /maskIdx 0 def", -+ "} def", -+ "/pdfMaskSrc {", -+ " maskIdx maskArray length lt {", -+ " maskArray maskIdx get", -+ " /maskIdx maskIdx 1 add def", -+ " } {", -+ " ()", -+ " } ifelse", -+ "} def", - "~23s", - "/pdfImSep {", - " findcmykcustomcolor exch", -@@ -523,17 +567,10 @@ - " 255 exch sub put", - " } for }", - " 6 5 roll customcolorimage", -- " { currentfile pdfImBuf readline", -- " not { pop exit } if", -- " (%-EOD-) eq { exit } if } loop", -+ " skipEOD", - "} def", - "~23sn", -- "/pdfImM {", -- " fCol imagemask", -- " { currentfile pdfImBuf readline", -- " not { pop exit } if", -- " (%-EOD-) eq { exit } if } loop", -- "} def", -+ "/pdfImM { fCol imagemask skipEOD } def", - "/pr { 2 index 2 index 3 2 roll putinterval 4 add } def", - "/pdfImClip {", - " gsave", -@@ -607,7 +644,7 @@ - " func n array astore", - "} def", - "/axialSH {", -- " dup 0 eq {", -+ " dup 2 lt {", - " true", - " } {", - " dup 8 eq {", -@@ -753,25 +790,12 @@ - double mWidth; // width of 'm' character - }; - --static char *psFonts[] = { -- "Courier", -- "Courier-Bold", -- "Courier-Oblique", -- "Courier-BoldOblique", -- "Helvetica", -- "Helvetica-Bold", -- "Helvetica-Oblique", -- "Helvetica-BoldOblique", -- "Symbol", -- "Times-Roman", -- "Times-Bold", -- "Times-Italic", -- "Times-BoldItalic", -- "ZapfDingbats", -- NULL --}; -- --static PSSubstFont psSubstFonts[] = { -+// NB: must be in same order as base14SubstFonts in GfxFont.cc -+static PSSubstFont psBase14SubstFonts[14] = { -+ {"Courier", 0.600}, -+ {"Courier-Oblique", 0.600}, -+ {"Courier-Bold", 0.600}, -+ {"Courier-BoldOblique", 0.600}, - {"Helvetica", 0.833}, - {"Helvetica-Oblique", 0.833}, - {"Helvetica-Bold", 0.889}, -@@ -780,22 +804,28 @@ - {"Times-Italic", 0.722}, - {"Times-Bold", 0.833}, - {"Times-BoldItalic", 0.778}, -- {"Courier", 0.600}, -- {"Courier-Oblique", 0.600}, -- {"Courier-Bold", 0.600}, -- {"Courier-BoldOblique", 0.600} -+ // the last two are never used for substitution -+ {"Symbol", 0}, -+ {"ZapfDingbats", 0} -+}; -+ -+// Mapping from Type 1/1C font file to PS font name. -+struct PST1FontName { -+ Ref fontFileID; -+ GString *psName; // PostScript font name used for this -+ // embedded font file - }; - - // Encoding info for substitute 16-bit font - struct PSFont16Enc { - Ref fontID; -- GString *enc; -+ GString *enc; // NULL means font wasn't correctly substituted - }; - - //------------------------------------------------------------------------ -@@ -845,6 +875,13 @@ - }; - - //------------------------------------------------------------------------ -+ -+struct PSOutPaperSize { -+ PSOutPaperSize(int wA, int hA) { w = wA; h = hA; } -+ int w, h; -+}; -+ -+//------------------------------------------------------------------------ - // DeviceNRecoder - //------------------------------------------------------------------------ - -@@ -897,6 +934,9 @@ - if (imgStr) { - delete imgStr; - } -+ if (str->isEncoder()) { -+ delete str; -+ } - } - - void DeviceNRecoder::reset() { -@@ -942,10 +982,12 @@ - fwrite(data, 1, len, (FILE *)stream); - } - - PSOutputDev::PSOutputDev(char *fileName, PDFDoc *docA, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, -- GBool manualCtrlA) { -+ GBool manualCtrlA, -+ PSOutCustomCodeCbk customCodeCbkA, -+ void *customCodeCbkDataA) { - FILE *f; - PSFileType fileTypeA; - -@@ -953,15 +995,18 @@ - underlayCbkData = NULL; - overlayCbk = NULL; - overlayCbkData = NULL; -+ customCodeCbk = customCodeCbkA; -+ customCodeCbkData = customCodeCbkDataA; - - fontIDs = NULL; -- fontFileIDs = NULL; -- fontFileNames = NULL; -+ fontNames = new GHash(gTrue); -+ t1FontNames = NULL; - font8Info = NULL; - font16Enc = NULL; - imgIDs = NULL; - formIDs = NULL; - xobjStack = NULL; -+ paperSizes = NULL; - embFontList = NULL; - customColors = NULL; - haveTextClip = gFalse; -@@ -978,71 +1023,82 @@ - signal(SIGPIPE, (SignalFunc)SIG_IGN); - #endif - if (!(f = popen(fileName + 1, "w"))) { - error(errIO, -1, "Couldn't run print command '{0:s}'", fileName); - ok = gFalse; - return; - } - #else - error(errIO, -1, "Print commands are not supported ('{0:s}')", fileName); - ok = gFalse; - return; - #endif - } else { - fileTypeA = psFile; - if (!(f = fopen(fileName, "w"))) { - error(errIO, -1, "Couldn't open PostScript file '{0:s}'", fileName); - ok = gFalse; - return; - } - } - - init(outputToFile, f, fileTypeA, -- xrefA, catalog, firstPage, lastPage, modeA, -+ docA, firstPage, lastPage, modeA, - imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA); - } - - PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, - PDFDoc *docA, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, -- GBool manualCtrlA) { -+ GBool manualCtrlA, -+ PSOutCustomCodeCbk customCodeCbkA, -+ void *customCodeCbkDataA) { - underlayCbk = NULL; - underlayCbkData = NULL; - overlayCbk = NULL; - overlayCbkData = NULL; -+ customCodeCbk = customCodeCbkA; -+ customCodeCbkData = customCodeCbkDataA; - - fontIDs = NULL; -- fontFileIDs = NULL; -- fontFileNames = NULL; -+ fontNames = new GHash(gTrue); -+ t1FontNames = NULL; - font8Info = NULL; - font16Enc = NULL; - imgIDs = NULL; - formIDs = NULL; - xobjStack = NULL; -+ paperSizes = NULL; - embFontList = NULL; - customColors = NULL; - haveTextClip = gFalse; - t3String = NULL; - - init(outputFuncA, outputStreamA, psGeneric, - docA, firstPage, lastPage, modeA, - imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA); - } - - void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, - PSFileType fileTypeA, PDFDoc *docA, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, - GBool manualCtrlA) { - Catalog *catalog; - Page *page; - PDFRectangle *box; -+ PSOutPaperSize *size; -+ GList *names; -+ int pg, w, h, i; - - // initialize - ok = gTrue; - outputFunc = outputFuncA; - outputStream = outputStreamA; - fileType = fileTypeA; - doc = docA; - xref = doc->getXRef(); - catalog = doc->getCatalog(); - level = globalParams->getPSLevel(); - mode = modeA; - paperWidth = globalParams->getPSPaperWidth(); -@@ -1055,18 +1111,34 @@ - globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY); - } - if (paperWidth < 0 || paperHeight < 0) { -- // this check is needed in case the document has zero pages -- if (firstPage > 0 && firstPage <= catalog->getNumPages()) { -- page = catalog->getPage(firstPage); -- paperWidth = (int)ceil(page->getMediaWidth()); -- paperHeight = (int)ceil(page->getMediaHeight()); -- } else { -- paperWidth = 1; -- paperHeight = 1; -- } -- imgLLX = imgLLY = 0; -- imgURX = paperWidth; -- imgURY = paperHeight; -+ paperMatch = gTrue; -+ paperSizes = new GList(); -+ paperWidth = paperHeight = 1; // in case the document has zero pages -+ for (pg = (firstPage >= 1) ? firstPage : 1; -+ pg <= lastPage && pg <= catalog->getNumPages(); -+ ++pg) { -+ page = catalog->getPage(pg); -+ w = (int)ceil(page->getMediaWidth()); -+ h = (int)ceil(page->getMediaHeight()); -+ for (i = 0; i < paperSizes->getLength(); ++i) { -+ size = (PSOutPaperSize *)paperSizes->get(i); -+ if (size->w == w && size->h == h) { -+ break; -+ } -+ } -+ if (i == paperSizes->getLength()) { -+ paperSizes->append(new PSOutPaperSize(w, h)); -+ } -+ if (w > paperWidth) { -+ paperWidth = w; -+ } -+ if (h > paperHeight) { -+ paperHeight = h; -+ } -+ } -+ // NB: img{LLX,LLY,URX,URY} will be set by startPage() -+ } else { -+ paperMatch = gFalse; - } - preload = globalParams->getPSPreload(); - manualCtrl = manualCtrlA; -@@ -1088,17 +1160,21 @@ - clipLLX0 = clipLLY0 = 0; - clipURX0 = clipURY0 = -1; - -- // initialize fontIDs, fontFileIDs, and fontFileNames lists -+ // initialize fontIDs and fontNames lists - fontIDSize = 64; - fontIDLen = 0; - fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref)); -- fontFileIDSize = 64; -- fontFileIDLen = 0; -- fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref)); -- fontFileNameSize = 64; -- fontFileNameLen = 0; -- fontFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *)); -- nextTrueTypeNum = 0; -+ for (i = 0; i < 14; ++i) { -+ fontNames->add(new GString(psBase14SubstFonts[i].psName), 1); -+ } -+ names = globalParams->getPSResidentFonts(); -+ for (i = 0; i < names->getLength(); ++i) { -+ fontNames->add((GString *)names->get(i), 1); -+ } -+ delete names; -+ t1FontNameSize = 64; -+ t1FontNameLen = 0; -+ t1FontNames = (PST1FontName *)gmallocn(t1FontNameSize, sizeof(PST1FontName)); - font8InfoLen = 0; - font8InfoSize = 0; - font16EncLen = 0; -@@ -1173,20 +1249,21 @@ - } - #endif - } -+ if (paperSizes) { -+ deleteGList(paperSizes, PSOutPaperSize); -+ } - if (embFontList) { - delete embFontList; - } - if (fontIDs) { - gfree(fontIDs); - } -- if (fontFileIDs) { -- gfree(fontFileIDs); -- } -- if (fontFileNames) { -- for (i = 0; i < fontFileNameLen; ++i) { -- delete fontFileNames[i]; -+ delete fontNames; -+ if (t1FontNames) { -+ for (i = 0; i < t1FontNameLen; ++i) { -+ delete t1FontNames[i].psName; - } -- gfree(fontFileNames); -+ gfree(t1FontNames); - } - if (font8Info) { - for (i = 0; i < font8InfoLen; ++i) { -@@ -1196,7 +1273,9 @@ - } - if (font16Enc) { - for (i = 0; i < font16EncLen; ++i) { -- delete font16Enc[i].enc; -+ if (font16Enc[i].enc) { -+ delete font16Enc[i].enc; -+ } - } - gfree(font16Enc); - } -@@ -1216,7 +1295,9 @@ - PDFRectangle *mediaBox, PDFRectangle *cropBox, - int pageRotate) { - Object info, obj1; -+ PSOutPaperSize *size; - double x1, y1, x2, y2; -+ int i; - - switch (mode) { - case psModePS: -@@ -1230,7 +1311,7 @@ - break; - } - -- writePSFmt("% Produced by xpdf/pdftops {0:s}\n", xpdfVersion); -+ writePSFmt("%XpdfVersion: {0:s}\n", xpdfVersion); - xref->getDocInfo(&info); - if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) { - writePS("%%Creator: "); -@@ -1254,14 +1335,24 @@ - - switch (mode) { - case psModePS: -- writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n", -- paperWidth, paperHeight); -+ if (paperMatch) { -+ for (i = 0; i < paperSizes->getLength(); ++i) { -+ size = (PSOutPaperSize *)paperSizes->get(i); -+ writePSFmt("%%{0:s} {1:d}x{2:d} {1:d} {2:d} 0 () ()\n", -+ i==0 ? "DocumentMedia:" : "+", size->w, size->h); -+ } -+ } else { -+ writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n", -+ paperWidth, paperHeight); -+ } - writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight); - writePSFmt("%%Pages: {0:d}\n", lastPage - firstPage + 1); - writePS("%%EndComments\n"); -- writePS("%%BeginDefaults\n"); -- writePS("%%PageMedia: plain\n"); -- writePS("%%EndDefaults\n"); -+ if (!paperMatch) { -+ writePS("%%BeginDefaults\n"); -+ writePS("%%PageMedia: plain\n"); -+ writePS("%%EndDefaults\n"); -+ } - break; - case psModeEPS: - epsX1 = cropBox->x1; -@@ -1343,7 +1434,9 @@ - Page *page; - Dict *resDict; - Annots *annots; -- Object obj1, obj2; -+ Object *acroForm; -+ Object obj1, obj2, obj3; -+ GString *s; - int pg, i; - - if (mode == psModeForm) { -@@ -1371,11 +1464,31 @@ - } - delete annots; - } -+ if ((acroForm = catalog->getAcroForm()) && acroForm->isDict()) { -+ if (acroForm->dictLookup("DR", &obj1)->isDict()) { -+ setupResources(obj1.getDict()); -+ } -+ obj1.free(); -+ if (acroForm->dictLookup("Fields", &obj1)->isArray()) { -+ for (i = 0; i < obj1.arrayGetLength(); ++i) { -+ if (obj1.arrayGet(i, &obj2)->isDict()) { -+ if (obj2.dictLookup("DR", &obj3)->isDict()) { -+ setupResources(obj3.getDict()); -+ } -+ obj3.free(); -+ } -+ obj2.free(); -+ } -+ } -+ obj1.free(); -+ } - if (mode != psModeForm) { - if (mode != psModeEPS && !manualCtrl) { -- writePSFmt("{0:d} {1:d} {2:s} pdfSetup\n", -- paperWidth, paperHeight, -+ writePSFmt("{0:s} pdfSetup\n", - globalParams->getPSDuplex() ? "true" : "false"); -+ if (!paperMatch) { -+ writePSFmt("{0:d} {1:d} pdfSetupPaper\n", paperWidth, paperHeight); -+ } - } - #if OPI_SUPPORT - if (globalParams->getPSOPI()) { -@@ -1383,6 +1496,13 @@ - } - #endif - } -+ if (customCodeCbk) { -+ if ((s = (*customCodeCbk)(this, psOutCustomDocSetup, 0, -+ customCodeCbkData))) { -+ writePS(s->getCString()); -+ delete s; -+ } -+ } - } - - void PSOutputDev::writePageTrailer() { -@@ -1558,18 +1681,15 @@ - } - - void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { -- Ref fontFileID; -- GString *name; -- PSFontParam *fontParam; -+ GfxFontLoc *fontLoc; - GString *psName; -- char buf[16]; - GBool subst; -+ char buf[16]; - UnicodeMap *uMap; - char *charName; - double xs, ys; - int code; - double w1, w2; -- double *fm; - int i, j; - - // check if font is already set up -@@ -1587,119 +1707,120 @@ - } - fontIDs[fontIDLen++] = *font->getID(); - -+ psName = NULL; - xs = ys = 1; - subst = gFalse; - -- // check for resident 8-bit font -- if (font->getName() && -- (fontParam = globalParams->getPSFont(font->getName()))) { -- psName = new GString(fontParam->psFontName->getCString()); -- -- // check for embedded Type 1 font -- } else if (globalParams->getPSEmbedType1() && -- font->getType() == fontType1 && -- font->getEmbeddedFontID(&fontFileID)) { -- psName = filterPSName(font->getEmbeddedFontName()); -- setupEmbeddedType1Font(&fontFileID, psName); -- -- // check for embedded Type 1C font -- } else if (globalParams->getPSEmbedType1() && -- font->getType() == fontType1C && -- font->getEmbeddedFontID(&fontFileID)) { -- // use the PDF font name because the embedded font name might -- // not include the subset prefix -- psName = filterPSName(font->getOrigName()); -- setupEmbeddedType1CFont(font, &fontFileID, psName); -- -- // check for embedded OpenType - Type 1C font -- } else if (globalParams->getPSEmbedType1() && -- font->getType() == fontType1COT && -- font->getEmbeddedFontID(&fontFileID)) { -- // use the PDF font name because the embedded font name might -- // not include the subset prefix -- psName = filterPSName(font->getOrigName()); -- setupEmbeddedOpenTypeT1CFont(font, &fontFileID, psName); -- -- // check for external Type 1 font file -- } else if (globalParams->getPSEmbedType1() && -- font->getType() == fontType1 && -- font->getExtFontFile()) { -- // this assumes that the PS font name matches the PDF font name -- psName = font->getName()->copy(); -- setupExternalType1Font(font->getExtFontFile(), psName); -- -- // check for embedded TrueType font -- } else if (globalParams->getPSEmbedTrueType() && -- (font->getType() == fontTrueType || -- font->getType() == fontTrueTypeOT) && -- font->getEmbeddedFontID(&fontFileID)) { -- psName = filterPSName(font->getEmbeddedFontName()); -- setupEmbeddedTrueTypeFont(font, &fontFileID, psName); -- -- // check for external TrueType font file -- } else if (globalParams->getPSEmbedTrueType() && -- font->getType() == fontTrueType && -- font->getExtFontFile()) { -- psName = filterPSName(font->getName()); -- setupExternalTrueTypeFont(font, psName); -- -- // check for embedded CID PostScript font -- } else if (globalParams->getPSEmbedCIDPostScript() && -- font->getType() == fontCIDType0C && -- font->getEmbeddedFontID(&fontFileID)) { -- psName = filterPSName(font->getEmbeddedFontName()); -- setupEmbeddedCIDType0Font(font, &fontFileID, psName); -- -- // check for embedded CID TrueType font -- } else if (globalParams->getPSEmbedCIDTrueType() && -- (font->getType() == fontCIDType2 || -- font->getType() == fontCIDType2OT) && -- font->getEmbeddedFontID(&fontFileID)) { -- psName = filterPSName(font->getEmbeddedFontName()); -- //~ should check to see if font actually uses vertical mode -- setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue); -- -- // check for embedded OpenType - CID CFF font -- } else if (globalParams->getPSEmbedCIDPostScript() && -- font->getType() == fontCIDType0COT && -- font->getEmbeddedFontID(&fontFileID)) { -- psName = filterPSName(font->getEmbeddedFontName()); -- setupEmbeddedOpenTypeCFFFont(font, &fontFileID, psName); -- -- // check for Type 3 font -- } else if (font->getType() == fontType3) { -+ if (font->getType() == fontType3) { - psName = GString::format("T3_{0:d}_{1:d}", - font->getID()->num, font->getID()->gen); - setupType3Font(font, psName, parentResDict); -- -- // do 8-bit font substitution -- } else if (!font->isCIDFont()) { -- subst = gTrue; -- name = font->getName(); -- psName = NULL; -- if (name) { -- for (i = 0; psFonts[i]; ++i) { -- if (name->cmp(psFonts[i]) == 0) { -- psName = new GString(psFonts[i]); -- break; -+ } else { -+ fontLoc = font->locateFont(xref, gTrue); -+ switch (fontLoc->locType) { -+ case gfxFontLocEmbedded: -+ switch (fontLoc->fontType) { -+ case fontType1: -+ // this assumes that the PS font name matches the PDF font name -+ psName = font->getEmbeddedFontName()->copy(); -+ setupEmbeddedType1Font(&fontLoc->embFontID, psName); -+ break; -+ case fontType1C: -+ psName = makePSFontName(font, &fontLoc->embFontID); -+ setupEmbeddedType1CFont(font, &fontLoc->embFontID, psName); -+ break; -+ case fontType1COT: -+ psName = makePSFontName(font, &fontLoc->embFontID); -+ setupEmbeddedOpenTypeT1CFont(font, &fontLoc->embFontID, psName); -+ break; -+ case fontTrueType: -+ case fontTrueTypeOT: -+ psName = makePSFontName(font, font->getID()); -+ setupEmbeddedTrueTypeFont(font, &fontLoc->embFontID, psName); -+ break; -+ case fontCIDType0C: -+ psName = makePSFontName(font, &fontLoc->embFontID); -+ setupEmbeddedCIDType0Font(font, &fontLoc->embFontID, psName); -+ break; -+ case fontCIDType2: -+ case fontCIDType2OT: -+ psName = makePSFontName(font, font->getID()); -+ //~ should check to see if font actually uses vertical mode -+ setupEmbeddedCIDTrueTypeFont(font, &fontLoc->embFontID, psName, gTrue); -+ break; -+ case fontCIDType0COT: -+ psName = makePSFontName(font, &fontLoc->embFontID); -+ setupEmbeddedOpenTypeCFFFont(font, &fontLoc->embFontID, psName); -+ break; -+ default: -+ break; -+ } -+ break; -+ case gfxFontLocExternal: -+ //~ add cases for external 16-bit fonts -+ switch (fontLoc->fontType) { -+ case fontType1: -+ if (font->getName()) { -+ // this assumes that the PS font name matches the PDF font name -+ psName = font->getName()->copy(); -+ } else { -+ //~ this won't work -- the PS font name won't match -+ psName = makePSFontName(font, font->getID()); - } -+ setupExternalType1Font(fontLoc->path, psName); -+ break; -+ case fontTrueType: -+ case fontTrueTypeOT: -+ psName = makePSFontName(font, font->getID()); -+ setupExternalTrueTypeFont(font, fontLoc->path, psName); -+ break; -+ case fontCIDType2: -+ case fontCIDType2OT: -+ psName = makePSFontName(font, font->getID()); -+ //~ should check to see if font actually uses vertical mode -+ setupExternalCIDTrueTypeFont(font, fontLoc->path, psName, gTrue); -+ break; -+ default: -+ break; - } -+ break; -+ case gfxFontLocResident: -+ psName = fontLoc->path->copy(); -+ break; - } -+ - if (!psName) { -- if (font->isFixedWidth()) { -- i = 8; -- } else if (font->isSerif()) { -- i = 4; -+ if (font->isCIDFont()) { -+ error(errSyntaxError, -1, -+ "Couldn't find a font to substitute for '{0:s}' ('{1:s}' character collection)", -+ font->getName() ? font->getName()->getCString() -+ : "(unnamed)", -+ ((GfxCIDFont *)font)->getCollection() -+ ? ((GfxCIDFont *)font)->getCollection()->getCString() -+ : "(unknown)"); -+ if (font16EncLen >= font16EncSize) { -+ font16EncSize += 16; -+ font16Enc = (PSFont16Enc *)greallocn(font16Enc, -+ font16EncSize, -+ sizeof(PSFont16Enc)); -+ } -+ font16Enc[font16EncLen].fontID = *font->getID(); -+ font16Enc[font16EncLen].enc = NULL; -+ ++font16EncLen; - } else { -- i = 0; -- } -- if (font->isBold()) { -- i += 2; -- } -- if (font->isItalic()) { -- i += 1; -+ error(errSyntaxError, -1, -+ "Couldn't find a font to substitute for '{0:s}'", -+ font->getName() ? font->getName()->getCString() -+ : "(unnamed)"); - } -- psName = new GString(psSubstFonts[i].psName); -+ delete fontLoc; -+ return; -+ } -+ -+ // scale substituted 8-bit fonts -+ if (fontLoc->locType == gfxFontLocResident && -+ fontLoc->substIdx >= 0) { -+ subst = gTrue; - for (code = 0; code < 256; ++code) { - if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) && - charName[0] == 'm' && charName[1] == '\0') { -@@ -1711,56 +1832,37 @@ - } else { - w1 = 0; - } -- w2 = psSubstFonts[i].mWidth; -+ w2 = psBase14SubstFonts[fontLoc->substIdx].mWidth; - xs = w1 / w2; - if (xs < 0.1) { - xs = 1; - } -- if (font->getType() == fontType3) { -- // This is a hack which makes it possible to substitute for some -- // Type 3 fonts. The problem is that it's impossible to know what -- // the base coordinate system used in the font is without actually -- // rendering the font. -- ys = xs; -- fm = font->getFontMatrix(); -- if (fm[0] != 0) { -- ys *= fm[3] / fm[0]; -- } -- } else { -- ys = 1; -- } - } - -- // do 16-bit font substitution -- } else if ((fontParam = globalParams-> -- getPSFont16(font->getName(), -- ((GfxCIDFont *)font)->getCollection(), -- font->getWMode()))) { -- subst = gTrue; -- psName = fontParam->psFontName->copy(); -- if (font16EncLen >= font16EncSize) { -- font16EncSize += 16; -- font16Enc = (PSFont16Enc *)greallocn(font16Enc, -- font16EncSize, sizeof(PSFont16Enc)); -- } -- font16Enc[font16EncLen].fontID = *font->getID(); -- font16Enc[font16EncLen].enc = fontParam->encoding->copy(); -- if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) { -- uMap->decRefCnt(); -+ // handle encodings for substituted CID fonts -+ if (fontLoc->locType == gfxFontLocResident && -+ fontLoc->fontType >= fontCIDType0) { -+ subst = gTrue; -+ if (font16EncLen >= font16EncSize) { -+ font16EncSize += 16; -+ font16Enc = (PSFont16Enc *)greallocn(font16Enc, -+ font16EncSize, -+ sizeof(PSFont16Enc)); -+ } -+ font16Enc[font16EncLen].fontID = *font->getID(); -+ if ((uMap = globalParams->getUnicodeMap(fontLoc->encoding))) { -+ font16Enc[font16EncLen].enc = fontLoc->encoding->copy(); -+ uMap->decRefCnt(); -+ } else { -+ error(errSyntaxError, -1, -+ "Couldn't find Unicode map for 16-bit font encoding '{0:t}'", -+ fontLoc->encoding); -+ font16Enc[font16EncLen].enc = NULL; -+ } - ++font16EncLen; -- } else { -- error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'", -- font16Enc[font16EncLen].enc->getCString()); - } - -- // give up - can't do anything with this font -- } else { -- error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)", -- font->getName() ? font->getName()->getCString() : "(unnamed)", -- ((GfxCIDFont *)font)->getCollection() -- ? ((GfxCIDFont *)font)->getCollection()->getCString() -- : "(unknown)"); -- return; -+ delete fontLoc; - } - - // generate PostScript code to set up the font -@@ -1787,11 +1889,6 @@ - charName = buf; - } else { - charName = ((Gfx8BitFont *)font)->getCharName(i+j); -- // this is a kludge for broken PDF files that encode char 32 -- // as .notdef -- if (i+j == 32 && charName && !strcmp(charName, ".notdef")) { -- charName = "space"; -- } - } - writePS("/"); - writePSName(charName ? charName : (char *)".notdef"); -@@ -1821,36 +1918,30 @@ - int i; - - // check if font is already embedded -- for (i = 0; i < fontFileIDLen; ++i) { -- if (fontFileIDs[i].num == id->num && -- fontFileIDs[i].gen == id->gen) -- return; -- } -- -- // add entry to fontFileIDs list -- if (fontFileIDLen >= fontFileIDSize) { -- fontFileIDSize += 64; -- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); -+ if (fontNames->lookupInt(psName)) { -+ return; - } -- fontFileIDs[fontFileIDLen++] = *id; -+ fontNames->add(psName->copy(), 1); - - // get the font stream and info - refObj.initRef(id->num, id->gen); - refObj.fetch(xref, &strObj); - refObj.free(); - if (!strObj.isStream()) { - error(errSyntaxError, -1, "Embedded font file object is not a stream"); - goto err1; - } - if (!(dict = strObj.streamGetDict())) { - error(errSyntaxError, -1, - "Embedded font stream is missing its dictionary"); - goto err1; - } - dict->lookup("Length1", &obj1); - dict->lookup("Length2", &obj2); - dict->lookup("Length3", &obj3); - if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) { - error(errSyntaxError, -1, - "Missing length fields in embedded font stream dictionary"); - obj1.free(); - obj2.free(); - obj3.free(); -@@ -1947,22 +2039,12 @@ - void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) { - FILE *fontFile; - int c; -- int i; - - // check if font is already embedded -- for (i = 0; i < fontFileNameLen; ++i) { -- if (!fontFileNames[i]->cmp(fileName)) { -- return; -- } -- } -- -- // add entry to fontFileNames list -- if (fontFileNameLen >= fontFileNameSize) { -- fontFileNameSize += 64; -- fontFileNames = (GString **)greallocn(fontFileNames, -- fontFileNameSize, sizeof(GString *)); -+ if (fontNames->lookupInt(psName)) { -+ return; - } -- fontFileNames[fontFileNameLen++] = fileName->copy(); -+ fontNames->add(psName->copy(), 1); - - // beginning comment - writePSFmt("%%BeginResource: font {0:t}\n", psName); -@@ -1992,18 +2074,22 @@ - int i; - - // check if font is already embedded -- for (i = 0; i < fontFileIDLen; ++i) { -- if (fontFileIDs[i].num == id->num && -- fontFileIDs[i].gen == id->gen) -+ for (i = 0; i < t1FontNameLen; ++i) { -+ if (t1FontNames[i].fontFileID.num == id->num && -+ t1FontNames[i].fontFileID.gen == id->gen) { -+ psName->clear(); -+ psName->insert(0, t1FontNames[i].psName); - return; -+ } - } -- -- // add entry to fontFileIDs list -- if (fontFileIDLen >= fontFileIDSize) { -- fontFileIDSize += 64; -- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); -- } -- fontFileIDs[fontFileIDLen++] = *id; -+ if (t1FontNameLen == t1FontNameSize) { -+ t1FontNameSize *= 2; -+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, -+ sizeof(PST1FontName)); -+ } -+ t1FontNames[t1FontNameLen].fontFileID = *id; -+ t1FontNames[t1FontNameLen].psName = psName->copy(); -+ ++t1FontNameLen; - - // beginning comment - writePSFmt("%%BeginResource: font {0:t}\n", psName); -@@ -2012,13 +2098,14 @@ - embFontList->append("\n"); - - // convert it to a Type 1 font -- fontBuf = font->readEmbFontFile(xref, &fontLen); -- if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { -- ffT1C->convertToType1(psName->getCString(), NULL, gTrue, -- outputFunc, outputStream); -- delete ffT1C; -+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { -+ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { -+ ffT1C->convertToType1(psName->getCString(), NULL, gTrue, -+ outputFunc, outputStream); -+ delete ffT1C; -+ } -+ gfree(fontBuf); - } -- gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); -@@ -2032,18 +2119,22 @@ - int i; - - // check if font is already embedded -- for (i = 0; i < fontFileIDLen; ++i) { -- if (fontFileIDs[i].num == id->num && -- fontFileIDs[i].gen == id->gen) -+ for (i = 0; i < t1FontNameLen; ++i) { -+ if (t1FontNames[i].fontFileID.num == id->num && -+ t1FontNames[i].fontFileID.gen == id->gen) { -+ psName->clear(); -+ psName->insert(0, t1FontNames[i].psName); - return; -+ } - } -- -- // add entry to fontFileIDs list -- if (fontFileIDLen >= fontFileIDSize) { -- fontFileIDSize += 64; -- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); -- } -- fontFileIDs[fontFileIDLen++] = *id; -+ if (t1FontNameLen == t1FontNameSize) { -+ t1FontNameSize *= 2; -+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, -+ sizeof(PST1FontName)); -+ } -+ t1FontNames[t1FontNameLen].fontFileID = *id; -+ t1FontNames[t1FontNameLen].psName = psName->copy(); -+ ++t1FontNameLen; - - // beginning comment - writePSFmt("%%BeginResource: font {0:t}\n", psName); -@@ -2052,15 +2143,16 @@ - embFontList->append("\n"); - - // convert it to a Type 1 font -- fontBuf = font->readEmbFontFile(xref, &fontLen); -- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { -- if (ffTT->isOpenTypeCFF()) { -- ffTT->convertToType1(psName->getCString(), NULL, gTrue, -- outputFunc, outputStream); -+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { -+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { -+ if (ffTT->isOpenTypeCFF()) { -+ ffTT->convertToType1(psName->getCString(), NULL, gTrue, -+ outputFunc, outputStream); -+ } -+ delete ffTT; - } -- delete ffTT; -+ gfree(fontBuf); - } -- gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); -@@ -2071,26 +2163,7 @@ - char *fontBuf; - int fontLen; - FoFiTrueType *ffTT; - int *codeToGID; -- int i; -- -- // check if font is already embedded -- for (i = 0; i < fontFileIDLen; ++i) { -- if (fontFileIDs[i].num == id->num && -- fontFileIDs[i].gen == id->gen) { -- psName->appendf("_{0:d}", nextTrueTypeNum++); -- break; -- } -- } -- -- // add entry to fontFileIDs list -- if (i == fontFileIDLen) { -- if (fontFileIDLen >= fontFileIDSize) { -- fontFileIDSize += 64; -- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); -- } -- fontFileIDs[fontFileIDLen++] = *id; -- } - - // beginning comment - writePSFmt("%%BeginResource: font {0:t}\n", psName); -@@ -2099,60 +2172,38 @@ - embFontList->append("\n"); - - // convert it to a Type 42 font -- fontBuf = font->readEmbFontFile(xref, &fontLen); -- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { -- codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); -- ffTT->convertToType42(psName->getCString(), -- ((Gfx8BitFont *)font)->getHasEncoding() -- ? ((Gfx8BitFont *)font)->getEncoding() -- : (char **)NULL, -- codeToGID, outputFunc, outputStream); -- if (codeToGID) { -- if (font8InfoLen >= font8InfoSize) { -- font8InfoSize += 16; -- font8Info = (PSFont8Info *)greallocn(font8Info, -- font8InfoSize, -- sizeof(PSFont8Info)); -+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { -+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { -+ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); -+ ffTT->convertToType42(psName->getCString(), -+ ((Gfx8BitFont *)font)->getHasEncoding() -+ ? ((Gfx8BitFont *)font)->getEncoding() -+ : (char **)NULL, -+ codeToGID, outputFunc, outputStream); -+ if (codeToGID) { -+ if (font8InfoLen >= font8InfoSize) { -+ font8InfoSize += 16; -+ font8Info = (PSFont8Info *)greallocn(font8Info, -+ font8InfoSize, -+ sizeof(PSFont8Info)); -+ } -+ font8Info[font8InfoLen].fontID = *font->getID(); -+ font8Info[font8InfoLen].codeToGID = codeToGID; -+ ++font8InfoLen; - } -- font8Info[font8InfoLen].fontID = *font->getID(); -- font8Info[font8InfoLen].codeToGID = codeToGID; -- ++font8InfoLen; -+ delete ffTT; - } -- delete ffTT; -+ gfree(fontBuf); - } -- gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); - } - --void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) { -- GString *fileName; -- char *fontBuf; -- int fontLen; -+void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *fileName, -+ GString *psName) { - FoFiTrueType *ffTT; - int *codeToGID; -- int i; -- -- // check if font is already embedded -- fileName = font->getExtFontFile(); -- for (i = 0; i < fontFileNameLen; ++i) { -- if (!fontFileNames[i]->cmp(fileName)) { -- psName->appendf("_{0:d}", nextTrueTypeNum++); -- break; -- } -- } -- -- // add entry to fontFileNames list -- if (i == fontFileNameLen) { -- if (fontFileNameLen >= fontFileNameSize) { -- fontFileNameSize += 64; -- fontFileNames = -- (GString **)greallocn(fontFileNames, -- fontFileNameSize, sizeof(GString *)); -- } -- fontFileNames[fontFileNameLen++] = fileName->copy(); -- } - - // beginning comment - writePSFmt("%%BeginResource: font {0:t}\n", psName); -@@ -2161,8 +2212,7 @@ - embFontList->append("\n"); - - // convert it to a Type 42 font -- fontBuf = font->readExtFontFile(&fontLen); -- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { -+ if ((ffTT = FoFiTrueType::load(fileName->getCString()))) { - codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); - ffTT->convertToType42(psName->getCString(), - ((Gfx8BitFont *)font)->getHasEncoding() -@@ -2182,7 +2232,6 @@ - } - delete ffTT; - } -- gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); -@@ -2196,18 +2245,22 @@ - int i; - - // check if font is already embedded -- for (i = 0; i < fontFileIDLen; ++i) { -- if (fontFileIDs[i].num == id->num && -- fontFileIDs[i].gen == id->gen) -+ for (i = 0; i < t1FontNameLen; ++i) { -+ if (t1FontNames[i].fontFileID.num == id->num && -+ t1FontNames[i].fontFileID.gen == id->gen) { -+ psName->clear(); -+ psName->insert(0, t1FontNames[i].psName); - return; -+ } - } -- -- // add entry to fontFileIDs list -- if (fontFileIDLen >= fontFileIDSize) { -- fontFileIDSize += 64; -- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); -- } -- fontFileIDs[fontFileIDLen++] = *id; -+ if (t1FontNameLen == t1FontNameSize) { -+ t1FontNameSize *= 2; -+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, -+ sizeof(PST1FontName)); -+ } -+ t1FontNames[t1FontNameLen].fontFileID = *id; -+ t1FontNames[t1FontNameLen].psName = psName->copy(); -+ ++t1FontNameLen; - - // beginning comment - writePSFmt("%%BeginResource: font {0:t}\n", psName); -@@ -2216,18 +2269,21 @@ - embFontList->append("\n"); - - // convert it to a Type 0 font -- fontBuf = font->readEmbFontFile(xref, &fontLen); -- if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { -- if (globalParams->getPSLevel() >= psLevel3) { -- // Level 3: use a CID font -- ffT1C->convertToCIDType0(psName->getCString(), 0, NULL, -- outputFunc, outputStream); -- } else { -- // otherwise: use a non-CID composite font -- ffT1C->convertToType0(psName->getCString(), 0, NULL, -- outputFunc, outputStream); -+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { -+ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { -+ if (globalParams->getPSLevel() >= psLevel3) { -+ // Level 3: use a CID font -+ ffT1C->convertToCIDType0(psName->getCString(), NULL, 0, -+ outputFunc, outputStream); -+ } else { -+ // otherwise: use a non-CID composite font -+ ffT1C->convertToType0(psName->getCString(), NULL, 0, -+ outputFunc, outputStream); -+ } -+ delete ffT1C; - } -- delete ffT1C; -+ gfree(fontBuf); - } -- gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); -@@ -2239,23 +2295,50 @@ - char *fontBuf; - int fontLen; - FoFiTrueType *ffTT; -- int i; - -- // check if font is already embedded -- for (i = 0; i < fontFileIDLen; ++i) { -- if (fontFileIDs[i].num == id->num && -- fontFileIDs[i].gen == id->gen) { -- psName->appendf("_{0:d}", nextTrueTypeNum++); -- break; -+ // beginning comment -+ writePSFmt("%%BeginResource: font {0:t}\n", psName); -+ embFontList->append("%%+ font "); -+ embFontList->append(psName->getCString()); -+ embFontList->append("\n"); -+ -+ // convert it to a Type 0 font -+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { -+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { -+ if (globalParams->getPSLevel() >= psLevel3) { -+ // Level 3: use a CID font -+ ffTT->convertToCIDType2(psName->getCString(), -+ ((GfxCIDFont *)font)->getCIDToGID(), -+ ((GfxCIDFont *)font)->getCIDToGIDLen(), -+ needVerticalMetrics, -+ outputFunc, outputStream); -+ } else { -+ // otherwise: use a non-CID composite font -+ ffTT->convertToType0(psName->getCString(), -+ ((GfxCIDFont *)font)->getCIDToGID(), -+ ((GfxCIDFont *)font)->getCIDToGIDLen(), -+ needVerticalMetrics, -+ outputFunc, outputStream); -+ } -+ delete ffTT; - } -+ gfree(fontBuf); - } - -- // add entry to fontFileIDs list -- if (fontFileIDLen >= fontFileIDSize) { -- fontFileIDSize += 64; -- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); -- } -- fontFileIDs[fontFileIDLen++] = *id; -+ // ending comment -+ writePS("%%EndResource\n"); -+} -+ -+void PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, -+ GString *fileName, -+ GString *psName, -+ GBool needVerticalMetrics) { -+ FoFiTrueType *ffTT; -+ int *codeToGID; -+ int codeToGIDLen; -+ CharCodeToUnicode *ctu; -+ Unicode uBuf[8]; -+ int cmap, code; - - // beginning comment - writePSFmt("%%BeginResource: font {0:t}\n", psName); -@@ -2264,26 +2347,62 @@ - embFontList->append("\n"); - - // convert it to a Type 0 font -- fontBuf = font->readEmbFontFile(xref, &fontLen); -- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { -- if (globalParams->getPSLevel() >= psLevel3) { -- // Level 3: use a CID font -- ffTT->convertToCIDType2(psName->getCString(), -- ((GfxCIDFont *)font)->getCIDToGID(), -- ((GfxCIDFont *)font)->getCIDToGIDLen(), -- needVerticalMetrics, -- outputFunc, outputStream); -+ //~ this should use fontNum to load the correct font -+ if ((ffTT = FoFiTrueType::load(fileName->getCString()))) { -+ -+ // check for embedding permission -+ if (ffTT->getEmbeddingRights() >= 1) { -+ -+ // create a CID-to-GID mapping, via Unicode -+ if ((ctu = ((GfxCIDFont *)font)->getToUnicode())) { -+ // look for a Unicode cmap -+ for (cmap = 0; cmap < ffTT->getNumCmaps(); ++cmap) { -+ if ((ffTT->getCmapPlatform(cmap) == 3 && -+ ffTT->getCmapEncoding(cmap) == 1) || -+ ffTT->getCmapPlatform(cmap) == 0) { -+ break; -+ } -+ } -+ if (cmap < ffTT->getNumCmaps()) { -+ // map CID -> Unicode -> GID -+ codeToGIDLen = ctu->getLength(); -+ codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int)); -+ for (code = 0; code < codeToGIDLen; ++code) { -+ if (ctu->mapToUnicode(code, uBuf, 8) > 0) { -+ codeToGID[code] = ffTT->mapCodeToGID(cmap, uBuf[0]); -+ } else { -+ codeToGID[code] = 0; -+ } -+ } -+ if (globalParams->getPSLevel() >= psLevel3) { -+ // Level 3: use a CID font -+ ffTT->convertToCIDType2(psName->getCString(), -+ codeToGID, codeToGIDLen, -+ needVerticalMetrics, -+ outputFunc, outputStream); -+ } else { -+ // otherwise: use a non-CID composite font -+ ffTT->convertToType0(psName->getCString(), -+ codeToGID, codeToGIDLen, -+ needVerticalMetrics, -+ outputFunc, outputStream); -+ } -+ gfree(codeToGID); -+ } -+ ctu->decRefCnt(); -+ } else { -+ error(errSyntaxError, -1, -+ "Couldn't find a mapping to Unicode for font '{0:s}'", -+ font->getName() ? font->getName()->getCString() : "(unnamed)"); -+ } - } else { -- // otherwise: use a non-CID composite font -- ffTT->convertToType0(psName->getCString(), -- ((GfxCIDFont *)font)->getCIDToGID(), -- ((GfxCIDFont *)font)->getCIDToGIDLen(), -- needVerticalMetrics, -- outputFunc, outputStream); -+ error(errSyntaxError, -1, -+ "TrueType font '%s' does not allow embedding", -+ font->getName() ? font->getName()->getCString() : "(unnamed)"); -+ - } - delete ffTT; - } -- gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); -@@ -2297,18 +2416,22 @@ - int i; - - // check if font is already embedded -- for (i = 0; i < fontFileIDLen; ++i) { -- if (fontFileIDs[i].num == id->num && -- fontFileIDs[i].gen == id->gen) -+ for (i = 0; i < t1FontNameLen; ++i) { -+ if (t1FontNames[i].fontFileID.num == id->num && -+ t1FontNames[i].fontFileID.gen == id->gen) { -+ psName->clear(); -+ psName->insert(0, t1FontNames[i].psName); - return; -+ } - } -- -- // add entry to fontFileIDs list -- if (fontFileIDLen >= fontFileIDSize) { -- fontFileIDSize += 64; -- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); -- } -- fontFileIDs[fontFileIDLen++] = *id; -+ if (t1FontNameLen == t1FontNameSize) { -+ t1FontNameSize *= 2; -+ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, -+ sizeof(PST1FontName)); -+ } -+ t1FontNames[t1FontNameLen].fontFileID = *id; -+ t1FontNames[t1FontNameLen].psName = psName->copy(); -+ ++t1FontNameLen; - - // beginning comment - writePSFmt("%%BeginResource: font {0:t}\n", psName); -@@ -2317,21 +2440,27 @@ - embFontList->append("\n"); - - // convert it to a Type 0 font -- fontBuf = font->readEmbFontFile(xref, &fontLen); -- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { -- if (ffTT->isOpenTypeCFF()) { -- if (globalParams->getPSLevel() >= psLevel3) { -- // Level 3: use a CID font -- ffTT->convertToCIDType0(psName->getCString(), -- ((GfxCIDFont *)font)->getCIDToGID(), -- ((GfxCIDFont *)font)->getCIDToGIDLen(), -- outputFunc, outputStream); -- } else { -- // otherwise: use a non-CID composite font -- ffTT->convertToType0(psName->getCString(), -- ((GfxCIDFont *)font)->getCIDToGID(), -- ((GfxCIDFont *)font)->getCIDToGIDLen(), -- outputFunc, outputStream); -+ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { -+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { -+ if (ffTT->isOpenTypeCFF()) { -+ if (globalParams->getPSLevel() >= psLevel3) { -+ // Level 3: use a CID font -+ ffTT->convertToCIDType0(psName->getCString(), -+ ((GfxCIDFont *)font)->getCIDToGID(), -+ ((GfxCIDFont *)font)->getCIDToGIDLen(), -+ outputFunc, outputStream); -+ } else { -+ // otherwise: use a non-CID composite font -+ ffTT->convertToType0(psName->getCString(), -+ ((GfxCIDFont *)font)->getCIDToGID(), -+ ((GfxCIDFont *)font)->getCIDToGIDLen(), -+ outputFunc, outputStream); -+ } - } -+ delete ffTT; - } -- delete ffTT; -+ gfree(fontBuf); - } -- gfree(fontBuf); - - // ending comment - writePS("%%EndResource\n"); -@@ -2390,9 +2519,10 @@ - box.y1 = m[1]; - box.x2 = m[2]; - box.y2 = m[3]; - gfx = new Gfx(doc, this, resDict, &box, NULL); - inType3Char = gTrue; - for (i = 0; i < charProcs->getLength(); ++i) { -+ t3FillColorOnly = gFalse; - t3Cacheable = gFalse; - t3NeedsRestore = gFalse; - writePS("/"); -@@ -2430,9 +2560,45 @@ - writePS("%%EndResource\n"); - } - -+// Make a unique PS font name, based on the names given in the PDF -+// font object, and an object ID (font file object for -+GString *PSOutputDev::makePSFontName(GfxFont *font, Ref *id) { -+ GString *psName, *s; -+ -+ if ((s = font->getEmbeddedFontName())) { -+ psName = filterPSName(s); -+ if (!fontNames->lookupInt(psName)) { -+ fontNames->add(psName->copy(), 1); -+ return psName; -+ } -+ delete psName; -+ } -+ if ((s = font->getName())) { -+ psName = filterPSName(s); -+ if (!fontNames->lookupInt(psName)) { -+ fontNames->add(psName->copy(), 1); -+ return psName; -+ } -+ delete psName; -+ } -+ psName = GString::format("FF{0:d}_{1:d}", id->num, id->gen); -+ if ((s = font->getEmbeddedFontName())) { -+ s = filterPSName(s); -+ psName->append('_')->append(s); -+ delete s; -+ } else if ((s = font->getName())) { -+ s = filterPSName(s); -+ psName->append('_')->append(s); -+ delete s; -+ } -+ fontNames->add(psName->copy(), 1); -+ return psName; -+} -+ - void PSOutputDev::setupImages(Dict *resDict) { -- Object xObjDict, xObj, xObjRef, subtypeObj; -- int i; -+ Object xObjDict, xObj, xObjRef, subtypeObj, maskObj, maskRef; -+ Ref imgID; -+ int i, j; - - if (!(mode == psModeForm || inType3Char || preload)) { - return; -@@ -2447,9 +2613,32 @@ - xObj.streamGetDict()->lookup("Subtype", &subtypeObj); - if (subtypeObj.isName("Image")) { - if (xObjRef.isRef()) { -- setupImage(xObjRef.getRef(), xObj.getStream()); -+ imgID = xObjRef.getRef(); -+ for (j = 0; j < imgIDLen; ++j) { -+ if (imgIDs[j].num == imgID.num && imgIDs[j].gen == imgID.gen) { -+ break; -+ } -+ } -+ if (j == imgIDLen) { -+ if (imgIDLen >= imgIDSize) { -+ if (imgIDSize == 0) { -+ imgIDSize = 64; -+ } else { -+ imgIDSize *= 2; -+ } -+ imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref)); -+ } -+ imgIDs[imgIDLen++] = imgID; -+ setupImage(imgID, xObj.getStream(), gFalse); -+ if (level >= psLevel3 && -+ xObj.streamGetDict()->lookup("Mask", &maskObj)->isStream()) { -+ setupImage(imgID, maskObj.getStream(), gTrue); -+ } -+ maskObj.free(); -+ } - } else { - error(errSyntaxError, -1, - "Image in resource dict is not an indirect reference"); - } - } - subtypeObj.free(); -@@ -2461,30 +2650,12 @@ - xObjDict.free(); - } - --void PSOutputDev::setupImage(Ref id, Stream *str) { -+void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) { - GBool useRLE, useCompressed, useASCIIHex; - GString *s; - int c; - int size, line, col, i; - -- // check if image is already setup -- for (i = 0; i < imgIDLen; ++i) { -- if (imgIDs[i].num == id.num && imgIDs[i].gen == id.gen) { -- return; -- } -- } -- -- // add entry to imgIDs list -- if (imgIDLen >= imgIDSize) { -- if (imgIDSize == 0) { -- imgIDSize = 64; -- } else { -- imgIDSize *= 2; -- } -- imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref)); -- } -- imgIDs[imgIDLen++] = id; -- - // filters - //~ this does not correctly handle the DeviceN color space - //~ -- need to use DeviceNRecoder -@@ -2493,17 +2664,21 @@ - useCompressed = gFalse; - useASCIIHex = gTrue; - } else { -- s = str->getPSFilter(level < psLevel3 ? 2 : 3, ""); -- if (s) { -+ if (globalParams->getPSUncompressPreloadedImages()) { - useRLE = gFalse; -- useCompressed = gTrue; -- delete s; -- } else { -- useRLE = gTrue; - useCompressed = gFalse; -+ } else { -+ s = str->getPSFilter(level < psLevel3 ? 2 : 3, ""); -+ if (s) { -+ useRLE = gFalse; -+ useCompressed = gTrue; -+ delete s; -+ } else { -+ useRLE = gTrue; -+ useCompressed = gFalse; -+ } - } -- useASCIIHex = level == psLevel1 || level == psLevel1Sep || -- globalParams->getPSASCIIHex(); -+ useASCIIHex = globalParams->getPSASCIIHex(); - } - if (useCompressed) { - str = str->getUndecodedStream(); -@@ -2552,8 +2727,8 @@ - if (useRLE) { - ++size; - } -- writePSFmt("{0:d} array dup /ImData_{1:d}_{2:d} exch def\n", -- size, id.num, id.gen); -+ writePSFmt("{0:d} array dup /{1:s}Data_{2:d}_{3:d} exch def\n", -+ size, mask ? "Mask" : "Im", id.num, id.gen); - str->close(); - - // write the data into the array -@@ -2722,12 +2898,14 @@ - int rotateA, GBool useMediaBox, GBool crop, - int sliceX, int sliceY, - int sliceW, int sliceH, - GBool printing, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { --#if HAVE_SPLASH - PreScanOutputDev *scan; - GBool rasterize; -+#if HAVE_SPLASH -+ GBool mono; -+ double dpi; - SplashOutputDev *splashOut; - SplashColor paperColor; - PDFRectangle box; -@@ -2737,43 +2915,33 @@ - Object obj; - Guchar *p; - Guchar col[4]; -+ double hDPI2, vDPI2; - double m0, m1, m2, m3, m4, m5; -+ int nStripes, stripeH, stripeY; - int c, w, h, x, y, comp, i; -+#endif - -- scan = new PreScanOutputDev(); -- page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop, -- sliceX, sliceY, sliceW, sliceH, -- printing, catalog, abortCheckCbk, abortCheckCbkData); -- rasterize = scan->usesTransparency(); -- delete scan; -+ if (globalParams->getPSAlwaysRasterize()) { -+ rasterize = gTrue; -+ } else { -+ scan = new PreScanOutputDev(); -+ page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop, -+ sliceX, sliceY, sliceW, sliceH, -+ printing, abortCheckCbk, abortCheckCbkData); -+ rasterize = scan->usesTransparency() || scan->usesPatternImageMask(); -+ delete scan; -+ } - if (!rasterize) { - return gTrue; - } - -- // rasterize the page -- if (level == psLevel1) { -- paperColor[0] = 0xff; -- splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse, -- paperColor, gTrue, gFalse); --#if SPLASH_CMYK -- } else if (level == psLevel1Sep) { -- paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0; -- splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse, -- paperColor, gTrue, gFalse); --#endif -- } else { -- paperColor[0] = paperColor[1] = paperColor[2] = 0xff; -- splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse, -- paperColor, gTrue, gFalse); -- } -- splashOut->startDoc(xref); -- page->displaySlice(splashOut, splashDPI, splashDPI, rotateA, -- useMediaBox, crop, -- sliceX, sliceY, sliceW, sliceH, -- printing, catalog, abortCheckCbk, abortCheckCbkData); -+#if HAVE_SPLASH -+ // get the rasterization parameters -+ dpi = globalParams->getPSRasterResolution(); -+ mono = globalParams->getPSRasterMono(); - - // start the PS page -- page->makeBox(splashDPI, splashDPI, rotateA, useMediaBox, gFalse, -+ page->makeBox(dpi, dpi, rotateA, useMediaBox, gFalse, - sliceX, sliceY, sliceW, sliceH, &box, &crop); - rotateA += page->getRotate(); - if (rotateA >= 360) { -@@ -2781,166 +2949,215 @@ - } else if (rotateA < 0) { - rotateA += 360; - } -- state = new GfxState(splashDPI, splashDPI, &box, rotateA, gFalse); -- startPage(page->getNum(), state); -- delete state; -- switch (rotateA) { -- case 0: -- default: // this should never happen -+ state = new GfxState(dpi, dpi, &box, rotateA, gFalse); -+ startPage(page->getNum(), state); -+ delete state; -+ -+ // set up the SplashOutputDev -+ if (mono || level == psLevel1) { -+ paperColor[0] = 0xff; -+ splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse, -+ paperColor, gFalse, -+ globalParams->getAntialiasPrinting()); -+#if SPLASH_CMYK -+ } else if (level == psLevel1Sep) { -+ paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0; -+ splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse, -+ paperColor, gFalse, -+ globalParams->getAntialiasPrinting()); -+#endif -+ } else { -+ paperColor[0] = paperColor[1] = paperColor[2] = 0xff; -+ splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse, -+ paperColor, gFalse, -+ globalParams->getAntialiasPrinting()); -+ } -+ splashOut->startDoc(xref); -+ -+ // break the page into stripes -+ hDPI2 = xScale * dpi; -+ vDPI2 = yScale * dpi; -+ if (sliceW < 0 || sliceH < 0) { -+ if (useMediaBox) { -+ box = *page->getMediaBox(); -+ } else { -+ box = *page->getCropBox(); -+ } -+ sliceX = sliceY = 0; -+ sliceW = (int)((box.x2 - box.x1) * hDPI2 / 72.0); -+ sliceH = (int)((box.y2 - box.y1) * vDPI2 / 72.0); -+ } -+ nStripes = (int)ceil((double)(sliceW * sliceH) / -+ (double)rasterizationSliceSize); -+ stripeH = (sliceH + nStripes - 1) / nStripes; -+ -+ // render the stripes -+ for (stripeY = sliceY; stripeY < sliceH; stripeY += stripeH) { -+ -+ // rasterize a stripe -+ page->makeBox(hDPI2, vDPI2, 0, useMediaBox, gFalse, -+ sliceX, stripeY, sliceW, stripeH, &box, &crop); - m0 = box.x2 - box.x1; - m1 = 0; - m2 = 0; - m3 = box.y2 - box.y1; - m4 = box.x1; - m5 = box.y1; -- break; -- case 90: -- m0 = 0; -- m1 = box.y2 - box.y1; -- m2 = -(box.x2 - box.x1); -- m3 = 0; -- m4 = box.x2; -- m5 = box.y1; -- break; -- case 180: -- m0 = -(box.x2 - box.x1); -- m1 = 0; -- m2 = 0; -- m3 = -(box.y2 - box.y1); -- m4 = box.x2; -- m5 = box.y2; -- break; -- case 270: -- m0 = 0; -- m1 = -(box.y2 - box.y1); -- m2 = box.x2 - box.x1; -- m3 = 0; -- m4 = box.x1; -- m5 = box.y2; -- break; -- } -- -- //~ need to add the process colors -- -- // draw the rasterized image -- bitmap = splashOut->getBitmap(); -- w = bitmap->getWidth(); -- h = bitmap->getHeight(); -- writePS("gsave\n"); -- writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] concat\n", -- m0, m1, m2, m3, m4, m5); -- switch (level) { -- case psLevel1: -- writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n", -- w, h, w, -h, h); -- p = bitmap->getDataPtr(); -- i = 0; -- for (y = 0; y < h; ++y) { -- for (x = 0; x < w; ++x) { -- writePSFmt("{0:02x}", *p++); -- if (++i == 32) { -- writePSChar('\n'); -- i = 0; -- } -- } -- } -- if (i != 0) { -- writePSChar('\n'); -- } -- break; -- case psLevel1Sep: -- writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n", -- w, h, w, -h, h); -- p = bitmap->getDataPtr(); -- i = 0; -- col[0] = col[1] = col[2] = col[3] = 0; -- for (y = 0; y < h; ++y) { -- for (comp = 0; comp < 4; ++comp) { -+ page->displaySlice(splashOut, hDPI2, vDPI2, -+ (360 - page->getRotate()) % 360, useMediaBox, crop, -+ sliceX, stripeY, sliceW, stripeH, -+ printing, abortCheckCbk, abortCheckCbkData); -+ -+ // draw the rasterized image -+ bitmap = splashOut->getBitmap(); -+ w = bitmap->getWidth(); -+ h = bitmap->getHeight(); -+ writePS("gsave\n"); -+ writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n", -+ m0, m1, m2, m3, m4, m5); -+ switch (level) { -+ case psLevel1: -+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n", -+ w, h, w, -h, h); -+ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize(); -+ i = 0; -+ for (y = 0; y < h; ++y) { - for (x = 0; x < w; ++x) { -- writePSFmt("{0:02x}", p[4*x + comp]); -- col[comp] |= p[4*x + comp]; -+ writePSFmt("{0:02x}", *p++); - if (++i == 32) { - writePSChar('\n'); - i = 0; - } - } - } -- p += bitmap->getRowSize(); -- } -- if (i != 0) { -+ if (i != 0) { -+ writePSChar('\n'); -+ } -+ break; -+ case psLevel1Sep: -+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n", -+ w, h, w, -h, h); -+ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize(); -+ i = 0; -+ col[0] = col[1] = col[2] = col[3] = 0; -+ for (y = 0; y < h; ++y) { -+ for (comp = 0; comp < 4; ++comp) { -+ for (x = 0; x < w; ++x) { -+ writePSFmt("{0:02x}", p[4*x + comp]); -+ col[comp] |= p[4*x + comp]; -+ if (++i == 32) { -+ writePSChar('\n'); -+ i = 0; -+ } -+ } -+ } -+ p -= bitmap->getRowSize(); -+ } -+ if (i != 0) { -+ writePSChar('\n'); -+ } -+ if (col[0]) { -+ processColors |= psProcessCyan; -+ } -+ if (col[1]) { -+ processColors |= psProcessMagenta; -+ } -+ if (col[2]) { -+ processColors |= psProcessYellow; -+ } -+ if (col[3]) { -+ processColors |= psProcessBlack; -+ } -+ break; -+ case psLevel2: -+ case psLevel2Sep: -+ case psLevel3: -+ case psLevel3Sep: -+ if (mono) { -+ writePS("/DeviceGray setcolorspace\n"); -+ } else { -+ writePS("/DeviceRGB setcolorspace\n"); -+ } -+ writePS("<<\n /ImageType 1\n"); -+ writePSFmt(" /Width {0:d}\n", bitmap->getWidth()); -+ writePSFmt(" /Height {0:d}\n", bitmap->getHeight()); -+ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h); -+ writePS(" /BitsPerComponent 8\n"); -+ if (mono) { -+ writePS(" /Decode [0 1]\n"); -+ } else { -+ writePS(" /Decode [0 1 0 1 0 1]\n"); -+ } -+ writePS(" /DataSource currentfile\n"); -+ if (globalParams->getPSASCIIHex()) { -+ writePS(" /ASCIIHexDecode filter\n"); -+ } else { -+ writePS(" /ASCII85Decode filter\n"); -+ } -+ writePS(" /RunLengthDecode filter\n"); -+ writePS(">>\n"); -+ writePS("image\n"); -+ obj.initNull(); -+ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize(); -+ str0 = new MemStream((char *)p, 0, w * h * (mono ? 1 : 3), &obj); -+ str = new RunLengthEncoder(str0); -+ if (globalParams->getPSASCIIHex()) { -+ str = new ASCIIHexEncoder(str); -+ } else { -+ str = new ASCII85Encoder(str); -+ } -+ str->reset(); -+ while ((c = str->getChar()) != EOF) { -+ writePSChar(c); -+ } -+ str->close(); -+ delete str; -+ delete str0; - writePSChar('\n'); -+ processColors |= mono ? psProcessBlack : psProcessCMYK; -+ break; - } -- if (col[0]) { -- processColors |= psProcessCyan; -- } -- if (col[1]) { -- processColors |= psProcessMagenta; -- } -- if (col[2]) { -- processColors |= psProcessYellow; -- } -- if (col[3]) { -- processColors |= psProcessBlack; -- } -- break; -- case psLevel2: -- case psLevel2Sep: -- case psLevel3: -- case psLevel3Sep: -- writePS("/DeviceRGB setcolorspace\n"); -- writePS("<<\n /ImageType 1\n"); -- writePSFmt(" /Width {0:d}\n", bitmap->getWidth()); -- writePSFmt(" /Height {0:d}\n", bitmap->getHeight()); -- writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h); -- writePS(" /BitsPerComponent 8\n"); -- writePS(" /Decode [0 1 0 1 0 1]\n"); -- writePS(" /DataSource currentfile\n"); -- if (globalParams->getPSASCIIHex()) { -- writePS(" /ASCIIHexDecode filter\n"); -- } else { -- writePS(" /ASCII85Decode filter\n"); -- } -- writePS(" /RunLengthDecode filter\n"); -- writePS(">>\n"); -- writePS("image\n"); -- obj.initNull(); -- str0 = new MemStream((char *)bitmap->getDataPtr(), 0, w * h * 3, &obj); -- str = new RunLengthEncoder(str0); -- if (globalParams->getPSASCIIHex()) { -- str = new ASCIIHexEncoder(str); -- } else { -- str = new ASCII85Encoder(str); -- } -- str->reset(); -- while ((c = str->getChar()) != EOF) { -- writePSChar(c); -- } -- str->close(); -- delete str; -- delete str0; -- processColors |= psProcessCMYK; -- break; -+ writePS("grestore\n"); - } ++ " } {", ++ " ()", ++ " } ifelse", ++ "} def", + "/pdfImM1a {", +- " { 2 copy get exch 1 add exch } imagemask", ++ " { pdfImStr } imagemask", + " pop pop", + "} def", + "~23sn", +- "% Level 2 image operators", ++ "% Level 2/3 image operators", + "/pdfImBuf 100 string def", +- "/pdfIm {", +- " image", ++ "/pdfImStr {", ++ " 2 copy exch length lt {", ++ " 2 copy get exch 1 add exch", ++ " } {", ++ " ()", ++ " } ifelse", ++ "} def", ++ "/skipEOD {", + " { currentfile pdfImBuf readline", + " not { pop exit } if", + " (%-EOD-) eq { exit } if } loop", + "} def", ++ "/pdfIm { image skipEOD } def", ++ "~3sn", ++ "/pdfMask {", ++ " /ReusableStreamDecode filter", ++ " skipEOD", ++ " /maskStream exch def", ++ "} def", ++ "/pdfMaskEnd { maskStream closefile } def", ++ "/pdfMaskInit {", ++ " /maskArray exch def", ++ " /maskIdx 0 def", ++ "} def", ++ "/pdfMaskSrc {", ++ " maskIdx maskArray length lt {", ++ " maskArray maskIdx get", ++ " /maskIdx maskIdx 1 add def", ++ " } {", ++ " ()", ++ " } ifelse", ++ "} def", + "~23s", + "/pdfImSep {", + " findcmykcustomcolor exch", +@@ -523,17 +567,10 @@ + " 255 exch sub put", + " } for }", + " 6 5 roll customcolorimage", +- " { currentfile pdfImBuf readline", +- " not { pop exit } if", +- " (%-EOD-) eq { exit } if } loop", ++ " skipEOD", + "} def", + "~23sn", +- "/pdfImM {", +- " fCol imagemask", +- " { currentfile pdfImBuf readline", +- " not { pop exit } if", +- " (%-EOD-) eq { exit } if } loop", +- "} def", ++ "/pdfImM { fCol imagemask skipEOD } def", + "/pr { 2 index 2 index 3 2 roll putinterval 4 add } def", + "/pdfImClip {", + " gsave", +@@ -607,7 +644,7 @@ + " func n array astore", + "} def", + "/axialSH {", +- " dup 0 eq {", ++ " dup 2 lt {", + " true", + " } {", + " dup 8 eq {", +@@ -753,25 +790,12 @@ + double mWidth; // width of 'm' character + }; + +-static char *psFonts[] = { +- "Courier", +- "Courier-Bold", +- "Courier-Oblique", +- "Courier-BoldOblique", +- "Helvetica", +- "Helvetica-Bold", +- "Helvetica-Oblique", +- "Helvetica-BoldOblique", +- "Symbol", +- "Times-Roman", +- "Times-Bold", +- "Times-Italic", +- "Times-BoldItalic", +- "ZapfDingbats", +- NULL +-}; +- +-static PSSubstFont psSubstFonts[] = { ++// NB: must be in same order as base14SubstFonts in GfxFont.cc ++static PSSubstFont psBase14SubstFonts[14] = { ++ {"Courier", 0.600}, ++ {"Courier-Oblique", 0.600}, ++ {"Courier-Bold", 0.600}, ++ {"Courier-BoldOblique", 0.600}, + {"Helvetica", 0.833}, + {"Helvetica-Oblique", 0.833}, + {"Helvetica-Bold", 0.889}, +@@ -780,22 +804,28 @@ + {"Times-Italic", 0.722}, + {"Times-Bold", 0.833}, + {"Times-BoldItalic", 0.778}, +- {"Courier", 0.600}, +- {"Courier-Oblique", 0.600}, +- {"Courier-Bold", 0.600}, +- {"Courier-BoldOblique", 0.600} ++ // the last two are never used for substitution ++ {"Symbol", 0}, ++ {"ZapfDingbats", 0} ++}; + - delete splashOut; -- writePS("grestore\n"); ++// Mapping from Type 1/1C font file to PS font name. ++struct PST1FontName { ++ Ref fontFileID; ++ GString *psName; // PostScript font name used for this ++ // embedded font file + }; - // finish the PS page - endPage(); + // Encoding info for substitute 16-bit font + struct PSFont16Enc { + Ref fontID; +- GString *enc; ++ GString *enc; // NULL means font wasn't correctly substituted + }; - return gFalse; --#else + //------------------------------------------------------------------------ +@@ -845,6 +875,13 @@ + }; + + //------------------------------------------------------------------------ + -+#else // HAVE_SPLASH ++struct PSOutPaperSize { ++ PSOutPaperSize(int wA, int hA) { w = wA; h = hA; } ++ int w, h; ++}; + -+ error(errSyntaxWarning, -1, -+ "PDF page uses transparency and PSOutputDev was built without" -+ " the Splash rasterizer - output may not be correct"); - return gTrue; --#endif -+#endif // HAVE_SPLASH ++//------------------------------------------------------------------------ + // DeviceNRecoder + //------------------------------------------------------------------------ + +@@ -897,6 +934,9 @@ + if (imgStr) { + delete imgStr; + } ++ if (str->isEncoder()) { ++ delete str; ++ } + } + + void DeviceNRecoder::reset() { +@@ -942,10 +982,12 @@ + fwrite(data, 1, len, (FILE *)stream); + } + + PSOutputDev::PSOutputDev(char *fileName, PDFDoc *docA, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, +- GBool manualCtrlA) { ++ GBool manualCtrlA, ++ PSOutCustomCodeCbk customCodeCbkA, ++ void *customCodeCbkDataA) { + FILE *f; + PSFileType fileTypeA; + +@@ -953,15 +995,18 @@ + underlayCbkData = NULL; + overlayCbk = NULL; + overlayCbkData = NULL; ++ customCodeCbk = customCodeCbkA; ++ customCodeCbkData = customCodeCbkDataA; + + fontIDs = NULL; +- fontFileIDs = NULL; +- fontFileNames = NULL; ++ fontNames = new GHash(gTrue); ++ t1FontNames = NULL; + font8Info = NULL; + font16Enc = NULL; + imgIDs = NULL; + formIDs = NULL; + xobjStack = NULL; ++ paperSizes = NULL; + embFontList = NULL; + customColors = NULL; + haveTextClip = gFalse; +@@ -978,71 +1023,82 @@ + signal(SIGPIPE, (SignalFunc)SIG_IGN); + #endif + if (!(f = popen(fileName + 1, "w"))) { + error(errIO, -1, "Couldn't run print command '{0:s}'", fileName); + ok = gFalse; + return; + } + #else + error(errIO, -1, "Print commands are not supported ('{0:s}')", fileName); + ok = gFalse; + return; + #endif + } else { + fileTypeA = psFile; + if (!(f = fopen(fileName, "w"))) { + error(errIO, -1, "Couldn't open PostScript file '{0:s}'", fileName); + ok = gFalse; + return; + } + } + + init(outputToFile, f, fileTypeA, +- xrefA, catalog, firstPage, lastPage, modeA, ++ docA, firstPage, lastPage, modeA, + imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA); + } + + PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, + PDFDoc *docA, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, +- GBool manualCtrlA) { ++ GBool manualCtrlA, ++ PSOutCustomCodeCbk customCodeCbkA, ++ void *customCodeCbkDataA) { + underlayCbk = NULL; + underlayCbkData = NULL; + overlayCbk = NULL; + overlayCbkData = NULL; ++ customCodeCbk = customCodeCbkA; ++ customCodeCbkData = customCodeCbkDataA; + + fontIDs = NULL; +- fontFileIDs = NULL; +- fontFileNames = NULL; ++ fontNames = new GHash(gTrue); ++ t1FontNames = NULL; + font8Info = NULL; + font16Enc = NULL; + imgIDs = NULL; + formIDs = NULL; + xobjStack = NULL; ++ paperSizes = NULL; + embFontList = NULL; + customColors = NULL; + haveTextClip = gFalse; + t3String = NULL; + + init(outputFuncA, outputStreamA, psGeneric, + docA, firstPage, lastPage, modeA, + imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA); } - void PSOutputDev::startPage(int pageNum, GfxState *state) { -- int x1, y1, x2, y2, width, height; -+ Page *page; -+ int x1, y1, x2, y2, width, height, t; - int imgWidth, imgHeight, imgWidth2, imgHeight2; - GBool landscape; -- -+ GString *s; + void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, + PSFileType fileTypeA, PDFDoc *docA, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, + GBool manualCtrlA) { + Catalog *catalog; + Page *page; + PDFRectangle *box; ++ PSOutPaperSize *size; ++ GList *names; ++ int pg, w, h, i; - if (mode == psModePS) { - writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage); -+ if (paperMatch) { -+ page = doc->getCatalog()->getPage(pageNum); -+ imgLLX = imgLLY = 0; -+ imgURX = (int)ceil(page->getMediaWidth()); -+ imgURY = (int)ceil(page->getMediaHeight()); -+ if (state->getRotate() == 90 || state->getRotate() == 270) { -+ t = imgURX; -+ imgURX = imgURY; -+ imgURY = t; + // initialize + ok = gTrue; + outputFunc = outputFuncA; + outputStream = outputStreamA; + fileType = fileTypeA; + doc = docA; + xref = doc->getXRef(); + catalog = doc->getCatalog(); + level = globalParams->getPSLevel(); + mode = modeA; + paperWidth = globalParams->getPSPaperWidth(); +@@ -1055,18 +1111,34 @@ + globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY); + } + if (paperWidth < 0 || paperHeight < 0) { +- // this check is needed in case the document has zero pages +- if (firstPage > 0 && firstPage <= catalog->getNumPages()) { +- page = catalog->getPage(firstPage); +- paperWidth = (int)ceil(page->getMediaWidth()); +- paperHeight = (int)ceil(page->getMediaHeight()); +- } else { +- paperWidth = 1; +- paperHeight = 1; +- } +- imgLLX = imgLLY = 0; +- imgURX = paperWidth; +- imgURY = paperHeight; ++ paperMatch = gTrue; ++ paperSizes = new GList(); ++ paperWidth = paperHeight = 1; // in case the document has zero pages ++ for (pg = (firstPage >= 1) ? firstPage : 1; ++ pg <= lastPage && pg <= catalog->getNumPages(); ++ ++pg) { ++ page = catalog->getPage(pg); ++ w = (int)ceil(page->getMediaWidth()); ++ h = (int)ceil(page->getMediaHeight()); ++ for (i = 0; i < paperSizes->getLength(); ++i) { ++ size = (PSOutPaperSize *)paperSizes->get(i); ++ if (size->w == w && size->h == h) { ++ break; ++ } ++ } ++ if (i == paperSizes->getLength()) { ++ paperSizes->append(new PSOutPaperSize(w, h)); ++ } ++ if (w > paperWidth) { ++ paperWidth = w; ++ } ++ if (h > paperHeight) { ++ paperHeight = h; + } -+ writePSFmt("%%PageMedia: {0:d}x{1:d}\n", imgURX, imgURY); -+ writePSFmt("%%PageBoundingBox: 0 0 {0:d} {1:d}\n", imgURX, imgURY); + } - writePS("%%BeginPageSetup\n"); ++ // NB: img{LLX,LLY,URX,URY} will be set by startPage() ++ } else { ++ paperMatch = gFalse; } + preload = globalParams->getPSPreload(); + manualCtrl = manualCtrlA; +@@ -1088,17 +1160,21 @@ + clipLLX0 = clipLLY0 = 0; + clipURX0 = clipURY0 = -1; -@@ -2966,20 +3183,25 @@ - height = y2 - y1; - tx = ty = 0; - // rotation and portrait/landscape mode -- if (rotate0 >= 0) { -+ if (paperMatch) { -+ rotate = (360 - state->getRotate()) % 360; -+ landscape = gFalse; -+ } else if (rotate0 >= 0) { - rotate = (360 - rotate0) % 360; - landscape = gFalse; - } else { - rotate = (360 - state->getRotate()) % 360; - if (rotate == 0 || rotate == 180) { -- if (width > height && width > imgWidth) { -+ if ((width < height && imgWidth > imgHeight && height > imgHeight) || -+ (width > height && imgWidth < imgHeight && width > imgWidth)) { - rotate += 90; - landscape = gTrue; - } else { - landscape = gFalse; - } - } else { // rotate == 90 || rotate == 270 -- if (height > width && height > imgWidth) { -+ if ((height < width && imgWidth > imgHeight && width > imgHeight) || -+ (height > width && imgWidth < imgHeight && height > imgWidth)) { - rotate = 270 - rotate; - landscape = gTrue; - } else { -@@ -2989,6 +3211,9 @@ - } - writePSFmt("%%PageOrientation: {0:s}\n", - landscape ? "Landscape" : "Portrait"); -+ if (paperMatch) { -+ writePSFmt("{0:d} {1:d} pdfSetupPaper\n", imgURX, imgURY); -+ } - writePS("pdfStartPage\n"); - if (rotate == 0) { - imgWidth2 = imgWidth; -@@ -3015,9 +3240,9 @@ - xScale = xScale0; - yScale = yScale0; - } else if ((globalParams->getPSShrinkLarger() && -- (width > imgWidth2 || height > imgHeight2)) || -- (globalParams->getPSExpandSmaller() && -- (width < imgWidth2 && height < imgHeight2))) { -+ (width > imgWidth2 || height > imgHeight2)) || -+ (globalParams->getPSExpandSmaller() && -+ (width < imgWidth2 && height < imgHeight2))) { - xScale = (double)imgWidth2 / (double)width; - yScale = (double)imgHeight2 / (double)height; - if (yScale < xScale) { -@@ -3038,8 +3263,8 @@ - } - // center - if (tx0 >= 0 && ty0 >= 0) { -- tx += rotate == 0 ? tx0 : ty0; -- ty += rotate == 0 ? ty0 : -tx0; -+ tx += (rotate == 0 || rotate == 180) ? tx0 : ty0; -+ ty += (rotate == 0 || rotate == 180) ? ty0 : -tx0; - } else if (globalParams->getPSCenter()) { - if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { - tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2; -@@ -3049,22 +3274,21 @@ - ty += (imgHeight2 - yScale * height) / 2; - } - } -- tx += rotate == 0 ? imgLLX : imgLLY; -- ty += rotate == 0 ? imgLLY : -imgLLX; -+ tx += (rotate == 0 || rotate == 180) ? imgLLX : imgLLY; -+ ty += (rotate == 0 || rotate == 180) ? imgLLY : -imgLLX; - if (tx != 0 || ty != 0) { - writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty); +- // initialize fontIDs, fontFileIDs, and fontFileNames lists ++ // initialize fontIDs and fontNames lists + fontIDSize = 64; + fontIDLen = 0; + fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref)); +- fontFileIDSize = 64; +- fontFileIDLen = 0; +- fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref)); +- fontFileNameSize = 64; +- fontFileNameLen = 0; +- fontFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *)); +- nextTrueTypeNum = 0; ++ for (i = 0; i < 14; ++i) { ++ fontNames->add(new GString(psBase14SubstFonts[i].psName), 1); ++ } ++ names = globalParams->getPSResidentFonts(); ++ for (i = 0; i < names->getLength(); ++i) { ++ fontNames->add((GString *)names->get(i), 1); ++ } ++ delete names; ++ t1FontNameSize = 64; ++ t1FontNameLen = 0; ++ t1FontNames = (PST1FontName *)gmallocn(t1FontNameSize, sizeof(PST1FontName)); + font8InfoLen = 0; + font8InfoSize = 0; + font16EncLen = 0; +@@ -1173,20 +1249,21 @@ } - if (xScale != 1 || yScale != 1) { - writePSFmt("{0:.6f} {1:.6f} scale\n", xScale, yScale); + #endif + } ++ if (paperSizes) { ++ deleteGList(paperSizes, PSOutPaperSize); ++ } + if (embFontList) { + delete embFontList; + } + if (fontIDs) { + gfree(fontIDs); + } +- if (fontFileIDs) { +- gfree(fontFileIDs); +- } +- if (fontFileNames) { +- for (i = 0; i < fontFileNameLen; ++i) { +- delete fontFileNames[i]; ++ delete fontNames; ++ if (t1FontNames) { ++ for (i = 0; i < t1FontNameLen; ++i) { ++ delete t1FontNames[i].psName; } - if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { - writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re W\n", - clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0); - } else { - writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1); +- gfree(fontFileNames); ++ gfree(t1FontNames); + } + if (font8Info) { + for (i = 0; i < font8InfoLen; ++i) { +@@ -1196,7 +1273,9 @@ + } + if (font16Enc) { + for (i = 0; i < font16EncLen; ++i) { +- delete font16Enc[i].enc; ++ if (font16Enc[i].enc) { ++ delete font16Enc[i].enc; ++ } } + gfree(font16Enc); + } +@@ -1216,7 +1295,9 @@ + PDFRectangle *mediaBox, PDFRectangle *cropBox, + int pageRotate) { + Object info, obj1; ++ PSOutPaperSize *size; + double x1, y1, x2, y2; ++ int i; -- writePS("%%EndPageSetup\n"); - ++seqPage; - break; - -@@ -3101,6 +3325,18 @@ - rotate = 0; + switch (mode) { + case psModePS: +@@ -1230,7 +1311,7 @@ break; } -+ -+ if (customCodeCbk) { -+ if ((s = (*customCodeCbk)(this, psOutCustomPageSetup, pageNum, -+ customCodeCbkData))) { -+ writePS(s->getCString()); -+ delete s; -+ } -+ } -+ -+ if (mode == psModePS) { -+ writePS("%%EndPageSetup\n"); -+ } - } - - void PSOutputDev::endPage() { -@@ -3458,25 +3693,33 @@ -+void PSOutputDev::saveTextPos(GfxState *state) { -+ writePS("currentpoint\n"); -+} -+ -+void PSOutputDev::restoreTextPos(GfxState *state) { -+ writePS("m\n"); -+} -+ - void PSOutputDev::stroke(GfxState *state) { - doPath(state->getPath()); -- if (t3String) { -- // if we're construct a cacheable Type 3 glyph, we need to do -+ if (inType3Char && t3FillColorOnly) { -+ // if we're constructing a cacheable Type 3 glyph, we need to do - // everything in the fill color - writePS("Sf\n"); - } else { -@@ -3494,19 +3737,19 @@ - writePS("f*\n"); - } - -@@ -3526,34 +3769,37 @@ - box.y1 = bbox[1]; - box.x2 = bbox[2]; - box.y2 = bbox[3]; - gfx = new Gfx(doc, this, resDict, &box, NULL); - writePS("/x {\n"); - if (paintType == 2) { - writePSFmt("{0:.6g} 0 {1:.6g} {2:.6g} {3:.6g} {4:.6g} setcachedevice\n", - xStep, bbox[0], bbox[1], bbox[2], bbox[3]); -+ t3FillColorOnly = gTrue; - } else { - if (x1 - 1 <= x0) { - writePS("1 0 setcharwidth\n"); - } else { - writePSFmt("{0:.6g} 0 setcharwidth\n", xStep); - } -+ t3FillColorOnly = gFalse; - } - inType3Char = gTrue; - ++numTilingPatterns; -- gfx->display(str); -+ gfx2->display(str); - --numTilingPatterns; - inType3Char = gFalse; - writePS("} def\n"); -- delete gfx; -+ delete gfx2; - writePS("end\n"); - writePS("currentdict end\n"); - writePSFmt("/xpdfTile{0:d} exch definefont pop\n", numTilingPatterns); - // draw the tiles - writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns); -+ writePS("fCol\n"); - writePSFmt("gsave [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n", - mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); - writePSFmt("{0:d} 1 {1:d} {{ {2:.6g} exch {3:.6g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n", - y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1); - writePS("grestore\n"); - } -@@ -3698,7 +3944,10 @@ - double xMin, yMin, xMax, yMax; - double x0, y0, r0, x1, y1, r1, t0, t1; - double xa, ya, ra; -- double sz, xz, yz, sMin, sMax, sa, ta; -+ double sz, sMin, sMax, h, ta; -+ double sLeft, sRight, sTop, sBottom, sZero, sDiag; -+ GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero; -+ GBool haveSMin, haveSMax; - double theta, alpha, a1, a2; - GBool enclosed; - int i; -@@ -3717,19 +3966,23 @@ +- writePSFmt("% Produced by xpdf/pdftops {0:s}\n", xpdfVersion); ++ writePSFmt("%XpdfVersion: {0:s}\n", xpdfVersion); + xref->getDocInfo(&info); + if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) { + writePS("%%Creator: "); +@@ -1254,14 +1335,24 @@ - // Compute the point at which r(s) = 0; check for the enclosed - // circles case; and compute the angles for the tangent lines. -- if (r0 == r1) { -- enclosed = x0 == x1 && y0 == y1; -+ h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); -+ if (h == 0) { -+ enclosed = gTrue; -+ theta = 0; // make gcc happy -+ sz = 0; // make gcc happy -+ } else if (r1 - r0 == 0) { -+ enclosed = gFalse; - theta = 0; - sz = 0; // make gcc happy -+ } else if (fabs(r1 - r0) >= h) { -+ enclosed = gTrue; -+ theta = 0; // make gcc happy -+ sz = 0; // make gcc happy - } else { -+ enclosed = gFalse; - sz = -r0 / (r1 - r0); -- xz = x0 + sz * (x1 - x0); -- yz = y0 + sz * (y1 - y0); -- enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0; -- theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz))); -- if (r0 > r1) { -- theta = -theta; -- } -+ theta = asin((r1 - r0) / h); - } - if (enclosed) { - a1 = 0; -@@ -3749,80 +4002,122 @@ - sMin = 0; - sMax = 1; - } else { -- sMin = 1; -- sMax = 0; -- // solve for x(s) + r(s) = xMin -- if ((x1 + r1) - (x0 + r0) != 0) { -- sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0)); -- if (sa < sMin) { -- sMin = sa; -- } else if (sa > sMax) { -- sMax = sa; -- } -- } -- // solve for x(s) - r(s) = xMax -- if ((x1 - r1) - (x0 - r0) != 0) { -- sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0)); -- if (sa < sMin) { -- sMin = sa; -- } else if (sa > sMax) { -- sMax = sa; -- } -- } -- // solve for y(s) + r(s) = yMin -- if ((y1 + r1) - (y0 + r0) != 0) { -- sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0)); -- if (sa < sMin) { -- sMin = sa; -- } else if (sa > sMax) { -- sMax = sa; -- } -- } -- // solve for y(s) - r(s) = yMax -- if ((y1 - r1) - (y0 - r0) != 0) { -- sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0)); -- if (sa < sMin) { -- sMin = sa; -- } else if (sa > sMax) { -- sMax = sa; -- } -- } -- // check against sz -- if (r0 < r1) { -- if (sMin < sz) { -- sMin = sz; -- } -- } else if (r0 > r1) { -- if (sMax > sz) { -- sMax = sz; -- } -+ // solve x(sLeft) + r(sLeft) = xMin -+ if ((haveSLeft = fabs((x1 + r1) - (x0 + r0)) > 0.000001)) { -+ sLeft = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0)); -+ } else { -+ sLeft = 0; // make gcc happy -+ } -+ // solve x(sRight) - r(sRight) = xMax -+ if ((haveSRight = fabs((x1 - r1) - (x0 - r0)) > 0.000001)) { -+ sRight = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0)); -+ } else { -+ sRight = 0; // make gcc happy -+ } -+ // solve y(sBottom) + r(sBottom) = yMin -+ if ((haveSBottom = fabs((y1 + r1) - (y0 + r0)) > 0.000001)) { -+ sBottom = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0)); -+ } else { -+ sBottom = 0; // make gcc happy -+ } -+ // solve y(sTop) - r(sTop) = yMax -+ if ((haveSTop = fabs((y1 - r1) - (y0 - r0)) > 0.000001)) { -+ sTop = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0)); -+ } else { -+ sTop = 0; // make gcc happy -+ } -+ // solve r(sZero) = 0 -+ if ((haveSZero = fabs(r1 - r0) > 0.000001)) { -+ sZero = -r0 / (r1 - r0); + switch (mode) { + case psModePS: +- writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n", +- paperWidth, paperHeight); ++ if (paperMatch) { ++ for (i = 0; i < paperSizes->getLength(); ++i) { ++ size = (PSOutPaperSize *)paperSizes->get(i); ++ writePSFmt("%%{0:s} {1:d}x{2:d} {1:d} {2:d} 0 () ()\n", ++ i==0 ? "DocumentMedia:" : "+", size->w, size->h); ++ } + } else { -+ sZero = 0; // make gcc happy ++ writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n", ++ paperWidth, paperHeight); + } -+ // solve r(sDiag) = sqrt((xMax-xMin)^2 + (yMax-yMin)^2) -+ if (haveSZero) { -+ sDiag = (sqrt((xMax - xMin) * (xMax - xMin) + -+ (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0); -+ } else { -+ sDiag = 0; // make gcc happy - } -- // check the 'extend' flags -- if (!shading->getExtend0() && sMin < 0) { -+ // compute sMin -+ if (shading->getExtend0()) { -+ sMin = 0; -+ haveSMin = gFalse; -+ if (x0 < x1 && haveSLeft && sLeft < 0) { -+ sMin = sLeft; -+ haveSMin = gTrue; -+ } else if (x0 > x1 && haveSRight && sRight < 0) { -+ sMin = sRight; -+ haveSMin = gTrue; -+ } -+ if (y0 < y1 && haveSBottom && sBottom < 0) { -+ if (!haveSMin || sBottom > sMin) { -+ sMin = sBottom; -+ haveSMin = gTrue; -+ } -+ } else if (y0 > y1 && haveSTop && sTop < 0) { -+ if (!haveSMin || sTop > sMin) { -+ sMin = sTop; -+ haveSMin = gTrue; + writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight); + writePSFmt("%%Pages: {0:d}\n", lastPage - firstPage + 1); + writePS("%%EndComments\n"); +- writePS("%%BeginDefaults\n"); +- writePS("%%PageMedia: plain\n"); +- writePS("%%EndDefaults\n"); ++ if (!paperMatch) { ++ writePS("%%BeginDefaults\n"); ++ writePS("%%PageMedia: plain\n"); ++ writePS("%%EndDefaults\n"); ++ } + break; + case psModeEPS: + epsX1 = cropBox->x1; +@@ -1343,7 +1434,9 @@ + Page *page; + Dict *resDict; + Annots *annots; +- Object obj1, obj2; ++ Object *acroForm; ++ Object obj1, obj2, obj3; ++ GString *s; + int pg, i; + + if (mode == psModeForm) { +@@ -1371,11 +1464,31 @@ + } + delete annots; + } ++ if ((acroForm = catalog->getAcroForm()) && acroForm->isDict()) { ++ if (acroForm->dictLookup("DR", &obj1)->isDict()) { ++ setupResources(obj1.getDict()); ++ } ++ obj1.free(); ++ if (acroForm->dictLookup("Fields", &obj1)->isArray()) { ++ for (i = 0; i < obj1.arrayGetLength(); ++i) { ++ if (obj1.arrayGet(i, &obj2)->isDict()) { ++ if (obj2.dictLookup("DR", &obj3)->isDict()) { ++ setupResources(obj3.getDict()); ++ } ++ obj3.free(); + } ++ obj2.free(); + } -+ if (haveSZero && sZero < 0) { -+ if (!haveSMin || sZero > sMin) { -+ sMin = sZero; -+ } ++ } ++ obj1.free(); ++ } + if (mode != psModeForm) { + if (mode != psModeEPS && !manualCtrl) { +- writePSFmt("{0:d} {1:d} {2:s} pdfSetup\n", +- paperWidth, paperHeight, ++ writePSFmt("{0:s} pdfSetup\n", + globalParams->getPSDuplex() ? "true" : "false"); ++ if (!paperMatch) { ++ writePSFmt("{0:d} {1:d} pdfSetupPaper\n", paperWidth, paperHeight); + } -+ } 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 OPI_SUPPORT + if (globalParams->getPSOPI()) { +@@ -1383,6 +1496,13 @@ + } + #endif + } ++ if (customCodeCbk) { ++ if ((s = (*customCodeCbk)(this, psOutCustomDocSetup, 0, ++ customCodeCbkData))) { ++ writePS(s->getCString()); ++ delete s; ++ } ++ } + } + + void PSOutputDev::writePageTrailer() { +@@ -1558,18 +1681,15 @@ + } + + void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { +- Ref fontFileID; +- GString *name; +- PSFontParam *fontParam; ++ GfxFontLoc *fontLoc; + GString *psName; +- char buf[16]; + GBool subst; ++ char buf[16]; + UnicodeMap *uMap; + char *charName; + double xs, ys; + int code; + double w1, w2; +- double *fm; + int i, j; + + // check if font is already set up +@@ -1587,119 +1707,120 @@ + } + fontIDs[fontIDLen++] = *font->getID(); + ++ psName = NULL; + xs = ys = 1; + subst = gFalse; + +- // check for resident 8-bit font +- if (font->getName() && +- (fontParam = globalParams->getPSFont(font->getName()))) { +- psName = new GString(fontParam->psFontName->getCString()); +- +- // check for embedded Type 1 font +- } else if (globalParams->getPSEmbedType1() && +- font->getType() == fontType1 && +- font->getEmbeddedFontID(&fontFileID)) { +- psName = filterPSName(font->getEmbeddedFontName()); +- setupEmbeddedType1Font(&fontFileID, psName); +- +- // check for embedded Type 1C font +- } else if (globalParams->getPSEmbedType1() && +- font->getType() == fontType1C && +- font->getEmbeddedFontID(&fontFileID)) { +- // use the PDF font name because the embedded font name might +- // not include the subset prefix +- psName = filterPSName(font->getOrigName()); +- setupEmbeddedType1CFont(font, &fontFileID, psName); +- +- // check for embedded OpenType - Type 1C font +- } else if (globalParams->getPSEmbedType1() && +- font->getType() == fontType1COT && +- font->getEmbeddedFontID(&fontFileID)) { +- // use the PDF font name because the embedded font name might +- // not include the subset prefix +- psName = filterPSName(font->getOrigName()); +- setupEmbeddedOpenTypeT1CFont(font, &fontFileID, psName); +- +- // check for external Type 1 font file +- } else if (globalParams->getPSEmbedType1() && +- font->getType() == fontType1 && +- font->getExtFontFile()) { +- // this assumes that the PS font name matches the PDF font name +- psName = font->getName()->copy(); +- setupExternalType1Font(font->getExtFontFile(), psName); +- +- // check for embedded TrueType font +- } else if (globalParams->getPSEmbedTrueType() && +- (font->getType() == fontTrueType || +- font->getType() == fontTrueTypeOT) && +- font->getEmbeddedFontID(&fontFileID)) { +- psName = filterPSName(font->getEmbeddedFontName()); +- setupEmbeddedTrueTypeFont(font, &fontFileID, psName); +- +- // check for external TrueType font file +- } else if (globalParams->getPSEmbedTrueType() && +- font->getType() == fontTrueType && +- font->getExtFontFile()) { +- psName = filterPSName(font->getName()); +- setupExternalTrueTypeFont(font, psName); +- +- // check for embedded CID PostScript font +- } else if (globalParams->getPSEmbedCIDPostScript() && +- font->getType() == fontCIDType0C && +- font->getEmbeddedFontID(&fontFileID)) { +- psName = filterPSName(font->getEmbeddedFontName()); +- setupEmbeddedCIDType0Font(font, &fontFileID, psName); +- +- // check for embedded CID TrueType font +- } else if (globalParams->getPSEmbedCIDTrueType() && +- (font->getType() == fontCIDType2 || +- font->getType() == fontCIDType2OT) && +- font->getEmbeddedFontID(&fontFileID)) { +- psName = filterPSName(font->getEmbeddedFontName()); +- //~ should check to see if font actually uses vertical mode +- setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue); +- +- // check for embedded OpenType - CID CFF font +- } else if (globalParams->getPSEmbedCIDPostScript() && +- font->getType() == fontCIDType0COT && +- font->getEmbeddedFontID(&fontFileID)) { +- psName = filterPSName(font->getEmbeddedFontName()); +- setupEmbeddedOpenTypeCFFFont(font, &fontFileID, psName); +- +- // check for Type 3 font +- } else if (font->getType() == fontType3) { ++ if (font->getType() == fontType3) { + psName = GString::format("T3_{0:d}_{1:d}", + font->getID()->num, font->getID()->gen); + setupType3Font(font, psName, parentResDict); +- +- // do 8-bit font substitution +- } else if (!font->isCIDFont()) { +- subst = gTrue; +- name = font->getName(); +- psName = NULL; +- if (name) { +- for (i = 0; psFonts[i]; ++i) { +- if (name->cmp(psFonts[i]) == 0) { +- psName = new GString(psFonts[i]); +- break; ++ } else { ++ fontLoc = font->locateFont(xref, gTrue); ++ switch (fontLoc->locType) { ++ case gfxFontLocEmbedded: ++ switch (fontLoc->fontType) { ++ case fontType1: ++ // this assumes that the PS font name matches the PDF font name ++ psName = font->getEmbeddedFontName()->copy(); ++ setupEmbeddedType1Font(&fontLoc->embFontID, psName); ++ break; ++ case fontType1C: ++ psName = makePSFontName(font, &fontLoc->embFontID); ++ setupEmbeddedType1CFont(font, &fontLoc->embFontID, psName); ++ break; ++ case fontType1COT: ++ psName = makePSFontName(font, &fontLoc->embFontID); ++ setupEmbeddedOpenTypeT1CFont(font, &fontLoc->embFontID, psName); ++ break; ++ case fontTrueType: ++ case fontTrueTypeOT: ++ psName = makePSFontName(font, font->getID()); ++ setupEmbeddedTrueTypeFont(font, &fontLoc->embFontID, psName); ++ break; ++ case fontCIDType0C: ++ psName = makePSFontName(font, &fontLoc->embFontID); ++ setupEmbeddedCIDType0Font(font, &fontLoc->embFontID, psName); ++ break; ++ case fontCIDType2: ++ case fontCIDType2OT: ++ psName = makePSFontName(font, font->getID()); ++ //~ should check to see if font actually uses vertical mode ++ setupEmbeddedCIDTrueTypeFont(font, &fontLoc->embFontID, psName, gTrue); ++ break; ++ case fontCIDType0COT: ++ psName = makePSFontName(font, &fontLoc->embFontID); ++ setupEmbeddedOpenTypeCFFFont(font, &fontLoc->embFontID, psName); ++ break; ++ default: ++ break; ++ } ++ break; ++ case gfxFontLocExternal: ++ //~ add cases for external 16-bit fonts ++ switch (fontLoc->fontType) { ++ case fontType1: ++ if (font->getName()) { ++ // this assumes that the PS font name matches the PDF font name ++ psName = font->getName()->copy(); ++ } else { ++ //~ this won't work -- the PS font name won't match ++ psName = makePSFontName(font, font->getID()); + } ++ setupExternalType1Font(fontLoc->path, psName); ++ break; ++ case fontTrueType: ++ case fontTrueTypeOT: ++ psName = makePSFontName(font, font->getID()); ++ setupExternalTrueTypeFont(font, fontLoc->path, psName); ++ break; ++ case fontCIDType2: ++ case fontCIDType2OT: ++ psName = makePSFontName(font, font->getID()); ++ //~ should check to see if font actually uses vertical mode ++ setupExternalCIDTrueTypeFont(font, fontLoc->path, psName, gTrue); ++ break; ++ default: ++ break; + } ++ break; ++ case gfxFontLocResident: ++ psName = fontLoc->path->copy(); ++ break; + } ++ + if (!psName) { +- if (font->isFixedWidth()) { +- i = 8; +- } else if (font->isSerif()) { +- i = 4; ++ if (font->isCIDFont()) { ++ error(errSyntaxError, -1, ++ "Couldn't find a font to substitute for '{0:s}' ('{1:s}' character collection)", ++ font->getName() ? font->getName()->getCString() ++ : "(unnamed)", ++ ((GfxCIDFont *)font)->getCollection() ++ ? ((GfxCIDFont *)font)->getCollection()->getCString() ++ : "(unknown)"); ++ if (font16EncLen >= font16EncSize) { ++ font16EncSize += 16; ++ font16Enc = (PSFont16Enc *)greallocn(font16Enc, ++ font16EncSize, ++ sizeof(PSFont16Enc)); + } ++ font16Enc[font16EncLen].fontID = *font->getID(); ++ font16Enc[font16EncLen].enc = NULL; ++ ++font16EncLen; + } else { +- i = 0; +- } +- if (font->isBold()) { +- i += 2; +- } +- if (font->isItalic()) { +- i += 1; ++ error(errSyntaxError, -1, ++ "Couldn't find a font to substitute for '{0:s}'", ++ font->getName() ? font->getName()->getCString() ++ : "(unnamed)"); + } +- psName = new GString(psSubstFonts[i].psName); ++ delete fontLoc; ++ return; ++ } ++ ++ // scale substituted 8-bit fonts ++ if (fontLoc->locType == gfxFontLocResident && ++ fontLoc->substIdx >= 0) { ++ subst = gTrue; + for (code = 0; code < 256; ++code) { + if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) && + charName[0] == 'm' && charName[1] == '\0') { +@@ -1711,56 +1832,37 @@ + } else { + w1 = 0; + } +- w2 = psSubstFonts[i].mWidth; ++ w2 = psBase14SubstFonts[fontLoc->substIdx].mWidth; + xs = w1 / w2; + if (xs < 0.1) { + xs = 1; + } +- if (font->getType() == fontType3) { +- // This is a hack which makes it possible to substitute for some +- // Type 3 fonts. The problem is that it's impossible to know what +- // the base coordinate system used in the font is without actually +- // rendering the font. +- ys = xs; +- fm = font->getFontMatrix(); +- if (fm[0] != 0) { +- ys *= fm[3] / fm[0]; +- } +- } else { +- ys = 1; +- } + } + +- // do 16-bit font substitution +- } else if ((fontParam = globalParams-> +- getPSFont16(font->getName(), +- ((GfxCIDFont *)font)->getCollection(), +- font->getWMode()))) { +- subst = gTrue; +- psName = fontParam->psFontName->copy(); +- if (font16EncLen >= font16EncSize) { +- font16EncSize += 16; +- font16Enc = (PSFont16Enc *)greallocn(font16Enc, +- font16EncSize, sizeof(PSFont16Enc)); +- } +- font16Enc[font16EncLen].fontID = *font->getID(); +- font16Enc[font16EncLen].enc = fontParam->encoding->copy(); +- if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) { +- uMap->decRefCnt(); ++ // handle encodings for substituted CID fonts ++ if (fontLoc->locType == gfxFontLocResident && ++ fontLoc->fontType >= fontCIDType0) { ++ subst = gTrue; ++ if (font16EncLen >= font16EncSize) { ++ font16EncSize += 16; ++ font16Enc = (PSFont16Enc *)greallocn(font16Enc, ++ font16EncSize, ++ sizeof(PSFont16Enc)); + } -+ if (haveSZero && sDiag > 1) { -+ if (!haveSMax || sDiag < sMax) { -+ sMax = sDiag; -+ } ++ font16Enc[font16EncLen].fontID = *font->getID(); ++ if ((uMap = globalParams->getUnicodeMap(fontLoc->encoding))) { ++ font16Enc[font16EncLen].enc = fontLoc->encoding->copy(); ++ uMap->decRefCnt(); ++ } else { ++ error(errSyntaxError, -1, ++ "Couldn't find Unicode map for 16-bit font encoding '{0:t}'", ++ fontLoc->encoding); ++ font16Enc[font16EncLen].enc = NULL; + } -+ } else { - sMax = 1; + ++font16EncLen; +- } else { +- error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'", +- font16Enc[font16EncLen].enc->getCString()); } + +- // give up - can't do anything with this font +- } else { +- error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)", +- font->getName() ? font->getName()->getCString() : "(unnamed)", +- ((GfxCIDFont *)font)->getCollection() +- ? ((GfxCIDFont *)font)->getCollection()->getCString() +- : "(unknown)"); +- return; ++ delete fontLoc; + } + + // generate PostScript code to set up the font +@@ -1787,11 +1889,6 @@ + charName = buf; + } else { + charName = ((Gfx8BitFont *)font)->getCharName(i+j); +- // this is a kludge for broken PDF files that encode char 32 +- // as .notdef +- if (i+j == 32 && charName && !strcmp(charName, ".notdef")) { +- charName = "space"; +- } + } + writePS("/"); + writePSName(charName ? charName : (char *)".notdef"); +@@ -1821,36 +1918,30 @@ + int i; + + // check if font is already embedded +- for (i = 0; i < fontFileIDLen; ++i) { +- if (fontFileIDs[i].num == id->num && +- fontFileIDs[i].gen == id->gen) +- return; +- } +- +- // add entry to fontFileIDs list +- if (fontFileIDLen >= fontFileIDSize) { +- fontFileIDSize += 64; +- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); ++ if (fontNames->lookupInt(psName)) { ++ return; + } +- fontFileIDs[fontFileIDLen++] = *id; ++ fontNames->add(psName->copy(), 1); + + // get the font stream and info + refObj.initRef(id->num, id->gen); + refObj.fetch(xref, &strObj); + refObj.free(); + if (!strObj.isStream()) { + error(errSyntaxError, -1, "Embedded font file object is not a stream"); + goto err1; + } + if (!(dict = strObj.streamGetDict())) { + error(errSyntaxError, -1, + "Embedded font stream is missing its dictionary"); + goto err1; + } + dict->lookup("Length1", &obj1); + dict->lookup("Length2", &obj2); + dict->lookup("Length3", &obj3); + if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) { + error(errSyntaxError, -1, + "Missing length fields in embedded font stream dictionary"); + obj1.free(); + obj2.free(); + obj3.free(); +@@ -1947,22 +2039,12 @@ + void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) { + FILE *fontFile; + int c; +- int i; + + // check if font is already embedded +- for (i = 0; i < fontFileNameLen; ++i) { +- if (!fontFileNames[i]->cmp(fileName)) { +- return; +- } +- } +- +- // add entry to fontFileNames list +- if (fontFileNameLen >= fontFileNameSize) { +- fontFileNameSize += 64; +- fontFileNames = (GString **)greallocn(fontFileNames, +- fontFileNameSize, sizeof(GString *)); ++ if (fontNames->lookupInt(psName)) { ++ return; + } +- fontFileNames[fontFileNameLen++] = fileName->copy(); ++ fontNames->add(psName->copy(), 1); + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); +@@ -1992,18 +2074,22 @@ + int i; + + // check if font is already embedded +- for (i = 0; i < fontFileIDLen; ++i) { +- if (fontFileIDs[i].num == id->num && +- fontFileIDs[i].gen == id->gen) ++ for (i = 0; i < t1FontNameLen; ++i) { ++ if (t1FontNames[i].fontFileID.num == id->num && ++ t1FontNames[i].fontFileID.gen == id->gen) { ++ psName->clear(); ++ psName->insert(0, t1FontNames[i].psName); + return; ++ } + } +- +- // add entry to fontFileIDs list +- if (fontFileIDLen >= fontFileIDSize) { +- fontFileIDSize += 64; +- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); +- } +- fontFileIDs[fontFileIDLen++] = *id; ++ if (t1FontNameLen == t1FontNameSize) { ++ t1FontNameSize *= 2; ++ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, ++ sizeof(PST1FontName)); ++ } ++ t1FontNames[t1FontNameLen].fontFileID = *id; ++ t1FontNames[t1FontNameLen].psName = psName->copy(); ++ ++t1FontNameLen; + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); +@@ -2012,13 +2098,14 @@ + embFontList->append("\n"); + + // convert it to a Type 1 font +- fontBuf = font->readEmbFontFile(xref, &fontLen); +- if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { +- ffT1C->convertToType1(psName->getCString(), NULL, gTrue, +- outputFunc, outputStream); +- delete ffT1C; ++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { ++ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { ++ ffT1C->convertToType1(psName->getCString(), NULL, gTrue, ++ outputFunc, outputStream); ++ delete ffT1C; ++ } ++ gfree(fontBuf); } +- gfree(fontBuf); - // generate the PS code -@@ -3970,15 +4265,16 @@ - GString *s2; -- double dx, dy, dx2, dy2, originX, originY; -+ double dx, dy, originX, originY; - char *p; - UnicodeMap *uMap; - CharCode code; - Unicode u[8]; - char buf[8]; -- int len, nChars, uLen, n, m, i, j; -+ double *dxdy; -+ int dxdySize, len, nChars, uLen, n, m, i, j; + // ending comment + writePS("%%EndResource\n"); +@@ -2032,18 +2119,22 @@ + int i; - // check for invisible text -- this is used by Acrobat Capture - if (state->getRender() == 3) { -@@ -4003,6 +4299,10 @@ - for (i = 0; i < font16EncLen; ++i) { - if (font->getID()->num == font16Enc[i].fontID.num && - font->getID()->gen == font16Enc[i].fontID.gen) { -+ if (!font16Enc[i].enc) { -+ // font substitution failed, so don't output any text -+ return; -+ } - uMap = globalParams->getUnicodeMap(font16Enc[i].enc); - break; - } -@@ -4019,63 +4319,89 @@ - } + // check if font is already embedded +- for (i = 0; i < fontFileIDLen; ++i) { +- if (fontFileIDs[i].num == id->num && +- fontFileIDs[i].gen == id->gen) ++ for (i = 0; i < t1FontNameLen; ++i) { ++ if (t1FontNames[i].fontFileID.num == id->num && ++ t1FontNames[i].fontFileID.gen == id->gen) { ++ psName->clear(); ++ psName->insert(0, t1FontNames[i].psName); + return; ++ } } +- +- // add entry to fontFileIDs list +- if (fontFileIDLen >= fontFileIDSize) { +- fontFileIDSize += 64; +- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); +- } +- fontFileIDs[fontFileIDLen++] = *id; ++ if (t1FontNameLen == t1FontNameSize) { ++ t1FontNameSize *= 2; ++ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, ++ sizeof(PST1FontName)); ++ } ++ t1FontNames[t1FontNameLen].fontFileID = *id; ++ t1FontNames[t1FontNameLen].psName = psName->copy(); ++ ++t1FontNameLen; -- // compute width of chars in string, ignoring char spacing and word -- // spacing -- the Tj operator will adjust for the metrics of the -- // font that's actually used -- dx = dy = 0; -+ // compute the positioning (dx, dy) for each char in the string - nChars = 0; - p = s->getCString(); - len = s->getLength(); - s2 = new GString(); -+ dxdySize = font->isCIDFont() ? 8 : s->getLength(); -+ dxdy = (double *)gmallocn(2 * dxdySize, sizeof(double)); - while (len > 0) { - n = font->getNextChar(p, len, &code, - u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, -- &dx2, &dy2, &originX, &originY); -+ &dx, &dy, &originX, &originY); -+ dx *= state->getFontSize(); -+ dy *= state->getFontSize(); -+ if (wMode) { -+ dy += state->getCharSpace(); -+ if (n == 1 && *p == ' ') { -+ dy += state->getWordSpace(); -+ } -+ } else { -+ dx += state->getCharSpace(); -+ if (n == 1 && *p == ' ') { -+ dx += state->getWordSpace(); + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); +@@ -2052,15 +2143,16 @@ + embFontList->append("\n"); + + // convert it to a Type 1 font +- fontBuf = font->readEmbFontFile(xref, &fontLen); +- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { +- if (ffTT->isOpenTypeCFF()) { +- ffTT->convertToType1(psName->getCString(), NULL, gTrue, +- outputFunc, outputStream); ++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { ++ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { ++ if (ffTT->isOpenTypeCFF()) { ++ ffTT->convertToType1(psName->getCString(), NULL, gTrue, ++ outputFunc, outputStream); + } -+ } -+ dx *= state->getHorizScaling(); - if (font->isCIDFont()) { - if (uMap) { -+ if (nChars + uLen > dxdySize) { -+ do { -+ dxdySize *= 2; -+ } while (nChars + uLen > dxdySize); -+ dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double)); -+ } - for (i = 0; i < uLen; ++i) { - m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf)); - for (j = 0; j < m; ++j) { - s2->append(buf[j]); - } -+ //~ this really needs to get the number of chars in the target -+ //~ encoding - which may be more than the number of Unicode -+ //~ chars -+ dxdy[2 * nChars] = dx; -+ dxdy[2 * nChars + 1] = dy; -+ ++nChars; - } -- //~ this really needs to get the number of chars in the target -- //~ encoding - which may be more than the number of Unicode -- //~ chars -- nChars += uLen; - } else { -+ if (nChars + 1 > dxdySize) { -+ dxdySize *= 2; -+ dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double)); -+ } - s2->append((char)((code >> 8) & 0xff)); - s2->append((char)(code & 0xff)); -+ dxdy[2 * nChars] = dx; -+ dxdy[2 * nChars + 1] = dy; - ++nChars; - } - } else { - if (!codeToGID || codeToGID[code] >= 0) { - s2->append((char)code); -+ dxdy[2 * nChars] = dx; -+ dxdy[2 * nChars + 1] = dy; -+ ++nChars; - } ++ delete ffTT; } -- dx += dx2; -- dy += dy2; - p += n; - len -= n; - } -- dx *= state->getFontSize() * state->getHorizScaling(); -- dy *= state->getFontSize(); - if (uMap) { - uMap->decRefCnt(); +- delete ffTT; ++ gfree(fontBuf); } +- gfree(fontBuf); -- if (s2->getLength() > 0) { -+ if (nChars > 0) { - writePSString(s2); -- if (font->isCIDFont()) { -- if (wMode) { -- writePSFmt(" {0:d} {1:.4g} Tj16V\n", nChars, dy); -- } else { -- writePSFmt(" {0:d} {1:.4g} Tj16\n", nChars, dx); -+ writePS("\n["); -+ for (i = 0; i < 2 * nChars; ++i) { -+ if (i > 0) { -+ writePS("\n"); + // ending comment + writePS("%%EndResource\n"); +@@ -2071,26 +2163,7 @@ + char *fontBuf; + int fontLen; + FoFiTrueType *ffTT; + int *codeToGID; +- int i; +- +- // check if font is already embedded +- for (i = 0; i < fontFileIDLen; ++i) { +- if (fontFileIDs[i].num == id->num && +- fontFileIDs[i].gen == id->gen) { +- psName->appendf("_{0:d}", nextTrueTypeNum++); +- break; +- } +- } +- +- // add entry to fontFileIDs list +- if (i == fontFileIDLen) { +- if (fontFileIDLen >= fontFileIDSize) { +- fontFileIDSize += 64; +- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); +- } +- fontFileIDs[fontFileIDLen++] = *id; +- } + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); +@@ -2099,60 +2172,38 @@ + embFontList->append("\n"); + + // convert it to a Type 42 font +- fontBuf = font->readEmbFontFile(xref, &fontLen); +- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { +- codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); +- ffTT->convertToType42(psName->getCString(), +- ((Gfx8BitFont *)font)->getHasEncoding() +- ? ((Gfx8BitFont *)font)->getEncoding() +- : (char **)NULL, +- codeToGID, outputFunc, outputStream); +- if (codeToGID) { +- if (font8InfoLen >= font8InfoSize) { +- font8InfoSize += 16; +- font8Info = (PSFont8Info *)greallocn(font8Info, +- font8InfoSize, +- sizeof(PSFont8Info)); ++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { ++ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { ++ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); ++ ffTT->convertToType42(psName->getCString(), ++ ((Gfx8BitFont *)font)->getHasEncoding() ++ ? ((Gfx8BitFont *)font)->getEncoding() ++ : (char **)NULL, ++ codeToGID, outputFunc, outputStream); ++ if (codeToGID) { ++ if (font8InfoLen >= font8InfoSize) { ++ font8InfoSize += 16; ++ font8Info = (PSFont8Info *)greallocn(font8Info, ++ font8InfoSize, ++ sizeof(PSFont8Info)); ++ } ++ font8Info[font8InfoLen].fontID = *font->getID(); ++ font8Info[font8InfoLen].codeToGID = codeToGID; ++ ++font8InfoLen; } -- } else { -- writePSFmt(" {0:.4g} Tj\n", dx); -+ writePSFmt("{0:.6g}", dxdy[i]); +- font8Info[font8InfoLen].fontID = *font->getID(); +- font8Info[font8InfoLen].codeToGID = codeToGID; +- ++font8InfoLen; ++ delete ffTT; } -+ writePS("] Tj\n"); +- delete ffTT; ++ gfree(fontBuf); } -+ gfree(dxdy); - delete s2; +- gfree(fontBuf); - if (state->getRender() & 4) { -@@ -4730,24 +5056,32 @@ + // ending comment + writePS("%%EndResource\n"); + } - // data source - if (mode == psModeForm || inType3Char || preload) { -- writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); -+ writePS(" /DataSource { pdfImStr }\n"); - } else { - writePS(" /DataSource currentfile\n"); +-void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) { +- GString *fileName; +- char *fontBuf; +- int fontLen; ++void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *fileName, ++ GString *psName) { + FoFiTrueType *ffTT; + int *codeToGID; +- int i; +- +- // check if font is already embedded +- fileName = font->getExtFontFile(); +- for (i = 0; i < fontFileNameLen; ++i) { +- if (!fontFileNames[i]->cmp(fileName)) { +- psName->appendf("_{0:d}", nextTrueTypeNum++); +- break; +- } +- } +- +- // add entry to fontFileNames list +- if (i == fontFileNameLen) { +- if (fontFileNameLen >= fontFileNameSize) { +- fontFileNameSize += 64; +- fontFileNames = +- (GString **)greallocn(fontFileNames, +- fontFileNameSize, sizeof(GString *)); +- } +- fontFileNames[fontFileNameLen++] = fileName->copy(); +- } + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); +@@ -2161,8 +2212,7 @@ + embFontList->append("\n"); + + // convert it to a Type 42 font +- fontBuf = font->readExtFontFile(&fontLen); +- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { ++ if ((ffTT = FoFiTrueType::load(fileName->getCString()))) { + codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); + ffTT->convertToType42(psName->getCString(), + ((Gfx8BitFont *)font)->getHasEncoding() +@@ -2182,7 +2232,6 @@ + } + delete ffTT; } +- gfree(fontBuf); - // filters -- s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, -- " "); -- if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || -- inlineImg || !s) { -- useRLE = gTrue; -- useASCII = !(mode == psModeForm || inType3Char || preload); -+ if ((mode == psModeForm || inType3Char || preload) && -+ globalParams->getPSUncompressPreloadedImages()) { -+ s = NULL; -+ useRLE = gFalse; - useCompressed = gFalse; -+ useASCII = gFalse; - } else { -- useRLE = gFalse; -- useASCII = str->isBinary() && -- !(mode == psModeForm || inType3Char || preload); -- useCompressed = gTrue; -+ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, -+ " "); -+ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || -+ inlineImg || !s) { -+ useRLE = gTrue; -+ useASCII = !(mode == psModeForm || inType3Char || preload); -+ useCompressed = gFalse; -+ } else { -+ useRLE = gFalse; -+ useASCII = str->isBinary() && -+ !(mode == psModeForm || inType3Char || preload); -+ useCompressed = gTrue; + // ending comment + writePS("%%EndResource\n"); +@@ -2196,18 +2245,22 @@ + int i; + + // check if font is already embedded +- for (i = 0; i < fontFileIDLen; ++i) { +- if (fontFileIDs[i].num == id->num && +- fontFileIDs[i].gen == id->gen) ++ for (i = 0; i < t1FontNameLen; ++i) { ++ if (t1FontNames[i].fontFileID.num == id->num && ++ t1FontNames[i].fontFileID.gen == id->gen) { ++ psName->clear(); ++ psName->insert(0, t1FontNames[i].psName); + return; + } } - if (useASCII) { - writePSFmt(" /ASCII{0:s}Decode filter\n", -@@ -4872,6 +5206,7 @@ - int n, numComps; - GBool useRLE, useASCII, useASCIIHex, useCompressed; - GBool maskUseRLE, maskUseASCII, maskUseCompressed; -+ GString *maskFilters; - GfxSeparationColorSpace *sepCS; - GfxColor color; - GfxCMYK cmyk; -@@ -4881,6 +5216,83 @@ - useASCIIHex = globalParams->getPSASCIIHex(); - useRLE = useASCII = useCompressed = gFalse; // make gcc happy - maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy -+ maskFilters = NULL; // make gcc happy -+ -+ // explicit masking -+ if (maskStr) { -+ -+ // mask data source -+ if ((mode == psModeForm || inType3Char || preload) && -+ globalParams->getPSUncompressPreloadedImages()) { -+ s = NULL; -+ maskUseRLE = gFalse; -+ maskUseCompressed = gFalse; -+ maskUseASCII = gFalse; -+ } else { -+ s = maskStr->getPSFilter(3, " "); -+ if (!s) { -+ maskUseRLE = gTrue; -+ maskUseASCII = !(mode == psModeForm || inType3Char || preload); -+ maskUseCompressed = gFalse; +- +- // add entry to fontFileIDs list +- if (fontFileIDLen >= fontFileIDSize) { +- fontFileIDSize += 64; +- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); +- } +- fontFileIDs[fontFileIDLen++] = *id; ++ if (t1FontNameLen == t1FontNameSize) { ++ t1FontNameSize *= 2; ++ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, ++ sizeof(PST1FontName)); ++ } ++ t1FontNames[t1FontNameLen].fontFileID = *id; ++ t1FontNames[t1FontNameLen].psName = psName->copy(); ++ ++t1FontNameLen; + + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); +@@ -2216,18 +2269,21 @@ + embFontList->append("\n"); + + // convert it to a Type 0 font +- fontBuf = font->readEmbFontFile(xref, &fontLen); +- if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { +- if (globalParams->getPSLevel() >= psLevel3) { +- // Level 3: use a CID font +- ffT1C->convertToCIDType0(psName->getCString(), 0, NULL, +- outputFunc, outputStream); +- } else { +- // otherwise: use a non-CID composite font +- ffT1C->convertToType0(psName->getCString(), 0, NULL, +- outputFunc, outputStream); ++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { ++ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { ++ if (globalParams->getPSLevel() >= psLevel3) { ++ // Level 3: use a CID font ++ ffT1C->convertToCIDType0(psName->getCString(), NULL, 0, ++ outputFunc, outputStream); + } else { -+ maskUseRLE = gFalse; -+ maskUseASCII = maskStr->isBinary() && -+ !(mode == psModeForm || inType3Char || preload); -+ maskUseCompressed = gTrue; -+ } -+ } -+ maskFilters = new GString(); -+ if (maskUseASCII) { -+ maskFilters->appendf(" /ASCII{0:s}Decode filter\n", -+ useASCIIHex ? "Hex" : "85"); -+ } -+ if (maskUseRLE) { -+ maskFilters->append(" /RunLengthDecode filter\n"); -+ } -+ if (maskUseCompressed) { -+ maskFilters->append(s); -+ } -+ if (s) { -+ delete s; -+ } -+ if (mode == psModeForm || inType3Char || preload) { -+ writePSFmt("MaskData_{0:d}_{1:d} pdfMaskInit\n", -+ ref->getRefNum(), ref->getRefGen()); -+ } else { -+ writePS("currentfile\n"); -+ writePS(maskFilters->getCString()); -+ writePS("pdfMask\n"); -+ -+ // add RunLengthEncode and ASCIIHex/85 encode filters -+ if (maskUseCompressed) { -+ maskStr = maskStr->getUndecodedStream(); -+ } -+ if (maskUseRLE) { -+ maskStr = new RunLengthEncoder(maskStr); -+ } -+ if (maskUseASCII) { -+ if (useASCIIHex) { -+ maskStr = new ASCIIHexEncoder(maskStr); -+ } else { -+ maskStr = new ASCII85Encoder(maskStr); -+ } -+ } -+ -+ // copy the stream data -+ maskStr->reset(); -+ while ((c = maskStr->getChar()) != EOF) { -+ writePSChar(c); -+ } -+ maskStr->close(); -+ writePSChar('\n'); -+ writePS("%-EOD-\n"); -+ -+ // delete encoders -+ if (maskUseRLE || maskUseASCII) { -+ delete maskStr; ++ // otherwise: use a non-CID composite font ++ ffT1C->convertToType0(psName->getCString(), NULL, 0, ++ outputFunc, outputStream); + } -+ } -+ } ++ delete ffT1C; + } +- delete ffT1C; ++ gfree(fontBuf); + } +- gfree(fontBuf); - // color space - if (colorMap) { -@@ -5015,24 +5427,32 @@ + // ending comment + writePS("%%EndResource\n"); +@@ -2239,23 +2295,50 @@ + char *fontBuf; + int fontLen; + FoFiTrueType *ffTT; +- int i; - // data source - if (mode == psModeForm || inType3Char || preload) { -- writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); -+ writePS(" /DataSource { pdfImStr }\n"); - } else { - writePS(" /DataSource currentfile\n"); +- // check if font is already embedded +- for (i = 0; i < fontFileIDLen; ++i) { +- if (fontFileIDs[i].num == id->num && +- fontFileIDs[i].gen == id->gen) { +- psName->appendf("_{0:d}", nextTrueTypeNum++); +- break; ++ // beginning comment ++ writePSFmt("%%BeginResource: font {0:t}\n", psName); ++ embFontList->append("%%+ font "); ++ embFontList->append(psName->getCString()); ++ embFontList->append("\n"); ++ ++ // convert it to a Type 0 font ++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { ++ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { ++ if (globalParams->getPSLevel() >= psLevel3) { ++ // Level 3: use a CID font ++ ffTT->convertToCIDType2(psName->getCString(), ++ ((GfxCIDFont *)font)->getCIDToGID(), ++ ((GfxCIDFont *)font)->getCIDToGIDLen(), ++ needVerticalMetrics, ++ outputFunc, outputStream); ++ } else { ++ // otherwise: use a non-CID composite font ++ ffTT->convertToType0(psName->getCString(), ++ ((GfxCIDFont *)font)->getCIDToGID(), ++ ((GfxCIDFont *)font)->getCIDToGIDLen(), ++ needVerticalMetrics, ++ outputFunc, outputStream); ++ } ++ delete ffTT; + } ++ gfree(fontBuf); } - // filters -- s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, -- " "); -- if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || -- inlineImg || !s) { -- useRLE = gTrue; -- useASCII = !(mode == psModeForm || inType3Char || preload); -+ if ((mode == psModeForm || inType3Char || preload) && -+ globalParams->getPSUncompressPreloadedImages()) { -+ s = NULL; -+ useRLE = gFalse; - useCompressed = gFalse; -+ useASCII = gFalse; - } else { -- useRLE = gFalse; -- useASCII = str->isBinary() && -- !(mode == psModeForm || inType3Char || preload); -- useCompressed = gTrue; -+ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, -+ " "); -+ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || -+ inlineImg || !s) { -+ useRLE = gTrue; -+ useASCII = !(mode == psModeForm || inType3Char || preload); -+ useCompressed = gFalse; -+ } else { -+ useRLE = gFalse; -+ useASCII = str->isBinary() && -+ !(mode == psModeForm || inType3Char || preload); -+ useCompressed = gTrue; -+ } - } - if (useASCII) { - writePSFmt(" /ASCII{0:s}Decode filter\n", -@@ -5065,30 +5485,13 @@ - maskInvert ? 1 : 0, maskInvert ? 0 : 1); +- // add entry to fontFileIDs list +- if (fontFileIDLen >= fontFileIDSize) { +- fontFileIDSize += 64; +- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); +- } +- fontFileIDs[fontFileIDLen++] = *id; ++ // ending comment ++ writePS("%%EndResource\n"); ++} ++ ++void PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, ++ GString *fileName, ++ GString *psName, ++ GBool needVerticalMetrics) { ++ FoFiTrueType *ffTT; ++ int *codeToGID; ++ int codeToGIDLen; ++ CharCodeToUnicode *ctu; ++ Unicode uBuf[8]; ++ int cmap, code; - // mask data source -- writePS(" /DataSource currentfile\n"); -- s = maskStr->getPSFilter(3, " "); -- if (!s) { -- maskUseRLE = gTrue; -- maskUseASCII = gTrue; -- maskUseCompressed = gFalse; -+ if (mode == psModeForm || inType3Char || preload) { -+ writePS(" /DataSource {pdfMaskSrc}\n"); -+ writePS(maskFilters->getCString()); + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); +@@ -2264,26 +2347,62 @@ + embFontList->append("\n"); + + // convert it to a Type 0 font +- fontBuf = font->readEmbFontFile(xref, &fontLen); +- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { +- if (globalParams->getPSLevel() >= psLevel3) { +- // Level 3: use a CID font +- ffTT->convertToCIDType2(psName->getCString(), +- ((GfxCIDFont *)font)->getCIDToGID(), +- ((GfxCIDFont *)font)->getCIDToGIDLen(), +- needVerticalMetrics, +- outputFunc, outputStream); ++ //~ this should use fontNum to load the correct font ++ if ((ffTT = FoFiTrueType::load(fileName->getCString()))) { ++ ++ // check for embedding permission ++ if (ffTT->getEmbeddingRights() >= 1) { ++ ++ // create a CID-to-GID mapping, via Unicode ++ if ((ctu = ((GfxCIDFont *)font)->getToUnicode())) { ++ // look for a Unicode cmap ++ for (cmap = 0; cmap < ffTT->getNumCmaps(); ++cmap) { ++ if ((ffTT->getCmapPlatform(cmap) == 3 && ++ ffTT->getCmapEncoding(cmap) == 1) || ++ ffTT->getCmapPlatform(cmap) == 0) { ++ break; ++ } ++ } ++ if (cmap < ffTT->getNumCmaps()) { ++ // map CID -> Unicode -> GID ++ codeToGIDLen = ctu->getLength(); ++ codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int)); ++ for (code = 0; code < codeToGIDLen; ++code) { ++ if (ctu->mapToUnicode(code, uBuf, 8) > 0) { ++ codeToGID[code] = ffTT->mapCodeToGID(cmap, uBuf[0]); ++ } else { ++ codeToGID[code] = 0; ++ } ++ } ++ if (globalParams->getPSLevel() >= psLevel3) { ++ // Level 3: use a CID font ++ ffTT->convertToCIDType2(psName->getCString(), ++ codeToGID, codeToGIDLen, ++ needVerticalMetrics, ++ outputFunc, outputStream); ++ } else { ++ // otherwise: use a non-CID composite font ++ ffTT->convertToType0(psName->getCString(), ++ codeToGID, codeToGIDLen, ++ needVerticalMetrics, ++ outputFunc, outputStream); ++ } ++ gfree(codeToGID); ++ } ++ ctu->decRefCnt(); ++ } else { ++ error(errSyntaxError, -1, ++ "Couldn't find a mapping to Unicode for font '{0:s}'", ++ font->getName() ? font->getName()->getCString() : "(unnamed)"); ++ } } else { -- maskUseRLE = gFalse; -- maskUseASCII = maskStr->isBinary(); -- maskUseCompressed = gTrue; -- } -- if (maskUseASCII) { -- writePSFmt(" /ASCII{0:s}Decode filter\n", -- useASCIIHex ? "Hex" : "85"); -- } -- if (maskUseRLE) { -- writePS(" /RunLengthDecode filter\n"); -- } -- if (maskUseCompressed) { -- writePS(s->getCString()); -- } -- if (s) { -- delete s; -+ writePS(" /DataSource maskStream\n"); +- // otherwise: use a non-CID composite font +- ffTT->convertToType0(psName->getCString(), +- ((GfxCIDFont *)font)->getCIDToGID(), +- ((GfxCIDFont *)font)->getCIDToGIDLen(), +- needVerticalMetrics, +- outputFunc, outputStream); ++ error(errSyntaxError, -1, ++ "TrueType font '%s' does not allow embedding", ++ font->getName() ? font->getName()->getCString() : "(unnamed)"); ++ } -+ delete maskFilters; - - writePS(">>\n"); - writePS(">>\n"); -@@ -5116,39 +5519,6 @@ - + delete ffTT; } +- gfree(fontBuf); -- // explicit masking -- if (maskStr) { -- -- if (maskUseCompressed) { -- maskStr = maskStr->getUndecodedStream(); -- } -- -- // add RunLengthEncode and ASCIIHex/85 encode filters -- if (maskUseRLE) { -- maskStr = new RunLengthEncoder(maskStr); -- } -- if (maskUseASCII) { -- if (useASCIIHex) { -- maskStr = new ASCIIHexEncoder(maskStr); -- } else { -- maskStr = new ASCII85Encoder(maskStr); -- } -- } -- -- // copy the stream data -- maskStr->reset(); -- while ((c = maskStr->getChar()) != EOF) { -- writePSChar(c); -- } -- maskStr->close(); -- writePSChar('\n'); + // ending comment + writePS("%%EndResource\n"); +@@ -2297,18 +2416,22 @@ + int i; + + // check if font is already embedded +- for (i = 0; i < fontFileIDLen; ++i) { +- if (fontFileIDs[i].num == id->num && +- fontFileIDs[i].gen == id->gen) ++ for (i = 0; i < t1FontNameLen; ++i) { ++ if (t1FontNames[i].fontFileID.num == id->num && ++ t1FontNames[i].fontFileID.gen == id->gen) { ++ psName->clear(); ++ psName->insert(0, t1FontNames[i].psName); + return; ++ } + } - -- // delete encoders -- if (maskUseRLE || maskUseASCII) { -- delete maskStr; -- } +- // add entry to fontFileIDs list +- if (fontFileIDLen >= fontFileIDSize) { +- fontFileIDSize += 64; +- fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); - } -- - // get rid of the array and index - if (mode == psModeForm || inType3Char || preload) { - writePS("pop pop\n"); -@@ -5196,6 +5566,13 @@ - delete str; - } - } -+ -+ // close the mask stream -+ if (maskStr) { -+ if (!(mode == psModeForm || inType3Char || preload)) { -+ writePS("pdfMaskEnd\n"); -+ } +- fontFileIDs[fontFileIDLen++] = *id; ++ if (t1FontNameLen == t1FontNameSize) { ++ t1FontNameSize *= 2; ++ t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, ++ sizeof(PST1FontName)); + } - } - - void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace, -@@ -5898,6 +6275,7 @@ - t3URY = ury; - t3String = new GString(); - writePS("q\n"); -+ t3FillColorOnly = gTrue; - t3Cacheable = gTrue; - t3NeedsRestore = gTrue; - } -diff -ru xpdf-3.02/xpdf/PSOutputDev.h xpdf-3.03/xpdf/PSOutputDev.h ---- xpdf-3.02/xpdf/PSOutputDev.h 2007-02-27 23:05:52.000000000 +0100 -+++ xpdf-3.03/xpdf/PSOutputDev.h 2011-08-15 23:08:53.000000000 +0200 -@@ -21,15 +21,20 @@ - #include "GlobalParams.h" - #include "OutputDev.h" - -+class GHash; -+class PDFDoc; -+class XRef; - class Function; - class GfxPath; - class GfxFont; - class GfxColorSpace; - class GfxSeparationColorSpace; - class PDFRectangle; -+struct PST1FontName; - struct PSFont8Info; - struct PSFont16Enc; - class PSOutCustomColor; -+class PSOutputDev; - - //------------------------------------------------------------------------ - // PSOutputDev -@@ -48,25 +53,38 @@ - psGeneric // write to a generic stream - }; - --typedef void (*PSOutputFunc)(void *stream, const char *data, int len); -+enum PSOutCustomCodeLocation { -+ psOutCustomDocSetup, -+ psOutCustomPageSetup -+}; -+ -+typedef void (*PSOutputFunc)(void *stream, const char *data, int len); -+ -+typedef GString *(*PSOutCustomCodeCbk)(PSOutputDev *psOut, -+ PSOutCustomCodeLocation loc, int n, -+ void *data); - - class PSOutputDev: public OutputDev { - public: - - // Open a PostScript output file, and write the prolog. - PSOutputDev(char *fileName, PDFDoc *docA, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA = 0, int imgLLYA = 0, - int imgURXA = 0, int imgURYA = 0, -- GBool manualCtrlA = gFalse); -+ GBool manualCtrlA = gFalse, -+ PSOutCustomCodeCbk customCodeCbkA = NULL, -+ void *customCodeCbkDataA = NULL); - - // Open a PSOutputDev that will write to a generic stream. - PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, - PDFDoc *docA, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA = 0, int imgLLYA = 0, - int imgURXA = 0, int imgURYA = 0, -- GBool manualCtrlA = gFalse); -+ GBool manualCtrlA = gFalse, -+ PSOutCustomCodeCbk customCodeCbkA = NULL, -+ void *customCodeCbkDataA = NULL); - - // Destructor -- writes the trailer and closes the file. - virtual ~PSOutputDev(); -@@ -171,12 +189,14 @@ - virtual void updateHorizScaling(GfxState *state); - virtual void updateTextPos(GfxState *state); - virtual void updateTextShift(GfxState *state, double shift); -+ virtual void saveTextPos(GfxState *state); -+ virtual void restoreTextPos(GfxState *state); - - //----- path painting - virtual void stroke(GfxState *state); - virtual void fill(GfxState *state); - virtual void eoFill(GfxState *state); -@@ -244,10 +264,10 @@ - private: ++ t1FontNames[t1FontNameLen].fontFileID = *id; ++ t1FontNames[t1FontNameLen].psName = psName->copy(); ++ ++t1FontNameLen; - void init(PSOutputFunc outputFuncA, void *outputStreamA, - PSFileType fileTypeA, PDFDoc *docA, - int firstPage, int lastPage, PSOutMode modeA, - int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, - GBool manualCtrlA); -@@ -256,14 +282,20 @@ - void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName); - void setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, GString *psName); - void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName); -- void setupExternalTrueTypeFont(GfxFont *font, GString *psName); -+ void setupExternalTrueTypeFont(GfxFont *font, GString *fileName, -+ GString *psName); - void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName); - void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName, - GBool needVerticalMetrics); -+ void setupExternalCIDTrueTypeFont(GfxFont *font, -+ GString *fileName, -+ GString *psName, -+ GBool needVerticalMetrics); - void setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, GString *psName); - void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict); -+ GString *makePSFontName(GfxFont *font, Ref *id); - void setupImages(Dict *resDict); -- void setupImage(Ref id, Stream *str); -+ void setupImage(Ref id, Stream *str, GBool mask); - void setupForms(Dict *resDict); - void setupForm(Ref id, Object *strObj); - void addProcessColor(double c, double m, double y, double k); -@@ -308,6 +335,7 @@ - PSOutMode mode; // PostScript mode (PS, EPS, form) - int paperWidth; // width of paper, in pts - int paperHeight; // height of paper, in pts -+ GBool paperMatch; // true if paper size is set to match each page - int imgLLX, imgLLY, // imageable area, in pts - imgURX, imgURY; - GBool preload; // load all images into memory, and -@@ -322,20 +350,21 @@ - void *underlayCbkData; - void (*overlayCbk)(PSOutputDev *psOut, void *data); - void *overlayCbkData; -+ GString *(*customCodeCbk)(PSOutputDev *psOut, -+ PSOutCustomCodeLocation loc, int n, -+ void *data); -+ void *customCodeCbkData; + // beginning comment + writePSFmt("%%BeginResource: font {0:t}\n", psName); +@@ -2317,21 +2440,27 @@ + embFontList->append("\n"); - PDFDoc *doc; - XRef *xref; // the xref table for this PDF file + // convert it to a Type 0 font +- fontBuf = font->readEmbFontFile(xref, &fontLen); +- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { +- if (ffTT->isOpenTypeCFF()) { +- if (globalParams->getPSLevel() >= psLevel3) { +- // Level 3: use a CID font +- ffTT->convertToCIDType0(psName->getCString(), +- ((GfxCIDFont *)font)->getCIDToGID(), +- ((GfxCIDFont *)font)->getCIDToGIDLen(), +- outputFunc, outputStream); +- } else { +- // otherwise: use a non-CID composite font +- ffTT->convertToType0(psName->getCString(), +- ((GfxCIDFont *)font)->getCIDToGID(), +- ((GfxCIDFont *)font)->getCIDToGIDLen(), +- outputFunc, outputStream); ++ if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { ++ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { ++ if (ffTT->isOpenTypeCFF()) { ++ if (globalParams->getPSLevel() >= psLevel3) { ++ // Level 3: use a CID font ++ ffTT->convertToCIDType0(psName->getCString(), ++ ((GfxCIDFont *)font)->getCIDToGID(), ++ ((GfxCIDFont *)font)->getCIDToGIDLen(), ++ outputFunc, outputStream); ++ } else { ++ // otherwise: use a non-CID composite font ++ ffTT->convertToType0(psName->getCString(), ++ ((GfxCIDFont *)font)->getCIDToGID(), ++ ((GfxCIDFont *)font)->getCIDToGIDLen(), ++ outputFunc, outputStream); ++ } + } ++ delete ffTT; + } +- delete ffTT; ++ gfree(fontBuf); + } +- gfree(fontBuf); - Ref *fontIDs; // list of object IDs of all used fonts - int fontIDLen; // number of entries in fontIDs array - int fontIDSize; // size of fontIDs array -- Ref *fontFileIDs; // list of object IDs of all embedded fonts -- int fontFileIDLen; // number of entries in fontFileIDs array -- int fontFileIDSize; // size of fontFileIDs array -- GString **fontFileNames; // list of names of all embedded external fonts -- int fontFileNameLen; // number of entries in fontFileNames array -- int fontFileNameSize; // size of fontFileNames array -- int nextTrueTypeNum; // next unique number to append to a TrueType -- // font name -+ GHash *fontNames; // all used font names -+ PST1FontName *t1FontNames; // font names for Type 1/1C fonts -+ int t1FontNameLen; // number of entries in t1FontNames array -+ int t1FontNameSize; // size of t1FontNames array - PSFont8Info *font8Info; // info for 8-bit fonts - int font8InfoLen; // number of entries in font8Info array - int font8InfoSize; // size of font8Info array -@@ -354,6 +383,8 @@ - int numTilingPatterns; // current number of nested tiling patterns - int nextFunc; // next unique number to use for a function + // ending comment + writePS("%%EndResource\n"); +@@ -2390,9 +2519,10 @@ + box.y1 = m[1]; + box.x2 = m[2]; + box.y2 = m[3]; + gfx = new Gfx(doc, this, resDict, &box, NULL); + inType3Char = gTrue; + for (i = 0; i < charProcs->getLength(); ++i) { ++ t3FillColorOnly = gFalse; + t3Cacheable = gFalse; + t3NeedsRestore = gFalse; + writePS("/"); +@@ -2430,9 +2560,45 @@ + writePS("%%EndResource\n"); + } -+ GList *paperSizes; // list of used paper sizes, if paperMatch -+ // is true [PSOutPaperSize] - double tx0, ty0; // global translation - double xScale0, yScale0; // global scaling - int rotate0; // rotation angle (0, 90, 180, 270) -@@ -378,6 +409,7 @@ - GString *t3String; // Type 3 content string - double t3WX, t3WY, // Type 3 character parameters - t3LLX, t3LLY, t3URX, t3URY; -+ GBool t3FillColorOnly; // operators should only use the fill color - GBool t3Cacheable; // cleared if char is not cacheable - GBool t3NeedsRestore; // set if a 'q' operator was issued ++// Make a unique PS font name, based on the names given in the PDF ++// font object, and an object ID (font file object for ++GString *PSOutputDev::makePSFontName(GfxFont *font, Ref *id) { ++ GString *psName, *s; ++ ++ if ((s = font->getEmbeddedFontName())) { ++ psName = filterPSName(s); ++ if (!fontNames->lookupInt(psName)) { ++ fontNames->add(psName->copy(), 1); ++ return psName; ++ } ++ delete psName; ++ } ++ if ((s = font->getName())) { ++ psName = filterPSName(s); ++ if (!fontNames->lookupInt(psName)) { ++ fontNames->add(psName->copy(), 1); ++ return psName; ++ } ++ delete psName; ++ } ++ psName = GString::format("FF{0:d}_{1:d}", id->num, id->gen); ++ if ((s = font->getEmbeddedFontName())) { ++ s = filterPSName(s); ++ psName->append('_')->append(s); ++ delete s; ++ } else if ((s = font->getName())) { ++ s = filterPSName(s); ++ psName->append('_')->append(s); ++ delete s; ++ } ++ fontNames->add(psName->copy(), 1); ++ return psName; ++} ++ + void PSOutputDev::setupImages(Dict *resDict) { +- Object xObjDict, xObj, xObjRef, subtypeObj; +- int i; ++ Object xObjDict, xObj, xObjRef, subtypeObj, maskObj, maskRef; ++ Ref imgID; ++ int i, j; -@@ -388,7 +420,6 @@ + if (!(mode == psModeForm || inType3Char || preload)) { + return; +@@ -2447,9 +2613,32 @@ + xObj.streamGetDict()->lookup("Subtype", &subtypeObj); + if (subtypeObj.isName("Image")) { + if (xObjRef.isRef()) { +- setupImage(xObjRef.getRef(), xObj.getStream()); ++ imgID = xObjRef.getRef(); ++ for (j = 0; j < imgIDLen; ++j) { ++ if (imgIDs[j].num == imgID.num && imgIDs[j].gen == imgID.gen) { ++ break; ++ } ++ } ++ if (j == imgIDLen) { ++ if (imgIDLen >= imgIDSize) { ++ if (imgIDSize == 0) { ++ imgIDSize = 64; ++ } else { ++ imgIDSize *= 2; ++ } ++ imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref)); ++ } ++ imgIDs[imgIDLen++] = imgID; ++ setupImage(imgID, xObj.getStream(), gFalse); ++ if (level >= psLevel3 && ++ xObj.streamGetDict()->lookup("Mask", &maskObj)->isStream()) { ++ setupImage(imgID, maskObj.getStream(), gTrue); ++ } ++ maskObj.free(); ++ } + } else { + error(errSyntaxError, -1, + "Image in resource dict is not an indirect reference"); + } + } + subtypeObj.free(); +@@ -2461,30 +2650,12 @@ + xObjDict.free(); + } - GBool ok; // set up ok? +-void PSOutputDev::setupImage(Ref id, Stream *str) { ++void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) { + GBool useRLE, useCompressed, useASCIIHex; + GString *s; + int c; + int size, line, col, i; +- // check if image is already setup +- for (i = 0; i < imgIDLen; ++i) { +- if (imgIDs[i].num == id.num && imgIDs[i].gen == id.gen) { +- return; +- } +- } - - 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 - #include -+#include - #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 @@ +- // add entry to imgIDs list +- if (imgIDLen >= imgIDSize) { +- if (imgIDSize == 0) { +- imgIDSize = 64; +- } else { +- imgIDSize *= 2; +- } +- imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref)); +- } +- imgIDs[imgIDLen++] = id; +- + // filters + //~ this does not correctly handle the DeviceN color space + //~ -- need to use DeviceNRecoder +@@ -2493,17 +2664,21 @@ + useCompressed = gFalse; + useASCIIHex = gTrue; + } else { +- s = str->getPSFilter(level < psLevel3 ? 2 : 3, ""); +- if (s) { ++ if (globalParams->getPSUncompressPreloadedImages()) { + useRLE = gFalse; +- useCompressed = gTrue; +- delete s; +- } else { +- useRLE = gTrue; + useCompressed = gFalse; ++ } else { ++ s = str->getPSFilter(level < psLevel3 ? 2 : 3, ""); ++ if (s) { ++ useRLE = gFalse; ++ useCompressed = gTrue; ++ delete s; ++ } else { ++ useRLE = gTrue; ++ useCompressed = gFalse; ++ } + } +- useASCIIHex = level == psLevel1 || level == psLevel1Sep || +- globalParams->getPSASCIIHex(); ++ useASCIIHex = globalParams->getPSASCIIHex(); + } + if (useCompressed) { + str = str->getUndecodedStream(); +@@ -2552,8 +2727,8 @@ + if (useRLE) { + ++size; + } +- writePSFmt("{0:d} array dup /ImData_{1:d}_{2:d} exch def\n", +- size, id.num, id.gen); ++ writePSFmt("{0:d} array dup /{1:s}Data_{2:d}_{3:d} exch def\n", ++ size, mask ? "Mask" : "Im", id.num, id.gen); + str->close(); - //------------------------------------------------------------------------ + // write the data into the array +@@ -2722,12 +2898,14 @@ + int rotateA, GBool useMediaBox, GBool crop, + int sliceX, int sliceY, + int sliceW, int sliceH, + GBool printing, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { +-#if HAVE_SPLASH + PreScanOutputDev *scan; + GBool rasterize; ++#if HAVE_SPLASH ++ GBool mono; ++ double dpi; + SplashOutputDev *splashOut; + SplashColor paperColor; + PDFRectangle box; +@@ -2737,43 +2915,33 @@ + Object obj; + Guchar *p; + Guchar col[4]; ++ double hDPI2, vDPI2; + double m0, m1, m2, m3, m4, m5; ++ int nStripes, stripeH, stripeY; + int c, w, h, x, y, comp, i; ++#endif -+// 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 @@ +- scan = new PreScanOutputDev(); +- page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop, +- sliceX, sliceY, sliceW, sliceH, +- printing, catalog, abortCheckCbk, abortCheckCbkData); +- rasterize = scan->usesTransparency(); +- delete scan; ++ if (globalParams->getPSAlwaysRasterize()) { ++ rasterize = gTrue; ++ } else { ++ scan = new PreScanOutputDev(); ++ page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop, ++ sliceX, sliceY, sliceW, sliceH, ++ printing, abortCheckCbk, abortCheckCbkData); ++ rasterize = scan->usesTransparency() || scan->usesPatternImageMask(); ++ delete scan; ++ } + if (!rasterize) { + return gTrue; } - } - --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; } +- // rasterize the page +- if (level == psLevel1) { +- paperColor[0] = 0xff; +- splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse, +- paperColor, gTrue, gFalse); +-#if SPLASH_CMYK +- } else if (level == psLevel1Sep) { +- paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0; +- splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse, +- paperColor, gTrue, gFalse); +-#endif - } else { -- 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; } +- paperColor[0] = paperColor[1] = paperColor[2] = 0xff; +- splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse, +- paperColor, gTrue, gFalse); - } -- if (cmax == cmin) { -- *h = *s = 0; -+static int getSat(int r, int g, int b) { -+ int rgbMin, rgbMax; +- splashOut->startDoc(xref); +- page->displaySlice(splashOut, splashDPI, splashDPI, rotateA, +- useMediaBox, crop, +- sliceX, sliceY, sliceW, sliceH, +- printing, catalog, abortCheckCbk, abortCheckCbkData); ++#if HAVE_SPLASH ++ // get the rasterization parameters ++ dpi = globalParams->getPSRasterResolution(); ++ mono = globalParams->getPSRasterMono(); + + // start the PS page +- page->makeBox(splashDPI, splashDPI, rotateA, useMediaBox, gFalse, ++ page->makeBox(dpi, dpi, rotateA, useMediaBox, gFalse, + sliceX, sliceY, sliceW, sliceH, &box, &crop); + rotateA += page->getRotate(); + if (rotateA >= 360) { +@@ -2781,166 +2949,215 @@ + } else if (rotateA < 0) { + rotateA += 360; + } +- state = new GfxState(splashDPI, splashDPI, &box, rotateA, gFalse); +- startPage(page->getNum(), state); +- delete state; +- switch (rotateA) { +- case 0: +- default: // this should never happen ++ state = new GfxState(dpi, dpi, &box, rotateA, gFalse); ++ startPage(page->getNum(), state); ++ delete state; + -+ rgbMin = rgbMax = r; -+ if (g < rgbMin) { -+ rgbMin = g; -+ } else if (g > rgbMax) { -+ rgbMax = g; ++ // set up the SplashOutputDev ++ if (mono || level == psLevel1) { ++ paperColor[0] = 0xff; ++ splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse, ++ paperColor, gFalse, ++ globalParams->getAntialiasPrinting()); ++#if SPLASH_CMYK ++ } else if (level == psLevel1Sep) { ++ paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0; ++ splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse, ++ paperColor, gFalse, ++ globalParams->getAntialiasPrinting()); ++#endif ++ } else { ++ paperColor[0] = paperColor[1] = paperColor[2] = 0xff; ++ splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse, ++ paperColor, gFalse, ++ globalParams->getAntialiasPrinting()); + } -+ if (b < rgbMin) { -+ rgbMin = b; -+ } else if (b > rgbMax) { -+ rgbMax = b; ++ splashOut->startDoc(xref); ++ ++ // break the page into stripes ++ hDPI2 = xScale * dpi; ++ vDPI2 = yScale * dpi; ++ if (sliceW < 0 || sliceH < 0) { ++ if (useMediaBox) { ++ box = *page->getMediaBox(); ++ } else { ++ box = *page->getCropBox(); ++ } ++ sliceX = sliceY = 0; ++ sliceW = (int)((box.x2 - box.x1) * hDPI2 / 72.0); ++ sliceH = (int)((box.y2 - box.y1) * vDPI2 / 72.0); + } -+ return rgbMax - rgbMin; -+} ++ nStripes = (int)ceil((double)(sliceW * sliceH) / ++ (double)rasterizationSliceSize); ++ stripeH = (sliceH + nStripes - 1) / nStripes; + -+static void clipColor(int rIn, int gIn, int bIn, -+ Guchar *rOut, Guchar *gOut, Guchar *bOut) { -+ int lum, rgbMin, rgbMax; ++ // render the stripes ++ for (stripeY = sliceY; stripeY < sliceH; stripeY += stripeH) { + -+ 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); ++ // rasterize a stripe ++ page->makeBox(hDPI2, vDPI2, 0, useMediaBox, gFalse, ++ sliceX, stripeY, sliceW, stripeH, &box, &crop); + m0 = box.x2 - box.x1; + m1 = 0; + m2 = 0; + m3 = box.y2 - box.y1; + m4 = box.x1; + m5 = box.y1; +- break; +- case 90: +- m0 = 0; +- m1 = box.y2 - box.y1; +- m2 = -(box.x2 - box.x1); +- m3 = 0; +- m4 = box.x2; +- m5 = box.y1; +- break; +- case 180: +- m0 = -(box.x2 - box.x1); +- m1 = 0; +- m2 = 0; +- m3 = -(box.y2 - box.y1); +- m4 = box.x2; +- m5 = box.y2; +- break; +- case 270: +- m0 = 0; +- m1 = -(box.y2 - box.y1); +- m2 = box.x2 - box.x1; +- m3 = 0; +- m4 = box.x1; +- m5 = box.y2; +- break; +- } +- +- //~ need to add the process colors +- +- // draw the rasterized image +- bitmap = splashOut->getBitmap(); +- w = bitmap->getWidth(); +- h = bitmap->getHeight(); +- writePS("gsave\n"); +- writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] concat\n", +- m0, m1, m2, m3, m4, m5); +- switch (level) { +- case psLevel1: +- writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n", +- w, h, w, -h, h); +- p = bitmap->getDataPtr(); +- i = 0; +- for (y = 0; y < h; ++y) { +- for (x = 0; x < w; ++x) { +- writePSFmt("{0:02x}", *p++); +- if (++i == 32) { +- writePSChar('\n'); +- i = 0; +- } +- } +- } +- if (i != 0) { +- writePSChar('\n'); +- } +- break; +- case psLevel1Sep: +- writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n", +- w, h, w, -h, h); +- p = bitmap->getDataPtr(); +- i = 0; +- col[0] = col[1] = col[2] = col[3] = 0; +- for (y = 0; y < h; ++y) { +- for (comp = 0; comp < 4; ++comp) { ++ page->displaySlice(splashOut, hDPI2, vDPI2, ++ (360 - page->getRotate()) % 360, useMediaBox, crop, ++ sliceX, stripeY, sliceW, stripeH, ++ printing, abortCheckCbk, abortCheckCbkData); ++ ++ // draw the rasterized image ++ bitmap = splashOut->getBitmap(); ++ w = bitmap->getWidth(); ++ h = bitmap->getHeight(); ++ writePS("gsave\n"); ++ writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n", ++ m0, m1, m2, m3, m4, m5); ++ switch (level) { ++ case psLevel1: ++ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n", ++ w, h, w, -h, h); ++ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize(); ++ i = 0; ++ for (y = 0; y < h; ++y) { + for (x = 0; x < w; ++x) { +- writePSFmt("{0:02x}", p[4*x + comp]); +- col[comp] |= p[4*x + comp]; ++ writePSFmt("{0:02x}", *p++); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } +- p += bitmap->getRowSize(); +- } +- if (i != 0) { ++ if (i != 0) { ++ writePSChar('\n'); ++ } ++ break; ++ case psLevel1Sep: ++ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n", ++ w, h, w, -h, h); ++ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize(); ++ i = 0; ++ col[0] = col[1] = col[2] = col[3] = 0; ++ for (y = 0; y < h; ++y) { ++ for (comp = 0; comp < 4; ++comp) { ++ for (x = 0; x < w; ++x) { ++ writePSFmt("{0:02x}", p[4*x + comp]); ++ col[comp] |= p[4*x + comp]; ++ if (++i == 32) { ++ writePSChar('\n'); ++ i = 0; ++ } ++ } ++ } ++ p -= bitmap->getRowSize(); ++ } ++ if (i != 0) { ++ writePSChar('\n'); ++ } ++ if (col[0]) { ++ processColors |= psProcessCyan; ++ } ++ if (col[1]) { ++ processColors |= psProcessMagenta; ++ } ++ if (col[2]) { ++ processColors |= psProcessYellow; ++ } ++ if (col[3]) { ++ processColors |= psProcessBlack; ++ } ++ break; ++ case psLevel2: ++ case psLevel2Sep: ++ case psLevel3: ++ case psLevel3Sep: ++ if (mono) { ++ writePS("/DeviceGray setcolorspace\n"); ++ } else { ++ writePS("/DeviceRGB setcolorspace\n"); ++ } ++ writePS("<<\n /ImageType 1\n"); ++ writePSFmt(" /Width {0:d}\n", bitmap->getWidth()); ++ writePSFmt(" /Height {0:d}\n", bitmap->getHeight()); ++ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h); ++ writePS(" /BitsPerComponent 8\n"); ++ if (mono) { ++ writePS(" /Decode [0 1]\n"); ++ } else { ++ writePS(" /Decode [0 1 0 1 0 1]\n"); ++ } ++ writePS(" /DataSource currentfile\n"); ++ if (globalParams->getPSASCIIHex()) { ++ writePS(" /ASCIIHexDecode filter\n"); ++ } else { ++ writePS(" /ASCII85Decode filter\n"); ++ } ++ writePS(" /RunLengthDecode filter\n"); ++ writePS(">>\n"); ++ writePS("image\n"); ++ obj.initNull(); ++ p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize(); ++ str0 = new MemStream((char *)p, 0, w * h * (mono ? 1 : 3), &obj); ++ str = new RunLengthEncoder(str0); ++ if (globalParams->getPSASCIIHex()) { ++ str = new ASCIIHexEncoder(str); ++ } else { ++ str = new ASCII85Encoder(str); ++ } ++ str->reset(); ++ while ((c = str->getChar()) != EOF) { ++ writePSChar(c); ++ } ++ str->close(); ++ delete str; ++ delete str0; + writePSChar('\n'); ++ processColors |= mono ? psProcessBlack : psProcessCMYK; ++ break; + } +- if (col[0]) { +- processColors |= psProcessCyan; +- } +- if (col[1]) { +- processColors |= psProcessMagenta; +- } +- if (col[2]) { +- processColors |= psProcessYellow; +- } +- if (col[3]) { +- processColors |= psProcessBlack; +- } +- break; +- case psLevel2: +- case psLevel2Sep: +- case psLevel3: +- case psLevel3Sep: +- writePS("/DeviceRGB setcolorspace\n"); +- writePS("<<\n /ImageType 1\n"); +- writePSFmt(" /Width {0:d}\n", bitmap->getWidth()); +- writePSFmt(" /Height {0:d}\n", bitmap->getHeight()); +- writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h); +- writePS(" /BitsPerComponent 8\n"); +- writePS(" /Decode [0 1 0 1 0 1]\n"); +- writePS(" /DataSource currentfile\n"); +- if (globalParams->getPSASCIIHex()) { +- writePS(" /ASCIIHexDecode filter\n"); +- } else { +- writePS(" /ASCII85Decode filter\n"); +- } +- writePS(" /RunLengthDecode filter\n"); +- writePS(">>\n"); +- writePS("image\n"); +- obj.initNull(); +- str0 = new MemStream((char *)bitmap->getDataPtr(), 0, w * h * 3, &obj); +- str = new RunLengthEncoder(str0); +- if (globalParams->getPSASCIIHex()) { +- str = new ASCIIHexEncoder(str); - } else { -- *h += ((cmid - cmin) * 60) / (cmax - cmin); +- str = new ASCII85Encoder(str); +- } +- str->reset(); +- while ((c = str->getChar()) != EOF) { +- writePSChar(c); - } -- *s = (255 * (cmax - cmin)) / cmax; -+ *rOut = rIn; -+ *gOut = gIn; -+ *bOut = bIn; +- str->close(); +- delete str; +- delete str0; +- processColors |= psProcessCMYK; +- break; ++ writePS("grestore\n"); } -- *v = cmax; - } ++ + delete splashOut; +- writePS("grestore\n"); --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; + // finish the PS page + endPage(); + + return gFalse; +-#else + -+ d = lum - getLum(rIn, gIn, bIn); -+ clipColor(rIn + d, gIn + d, bIn + d, rOut, gOut, bOut); -+} ++#else // HAVE_SPLASH + -+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; ++ error(errSyntaxWarning, -1, ++ "PDF page uses transparency and PSOutputDev was built without" ++ " the Splash rasterizer - output may not be correct"); + return gTrue; +-#endif ++#endif // HAVE_SPLASH } - 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; + void PSOutputDev::startPage(int pageNum, GfxState *state) { +- int x1, y1, x2, y2, width, height; ++ Page *page; ++ int x1, y1, x2, y2, width, height, t; + int imgWidth, imgHeight, imgWidth2, imgHeight2; + GBool landscape; +- ++ GString *s; - 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 + if (mode == psModePS) { + writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage); ++ if (paperMatch) { ++ page = doc->getCatalog()->getPage(pageNum); ++ imgLLX = imgLLY = 0; ++ imgURX = (int)ceil(page->getMediaWidth()); ++ imgURY = (int)ceil(page->getMediaHeight()); ++ if (state->getRotate() == 90 || state->getRotate() == 270) { ++ t = imgURX; ++ imgURX = imgURY; ++ imgURY = t; ++ } ++ writePSFmt("%%PageMedia: {0:d}x{1:d}\n", imgURX, imgURY); ++ writePSFmt("%%PageBoundingBox: 0 0 {0:d} {1:d}\n", imgURX, imgURY); ++ } + writePS("%%BeginPageSetup\n"); } -@@ -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 @@ +@@ -2966,20 +3183,25 @@ + height = y2 - y1; + tx = ty = 0; + // rotation and portrait/landscape mode +- if (rotate0 >= 0) { ++ if (paperMatch) { ++ rotate = (360 - state->getRotate()) % 360; ++ landscape = gFalse; ++ } else if (rotate0 >= 0) { + rotate = (360 - rotate0) % 360; + landscape = gFalse; + } else { + rotate = (360 - state->getRotate()) % 360; + if (rotate == 0 || rotate == 180) { +- if (width > height && width > imgWidth) { ++ if ((width < height && imgWidth > imgHeight && height > imgHeight) || ++ (width > height && imgWidth < imgHeight && width > imgWidth)) { + rotate += 90; + landscape = gTrue; + } else { + landscape = gFalse; + } + } else { // rotate == 90 || rotate == 270 +- if (height > width && height > imgWidth) { ++ if ((height < width && imgWidth > imgHeight && width > imgHeight) || ++ (height > width && imgWidth < imgHeight && height > imgWidth)) { + rotate = 270 - rotate; + landscape = gTrue; + } else { +@@ -2989,6 +3211,9 @@ + } + writePSFmt("%%PageOrientation: {0:s}\n", + landscape ? "Landscape" : "Portrait"); ++ if (paperMatch) { ++ writePSFmt("{0:d} {1:d} pdfSetupPaper\n", imgURX, imgURY); ++ } + writePS("pdfStartPage\n"); + if (rotate == 0) { + imgWidth2 = imgWidth; +@@ -3015,9 +3240,9 @@ + xScale = xScale0; + yScale = yScale0; + } else if ((globalParams->getPSShrinkLarger() && +- (width > imgWidth2 || height > imgHeight2)) || +- (globalParams->getPSExpandSmaller() && +- (width < imgWidth2 && height < imgHeight2))) { ++ (width > imgWidth2 || height > imgHeight2)) || ++ (globalParams->getPSExpandSmaller() && ++ (width < imgWidth2 && height < imgHeight2))) { + xScale = (double)imgWidth2 / (double)width; + yScale = (double)imgHeight2 / (double)height; + if (yScale < xScale) { +@@ -3038,8 +3263,8 @@ + } + // center + if (tx0 >= 0 && ty0 >= 0) { +- tx += rotate == 0 ? tx0 : ty0; +- ty += rotate == 0 ? ty0 : -tx0; ++ tx += (rotate == 0 || rotate == 180) ? tx0 : ty0; ++ ty += (rotate == 0 || rotate == 180) ? ty0 : -tx0; + } else if (globalParams->getPSCenter()) { + if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { + tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2; +@@ -3049,22 +3274,21 @@ + ty += (imgHeight2 - yScale * height) / 2; + } + } +- tx += rotate == 0 ? imgLLX : imgLLY; +- ty += rotate == 0 ? imgLLY : -imgLLX; ++ tx += (rotate == 0 || rotate == 180) ? imgLLX : imgLLY; ++ ty += (rotate == 0 || rotate == 180) ? imgLLY : -imgLLX; + if (tx != 0 || ty != 0) { + writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty); + } + if (xScale != 1 || yScale != 1) { + writePSFmt("{0:.6f} {1:.6f} scale\n", xScale, yScale); + } + if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { + writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re W\n", + clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0); + } else { + writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1); + } - 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]); +- writePS("%%EndPageSetup\n"); + ++seqPage; 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]; + +@@ -3101,6 +3325,18 @@ + rotate = 0; 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; ++ if (customCodeCbk) { ++ if ((s = (*customCodeCbk)(this, psOutCustomPageSetup, pageNum, ++ customCodeCbkData))) { ++ writePS(s->getCString()); ++ delete s; ++ } + } -+ 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()); ++ if (mode == psModePS) { ++ writePS("%%EndPageSetup\n"); ++ } } - void SplashOutputDev::updateFont(GfxState *state) { - needFontUpdate = gTrue; + void PSOutputDev::endPage() { +@@ -3458,25 +3693,33 @@ + void PSOutputDev::stroke(GfxState *state) { + doPath(state->getPath()); +- if (t3String) { +- // if we're construct a cacheable Type 3 glyph, we need to do ++ if (inType3Char && t3FillColorOnly) { ++ // if we're constructing a cacheable Type 3 glyph, we need to do + // everything in the fill color + writePS("Sf\n"); + } else { +@@ -3494,19 +3737,19 @@ + writePS("f*\n"); } - void 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; +@@ -3526,34 +3769,37 @@ + box.y1 = bbox[1]; + box.x2 = bbox[2]; + box.y2 = bbox[3]; + gfx = new Gfx(doc, this, resDict, &box, NULL); + writePS("/x {\n"); + if (paintType == 2) { + writePSFmt("{0:.6g} 0 {1:.6g} {2:.6g} {3:.6g} {4:.6g} setcachedevice\n", + xStep, bbox[0], bbox[1], bbox[2], bbox[3]); ++ t3FillColorOnly = gTrue; + } else { + if (x1 - 1 <= x0) { + writePS("1 0 setcharwidth\n"); + } else { + writePSFmt("{0:.6g} 0 setcharwidth\n", xStep); + } ++ t3FillColorOnly = gFalse; } + inType3Char = gTrue; + ++numTilingPatterns; +- gfx->display(str); ++ gfx2->display(str); + --numTilingPatterns; + inType3Char = gFalse; + writePS("} def\n"); +- delete gfx; ++ delete gfx2; + writePS("end\n"); + writePS("currentdict end\n"); + writePSFmt("/xpdfTile{0:d} exch definefont pop\n", numTilingPatterns); -+ // 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 @@ + // draw the tiles + writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns); ++ writePS("fCol\n"); + writePSFmt("gsave [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n", + mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + writePSFmt("{0:d} 1 {1:d} {{ {2:.6g} exch {3:.6g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n", + y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1); + writePS("grestore\n"); + } +@@ -3698,7 +3944,10 @@ + double xMin, yMin, xMax, yMax; + double x0, y0, r0, x1, y1, r1, t0, t1; + double xa, ya, ra; +- double sz, xz, yz, sMin, sMax, sa, ta; ++ double sz, sMin, sMax, h, ta; ++ double sLeft, sRight, sTop, sBottom, sZero, sDiag; ++ GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero; ++ GBool haveSMin, haveSMax; + double theta, alpha, a1, a2; + GBool enclosed; + int i; +@@ -3717,19 +3966,23 @@ + // Compute the point at which r(s) = 0; check for the enclosed + // circles case; and compute the angles for the tangent lines. +- if (r0 == r1) { +- enclosed = x0 == x1 && y0 == y1; ++ h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); ++ if (h == 0) { ++ enclosed = gTrue; ++ theta = 0; // make gcc happy ++ sz = 0; // make gcc happy ++ } else if (r1 - r0 == 0) { ++ enclosed = gFalse; + theta = 0; + sz = 0; // make gcc happy ++ } else if (fabs(r1 - r0) >= h) { ++ enclosed = gTrue; ++ theta = 0; // make gcc happy ++ sz = 0; // make gcc happy } else { - -- // 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); -- } ++ enclosed = gFalse; + sz = -r0 / (r1 - r0); +- xz = x0 + sz * (x1 - x0); +- yz = y0 + sz * (y1 - y0); +- enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0; +- theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz))); +- if (r0 > r1) { +- theta = -theta; +- } ++ theta = asin((r1 - r0) / h); + } + if (enclosed) { + a1 = 0; +@@ -3749,80 +4002,122 @@ + sMin = 0; + sMax = 1; + } else { +- sMin = 1; +- sMax = 0; +- // solve for x(s) + r(s) = xMin +- if ((x1 + r1) - (x0 + r0) != 0) { +- sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0)); +- if (sa < sMin) { +- sMin = sa; +- } else if (sa > sMax) { +- sMax = sa; +- } +- } +- // solve for x(s) - r(s) = xMax +- if ((x1 - r1) - (x0 - r0) != 0) { +- sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0)); +- if (sa < sMin) { +- sMin = sa; +- } else if (sa > sMax) { +- sMax = sa; - } -- if (!dfp) { -- error(-1, "Couldn't find a font for '%s'", -- gfxFont->getName() ? gfxFont->getName()->getCString() -- : "(unnamed)"); -- goto err2; +- } +- // 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; - } -- 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); - } +- } +- // solve for y(s) - r(s) = yMax +- if ((y1 - r1) - (y0 - r0) != 0) { +- sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0)); +- if (sa < sMin) { +- sMin = sa; +- } else if (sa > sMax) { +- sMax = sa; +- } +- } +- // check against sz +- if (r0 < r1) { +- if (sMin < sz) { +- sMin = sz; +- } +- } else if (r0 > r1) { +- if (sMax > sz) { +- sMax = sz; +- } ++ // solve x(sLeft) + r(sLeft) = xMin ++ if ((haveSLeft = fabs((x1 + r1) - (x0 + r0)) > 0.000001)) { ++ sLeft = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0)); ++ } else { ++ sLeft = 0; // make gcc happy ++ } ++ // solve x(sRight) - r(sRight) = xMax ++ if ((haveSRight = fabs((x1 - r1) - (x0 - r0)) > 0.000001)) { ++ sRight = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0)); ++ } else { ++ sRight = 0; // make gcc happy ++ } ++ // solve y(sBottom) + r(sBottom) = yMin ++ if ((haveSBottom = fabs((y1 + r1) - (y0 + r0)) > 0.000001)) { ++ sBottom = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0)); ++ } else { ++ sBottom = 0; // make gcc happy ++ } ++ // solve y(sTop) - r(sTop) = yMax ++ if ((haveSTop = fabs((y1 - r1) - (y0 - r0)) > 0.000001)) { ++ sTop = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0)); ++ } else { ++ sTop = 0; // make gcc happy ++ } ++ // solve r(sZero) = 0 ++ if ((haveSZero = fabs(r1 - r0) > 0.000001)) { ++ sZero = -r0 / (r1 - r0); ++ } else { ++ sZero = 0; // make gcc happy ++ } ++ // solve r(sDiag) = sqrt((xMax-xMin)^2 + (yMax-yMin)^2) ++ if (haveSZero) { ++ sDiag = (sqrt((xMax - xMin) * (xMax - xMin) + ++ (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0); ++ } else { ++ sDiag = 0; // make gcc happy + } +- // check the 'extend' flags +- if (!shading->getExtend0() && sMin < 0) { ++ // compute sMin ++ if (shading->getExtend0()) { ++ sMin = 0; ++ haveSMin = gFalse; ++ if (x0 < x1 && haveSLeft && sLeft < 0) { ++ sMin = sLeft; ++ haveSMin = gTrue; ++ } else if (x0 > x1 && haveSRight && sRight < 0) { ++ sMin = sRight; ++ haveSMin = gTrue; ++ } ++ if (y0 < y1 && haveSBottom && sBottom < 0) { ++ if (!haveSMin || sBottom > sMin) { ++ sMin = sBottom; ++ haveSMin = gTrue; ++ } ++ } else if (y0 > y1 && haveSTop && sTop < 0) { ++ if (!haveSMin || sTop > sMin) { ++ sMin = sTop; ++ haveSMin = gTrue; ++ } ++ } ++ if (haveSZero && sZero < 0) { ++ if (!haveSMin || sZero > sMin) { ++ sMin = sZero; ++ } ++ } ++ } else { + sMin = 0; + } +- if (!shading->getExtend1() && sMax > 1) { ++ // compute sMax ++ if (shading->getExtend1()) { ++ sMax = 1; ++ haveSMax = gFalse; ++ if (x1 < x0 && haveSLeft && sLeft > 1) { ++ sMax = sLeft; ++ haveSMax = gTrue; ++ } else if (x1 > x0 && haveSRight && sRight > 1) { ++ sMax = sRight; ++ haveSMax = gTrue; ++ } ++ if (y1 < y0 && haveSBottom && sBottom > 1) { ++ if (!haveSMax || sBottom < sMax) { ++ sMax = sBottom; ++ haveSMax = gTrue; ++ } ++ } else if (y1 > y0 && haveSTop && sTop > 1) { ++ if (!haveSMax || sTop < sMax) { ++ sMax = sTop; ++ haveSMax = gTrue; ++ } ++ } ++ if (haveSZero && sDiag > 1) { ++ if (!haveSMax || sDiag < sMax) { ++ sMax = sDiag; ++ } ++ } ++ } else { + sMax = 1; } + } - // 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; -+ } -+ } + // generate the PS code +@@ -3970,15 +4265,16 @@ + GString *s2; +- double dx, dy, dx2, dy2, originX, originY; ++ double dx, dy, originX, originY; + char *p; + UnicodeMap *uMap; + CharCode code; + Unicode u[8]; + char buf[8]; +- int len, nChars, uLen, n, m, i, j; ++ double *dxdy; ++ int dxdySize, len, nChars, uLen, n, m, i, j; + + // check for invisible text -- this is used by Acrobat Capture + if (state->getRender() == 3) { +@@ -4003,6 +4299,10 @@ + for (i = 0; i < font16EncLen; ++i) { + if (font->getID()->num == font16Enc[i].fontID.num && + font->getID()->gen == font16Enc[i].fontID.gen) { ++ if (!font16Enc[i].enc) { ++ // font substitution failed, so don't output any text ++ return; + } - } 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; + uMap = globalParams->getUnicodeMap(font16Enc[i].enc); + break; } - 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)); +@@ -4019,63 +4319,89 @@ + } + } + +- // compute width of chars in string, ignoring char spacing and word +- // spacing -- the Tj operator will adjust for the metrics of the +- // font that's actually used +- dx = dy = 0; ++ // compute the positioning (dx, dy) for each char in the string + nChars = 0; + p = s->getCString(); + len = s->getLength(); + s2 = new GString(); ++ dxdySize = font->isCIDFont() ? 8 : s->getLength(); ++ dxdy = (double *)gmallocn(2 * dxdySize, sizeof(double)); + while (len > 0) { + n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, +- &dx2, &dy2, &originX, &originY); ++ &dx, &dy, &originX, &originY); ++ dx *= state->getFontSize(); ++ dy *= state->getFontSize(); ++ if (wMode) { ++ dy += state->getCharSpace(); ++ if (n == 1 && *p == ' ') { ++ dy += state->getWordSpace(); ++ } ++ } else { ++ dx += state->getCharSpace(); ++ if (n == 1 && *p == ' ') { ++ dx += state->getWordSpace(); ++ } ++ } ++ dx *= state->getHorizScaling(); + if (font->isCIDFont()) { + if (uMap) { ++ if (nChars + uLen > dxdySize) { ++ do { ++ dxdySize *= 2; ++ } while (nChars + uLen > dxdySize); ++ dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double)); + } -+ } 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 @@ + for (i = 0; i < uLen; ++i) { + m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf)); + for (j = 0; j < m; ++j) { + s2->append(buf[j]); } - 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)"); ++ //~ this really needs to get the number of chars in the target ++ //~ encoding - which may be more than the number of Unicode ++ //~ chars ++ dxdy[2 * nChars] = dx; ++ dxdy[2 * nChars + 1] = dy; ++ ++nChars; } -- } else { -- if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { -- n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); -- codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort)); -- memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), -- n * sizeof(Gushort)); -- } +- //~ this really needs to get the number of chars in the target +- //~ encoding - which may be more than the number of Unicode +- //~ chars +- nChars += uLen; + } else { ++ if (nChars + 1 > dxdySize) { ++ dxdySize *= 2; ++ dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double)); ++ } + s2->append((char)((code >> 8) & 0xff)); + s2->append((char)(code & 0xff)); ++ dxdy[2 * nChars] = dx; ++ dxdy[2 * nChars + 1] = dy; + ++nChars; } - 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; + } else { + if (!codeToGID || codeToGID[code] >= 0) { + s2->append((char)code); ++ dxdy[2 * nChars] = dx; ++ dxdy[2 * nChars + 1] = dy; ++ ++nChars; } - break; -@@ -1219,6 +1335,8 @@ - // this shouldn't happen - goto err2; } -+ -+ delete fontLoc; +- dx += dx2; +- dy += dy2; + p += n; + len -= n; + } +- dx *= state->getFontSize() * state->getHorizScaling(); +- dy *= state->getFontSize(); + if (uMap) { + uMap->decRefCnt(); } - // 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; +- if (s2->getLength() > 0) { ++ if (nChars > 0) { + writePSString(s2); +- if (font->isCIDFont()) { +- if (wMode) { +- writePSFmt(" {0:d} {1:.4g} Tj16V\n", nChars, dy); +- } else { +- writePSFmt(" {0:d} {1:.4g} Tj16\n", nChars, dx); ++ writePS("\n["); ++ for (i = 0; i < 2 * nChars; ++i) { ++ if (i > 0) { ++ writePS("\n"); } +- } else { +- writePSFmt(" {0:.4g} Tj\n", dx); ++ writePSFmt("{0:.6g}", dxdy[i]); } ++ writePS("] Tj\n"); } -@@ -1375,6 +1655,18 @@ - Unicode *u, int uLen) { - SplashPath *path; - int render; -+ GBool doFill, doStroke, doClip, strokeAdjust; -+ double m[4]; -+ GBool horiz; ++ gfree(dxdy); + delete s2; + + if (state->getRender() & 4) { +@@ -4730,24 +5056,32 @@ + + // data source + if (mode == psModeForm || inType3Char || preload) { +- writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); ++ writePS(" /DataSource { pdfImStr }\n"); + } else { + writePS(" /DataSource currentfile\n"); + } + + // filters +- s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, +- " "); +- if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || +- inlineImg || !s) { +- useRLE = gTrue; +- useASCII = !(mode == psModeForm || inType3Char || preload); ++ if ((mode == psModeForm || inType3Char || preload) && ++ globalParams->getPSUncompressPreloadedImages()) { ++ s = NULL; ++ useRLE = gFalse; + useCompressed = gFalse; ++ useASCII = gFalse; + } else { +- useRLE = gFalse; +- useASCII = str->isBinary() && +- !(mode == psModeForm || inType3Char || preload); +- useCompressed = gTrue; ++ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, ++ " "); ++ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || ++ inlineImg || !s) { ++ useRLE = gTrue; ++ useASCII = !(mode == psModeForm || inType3Char || preload); ++ useCompressed = gFalse; ++ } else { ++ useRLE = gFalse; ++ useASCII = str->isBinary() && ++ !(mode == psModeForm || inType3Char || preload); ++ useCompressed = gTrue; ++ } + } + if (useASCII) { + writePSFmt(" /ASCII{0:s}Decode filter\n", +@@ -4872,6 +5206,7 @@ + int n, numComps; + GBool useRLE, useASCII, useASCIIHex, useCompressed; + GBool maskUseRLE, maskUseASCII, maskUseCompressed; ++ GString *maskFilters; + GfxSeparationColorSpace *sepCS; + GfxColor color; + GfxCMYK cmyk; +@@ -4881,6 +5216,83 @@ + useASCIIHex = globalParams->getPSASCIIHex(); + useRLE = useASCII = useCompressed = gFalse; // make gcc happy + maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy ++ maskFilters = NULL; // make gcc happy + -+ 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; ++ // explicit masking ++ if (maskStr) { ++ ++ // mask data source ++ if ((mode == psModeForm || inType3Char || preload) && ++ globalParams->getPSUncompressPreloadedImages()) { ++ s = NULL; ++ maskUseRLE = gFalse; ++ maskUseCompressed = gFalse; ++ maskUseASCII = gFalse; ++ } else { ++ s = maskStr->getPSFilter(3, " "); ++ if (!s) { ++ maskUseRLE = gTrue; ++ maskUseASCII = !(mode == psModeForm || inType3Char || preload); ++ maskUseCompressed = gFalse; ++ } else { ++ maskUseRLE = gFalse; ++ maskUseASCII = maskStr->isBinary() && ++ !(mode == psModeForm || inType3Char || preload); ++ maskUseCompressed = gTrue; ++ } ++ } ++ maskFilters = new GString(); ++ if (maskUseASCII) { ++ maskFilters->appendf(" /ASCII{0:s}Decode filter\n", ++ useASCIIHex ? "Hex" : "85"); + } -+ } - - // 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); ++ if (maskUseRLE) { ++ maskFilters->append(" /RunLengthDecode filter\n"); + } ++ if (maskUseCompressed) { ++ maskFilters->append(s); ++ } ++ if (s) { ++ delete s; ++ } ++ if (mode == psModeForm || inType3Char || preload) { ++ writePSFmt("MaskData_{0:d}_{1:d} pdfMaskInit\n", ++ ref->getRefNum(), ref->getRefGen()); ++ } else { ++ writePS("currentfile\n"); ++ writePS(maskFilters->getCString()); ++ writePS("pdfMask\n"); + -+ // 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); -+ } ++ // add RunLengthEncode and ASCIIHex/85 encode filters ++ if (maskUseCompressed) { ++ maskStr = maskStr->getUndecodedStream(); ++ } ++ if (maskUseRLE) { ++ maskStr = new RunLengthEncoder(maskStr); ++ } ++ if (maskUseASCII) { ++ if (useASCIIHex) { ++ maskStr = new ASCIIHexEncoder(maskStr); ++ } else { ++ maskStr = new ASCII85Encoder(maskStr); ++ } ++ } + -+ 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; ++ // copy the stream data ++ maskStr->reset(); ++ while ((c = maskStr->getChar()) != EOF) { ++ writePSChar(c); ++ } ++ maskStr->close(); ++ writePSChar('\n'); ++ writePS("%-EOD-\n"); ++ ++ // delete encoders ++ if (maskUseRLE || maskUseASCII) { ++ delete maskStr; ++ } + } + } -+ - 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; + // color space + if (colorMap) { +@@ -5015,24 +5427,32 @@ -+ // 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; + // data source + if (mode == psModeForm || inType3Char || preload) { +- writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); ++ writePS(" /DataSource { pdfImStr }\n"); } 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; + writePS(" /DataSource currentfile\n"); } -+ 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; + // filters +- s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, +- " "); +- if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || +- inlineImg || !s) { +- useRLE = gTrue; +- useASCII = !(mode == psModeForm || inType3Char || preload); ++ if ((mode == psModeForm || inType3Char || preload) && ++ globalParams->getPSUncompressPreloadedImages()) { ++ s = NULL; ++ useRLE = gFalse; + useCompressed = gFalse; ++ useASCII = gFalse; + } else { +- useRLE = gFalse; +- useASCII = str->isBinary() && +- !(mode == psModeForm || inType3Char || preload); +- useCompressed = gTrue; ++ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, ++ " "); ++ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || ++ inlineImg || !s) { ++ useRLE = gTrue; ++ useASCII = !(mode == psModeForm || inType3Char || preload); ++ useCompressed = gFalse; ++ } else { ++ useRLE = gFalse; ++ useASCII = str->isBinary() && ++ !(mode == psModeForm || inType3Char || preload); ++ useCompressed = gTrue; ++ } } -+ if (!(p = imgData->imgStr->getLine())) { -+ return gFalse; -+ } + if (useASCII) { + writePSFmt(" /ASCII{0:s}Decode filter\n", +@@ -5065,30 +5485,13 @@ + maskInvert ? 1 : 0, maskInvert ? 0 : 1); - 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; + // mask data source +- writePS(" /DataSource currentfile\n"); +- s = maskStr->getPSFilter(3, " "); +- if (!s) { +- maskUseRLE = gTrue; +- maskUseASCII = gTrue; +- maskUseCompressed = gFalse; ++ if (mode == psModeForm || inType3Char || preload) { ++ writePS(" /DataSource {pdfMaskSrc}\n"); ++ writePS(maskFilters->getCString()); } else { - 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; +- maskUseRLE = gFalse; +- maskUseASCII = maskStr->isBinary(); +- maskUseCompressed = gTrue; +- } +- if (maskUseASCII) { +- writePSFmt(" /ASCII{0:s}Decode filter\n", +- useASCIIHex ? "Hex" : "85"); +- } +- if (maskUseRLE) { +- writePS(" /RunLengthDecode filter\n"); +- } +- if (maskUseCompressed) { +- writePS(s->getCString()); +- } +- if (s) { +- delete s; ++ writePS(" /DataSource maskStream\n"); } - } ++ delete maskFilters; -@@ -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; + writePS(">>\n"); + writePS(">>\n"); +@@ -5116,39 +5519,6 @@ - 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; +- // explicit masking +- if (maskStr) { +- +- if (maskUseCompressed) { +- maskStr = maskStr->getUndecodedStream(); +- } +- +- // add RunLengthEncode and ASCIIHex/85 encode filters +- if (maskUseRLE) { +- maskStr = new RunLengthEncoder(maskStr); +- } +- if (maskUseASCII) { +- if (useASCIIHex) { +- maskStr = new ASCIIHexEncoder(maskStr); +- } else { +- maskStr = new ASCII85Encoder(maskStr); +- } +- } +- +- // copy the stream data +- maskStr->reset(); +- while ((c = maskStr->getChar()) != EOF) { +- writePSChar(c); +- } +- maskStr->close(); +- writePSChar('\n'); +- +- // delete encoders +- if (maskUseRLE || maskUseASCII) { +- delete maskStr; +- } +- } +- + // get rid of the array and index + if (mode == psModeForm || inType3Char || preload) { + writePS("pop pop\n"); +@@ -5196,6 +5566,13 @@ + delete str; } } - -@@ -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 ++ // close the mask stream ++ if (maskStr) { ++ if (!(mode == psModeForm || inType3Char || preload)) { ++ writePS("pdfMaskEnd\n"); + } + } - - // 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); + void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace, +@@ -5898,6 +6275,7 @@ + t3URY = ury; + t3String = new GString(); + writePS("q\n"); ++ t3FillColorOnly = gTrue; + t3Cacheable = gTrue; + t3NeedsRestore = gTrue; } -@@ -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); +diff -ru xpdf-3.02/xpdf/PSOutputDev.h xpdf-3.03/xpdf/PSOutputDev.h +--- xpdf-3.02/xpdf/PSOutputDev.h 2007-02-27 23:05:52.000000000 +0100 ++++ xpdf-3.03/xpdf/PSOutputDev.h 2011-08-15 23:08:53.000000000 +0200 +@@ -21,15 +21,20 @@ + #include "GlobalParams.h" + #include "OutputDev.h" -@@ -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 -+ } - } ++class GHash; ++class PDFDoc; ++class XRef; + class Function; + class GfxPath; + class GfxFont; + class GfxColorSpace; + class GfxSeparationColorSpace; + class PDFRectangle; ++struct PST1FontName; + struct PSFont8Info; + struct PSFont16Enc; + class PSOutCustomColor; ++class PSOutputDev; --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 @@ + //------------------------------------------------------------------------ + // PSOutputDev +@@ -48,25 +53,38 @@ + psGeneric // write to a generic stream + }; - // 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; - } +-typedef void (*PSOutputFunc)(void *stream, const char *data, int len); ++enum PSOutCustomCodeLocation { ++ psOutCustomDocSetup, ++ psOutCustomPageSetup ++}; ++ ++typedef void (*PSOutputFunc)(void *stream, const char *data, int len); ++ ++typedef GString *(*PSOutCustomCodeCbk)(PSOutputDev *psOut, ++ PSOutCustomCodeLocation loc, int n, ++ void *data); - // create the scaled font -@@ -2835,11 +3284,7 @@ - } + class PSOutputDev: public OutputDev { + public: - #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 @@ + // Open a PostScript output file, and write the prolog. + PSOutputDev(char *fileName, PDFDoc *docA, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA = 0, int imgLLYA = 0, + int imgURXA = 0, int imgURYA = 0, +- GBool manualCtrlA = gFalse); ++ GBool manualCtrlA = gFalse, ++ PSOutCustomCodeCbk customCodeCbkA = NULL, ++ void *customCodeCbkDataA = NULL); - // 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; } + // Open a PSOutputDev that will write to a generic stream. + PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, + PDFDoc *docA, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA = 0, int imgLLYA = 0, + int imgURXA = 0, int imgURYA = 0, +- GBool manualCtrlA = gFalse); ++ GBool manualCtrlA = gFalse, ++ PSOutCustomCodeCbk customCodeCbkA = NULL, ++ void *customCodeCbkDataA = NULL); - // Does this device use drawChar() or drawString()? - virtual GBool useDrawChar() { return gTrue; } + // Destructor -- writes the trailer and closes the file. + virtual ~PSOutputDev(); +@@ -244,10 +264,10 @@ + private: -@@ -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; } + void init(PSOutputFunc outputFuncA, void *outputStreamA, + PSFileType fileTypeA, PDFDoc *docA, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, + GBool manualCtrlA); +@@ -256,14 +282,20 @@ + void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName); + void setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, GString *psName); + void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName); +- void setupExternalTrueTypeFont(GfxFont *font, GString *psName); ++ void setupExternalTrueTypeFont(GfxFont *font, GString *fileName, ++ GString *psName); + void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName); + void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName, + GBool needVerticalMetrics); ++ void setupExternalCIDTrueTypeFont(GfxFont *font, ++ GString *fileName, ++ GString *psName, ++ GBool needVerticalMetrics); + void setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, GString *psName); + void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict); ++ GString *makePSFontName(GfxFont *font, Ref *id); + void setupImages(Dict *resDict); +- void setupImage(Ref id, Stream *str); ++ void setupImage(Ref id, Stream *str, GBool mask); + void setupForms(Dict *resDict); + void setupForm(Ref id, Object *strObj); + void addProcessColor(double c, double m, double y, double k); +@@ -308,6 +335,7 @@ + PSOutMode mode; // PostScript mode (PS, EPS, form) + int paperWidth; // width of paper, in pts + int paperHeight; // height of paper, in pts ++ GBool paperMatch; // true if paper size is set to match each page + int imgLLX, imgLLY, // imageable area, in pts + imgURX, imgURY; + GBool preload; // load all images into memory, and +@@ -322,20 +350,21 @@ + void *underlayCbkData; + void (*overlayCbk)(PSOutputDev *psOut, void *data); + void *overlayCbkData; ++ GString *(*customCodeCbk)(PSOutputDev *psOut, ++ PSOutCustomCodeLocation loc, int n, ++ void *data); ++ void *customCodeCbkData; -@@ -187,26 +207,36 @@ - void setFillColor(int r, int g, int b); + PDFDoc *doc; + XRef *xref; // the xref table for this PDF file - // 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); + Ref *fontIDs; // list of object IDs of all used fonts + int fontIDLen; // number of entries in fontIDs array + int fontIDSize; // size of fontIDs array +- Ref *fontFileIDs; // list of object IDs of all embedded fonts +- int fontFileIDLen; // number of entries in fontFileIDs array +- int fontFileIDSize; // size of fontFileIDs array +- GString **fontFileNames; // list of names of all embedded external fonts +- int fontFileNameLen; // number of entries in fontFileNames array +- int fontFileNameSize; // size of fontFileNames array +- int nextTrueTypeNum; // next unique number to append to a TrueType +- // font name ++ GHash *fontNames; // all used font names ++ PST1FontName *t1FontNames; // font names for Type 1/1C fonts ++ int t1FontNameLen; // number of entries in t1FontNames array ++ int t1FontNameSize; // size of t1FontNames array + PSFont8Info *font8Info; // info for 8-bit fonts + int font8InfoLen; // number of entries in font8Info array + int font8InfoSize; // size of font8Info array +@@ -354,6 +383,8 @@ + int numTilingPatterns; // current number of nested tiling patterns + int nextFunc; // next unique number to use for a function - SplashFont *getCurrentFont() { return font; } ++ GList *paperSizes; // list of used paper sizes, if paperMatch ++ // is true [PSOutPaperSize] + double tx0, ty0; // global translation + double xScale0, yScale0; // global scaling + int rotate0; // rotation angle (0, 90, 180, 270) +@@ -378,6 +409,7 @@ + GString *t3String; // Type 3 content string + double t3WX, t3WY, // Type 3 character parameters + t3LLX, t3LLY, t3URX, t3URY; ++ GBool t3FillColorOnly; // operators should only use the fill color + GBool t3Cacheable; // cleared if char is not cacheable + GBool t3NeedsRestore; // set if a 'q' operator was issued -+ // If is true, don't draw horizontal text. -+ // If 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 +@@ -388,7 +420,6 @@ - private: + GBool ok; // set up ok? - 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; +- + friend class WinPDFPrinter; }; - #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 . void updatePriMinMax(TextBlock *blk); -@@ -429,6 +430,15 @@ - double dx, double dy, - CharCode c, int nBytes, Unicode *u, int uLen); - -+ // Add 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, -- cgit v1.2.3