📄 splashoutputdev.cc
字号:
} strObj.streamClose(); strObj.free(); fclose(tmpFile); fileName = tmpFileName; // if there is an external font file, use it } else if (!(fileName = gfxFont->getExtFontFile())) { // look for a display font mapping or a substitute font if (gfxFont->isCIDFont()) { if (((GfxCIDFont *)gfxFont)->getCollection()) { dfp = globalParams-> getDisplayCIDFont(gfxFont->getName(), ((GfxCIDFont *)gfxFont)->getCollection()); } } else { if (gfxFont->getName()) { dfp = globalParams->getDisplayFont(gfxFont->getName()); } if (!dfp) { // 8-bit font substitution if (gfxFont->isFixedWidth()) { substIdx = 8; } else if (gfxFont->isSerif()) { substIdx = 4; } else { substIdx = 0; } if (gfxFont->isBold()) { substIdx += 2; } if (gfxFont->isItalic()) { substIdx += 1; } substName = new GString(splashOutSubstFonts[substIdx].name); dfp = globalParams->getDisplayFont(substName); delete substName; id->setSubstIdx(substIdx); } } if (!dfp) { error(-1, "Couldn't find a font for '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); goto err2; } switch (dfp->kind) { case displayFontT1: fileName = dfp->t1.fileName; fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1; break; case displayFontTT: fileName = dfp->tt.fileName; fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType; break; } } // load the font file switch (fontType) { case fontType1: if (!(fontFile = fontEngine->loadType1Font( id, fileName->getCString(), fileName == tmpFileName, ((Gfx8BitFont *)gfxFont)->getEncoding()))) { error(-1, "Couldn't create a font for '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); goto err2; } break; case fontType1C: if (!(fontFile = fontEngine->loadType1CFont( id, fileName->getCString(), fileName == tmpFileName, ((Gfx8BitFont *)gfxFont)->getEncoding()))) { error(-1, "Couldn't create a font for '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); goto err2; } break; case fontTrueType: if ((ff = FoFiTrueType::load(fileName->getCString()))) { codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff); n = 256; delete ff; } else { codeToGID = NULL; n = 0; } if (!(fontFile = fontEngine->loadTrueTypeFont( id, fileName->getCString(), fileName == tmpFileName, codeToGID, n))) { error(-1, "Couldn't create a font for '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); goto err2; } break; case fontCIDType0: case fontCIDType0C: if (!(fontFile = fontEngine->loadCIDFont( id, fileName->getCString(), fileName == tmpFileName))) { error(-1, "Couldn't create a font for '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); goto err2; } break; case fontCIDType2: codeToGID = NULL; n = 0; if (dfp) { // create a CID-to-GID mapping, via Unicode if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) { if ((ff = FoFiTrueType::load(fileName->getCString()))) { // look for a Unicode cmap for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) { if ((ff->getCmapPlatform(cmap) == 3 && ff->getCmapEncoding(cmap) == 1) || ff->getCmapPlatform(cmap) == 0) { break; } } if (cmap < ff->getNumCmaps()) { // map CID -> Unicode -> GID n = ctu->getLength(); codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort)); for (code = 0; code < n; ++code) { if (ctu->mapToUnicode(code, uBuf, 8) > 0) { codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]); } else { codeToGID[code] = 0; } } } delete ff; } ctu->decRefCnt(); } else { error(-1, "Couldn't find a mapping to Unicode for font '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); } } else { if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort)); memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), n * sizeof(Gushort)); } } if (!(fontFile = fontEngine->loadTrueTypeFont( id, fileName->getCString(), fileName == tmpFileName, codeToGID, n))) { error(-1, "Couldn't create a font for '%s'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); goto err2; } break; default: // this shouldn't happen goto err2; } } // get the font matrix state->getFontTransMat(&m11, &m12, &m21, &m22); m11 *= state->getHorizScaling(); m12 *= state->getHorizScaling(); // for substituted fonts: adjust the font matrix -- compare the // width of 'm' in the original font and the substituted font substIdx = ((SplashOutFontFileID *)fontFile->getID())->getSubstIdx(); if (substIdx >= 0) { for (code = 0; code < 256; ++code) { if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) && name[0] == 'm' && name[1] == '\0') { break; } } 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; } } } } // create the scaled font mat[0] = m11; mat[1] = -m12; mat[2] = m21; mat[3] = -m22; if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.01) { // avoid a singular (or close-to-singular) matrix mat[0] = 0.01; mat[1] = 0; mat[2] = 0; mat[3] = 0.01; } font = fontEngine->getFont(fontFile, mat); if (tmpFileName) { delete tmpFileName; } return; err2: delete id; err1: if (tmpFileName) { delete tmpFileName; } return;}void SplashOutputDev::stroke(GfxState *state) { SplashPath *path; path = convertPath(state, state->getPath()); splash->stroke(path); delete path;}void SplashOutputDev::fill(GfxState *state) { SplashPath *path; path = convertPath(state, state->getPath()); splash->fill(path, gFalse); delete path;}void SplashOutputDev::eoFill(GfxState *state) { SplashPath *path; path = convertPath(state, state->getPath()); splash->fill(path, gTrue); delete path;}void SplashOutputDev::clip(GfxState *state) { SplashPath *path; path = convertPath(state, state->getPath()); splash->clipToPath(path, gFalse); delete path;}void SplashOutputDev::eoClip(GfxState *state) { SplashPath *path; path = convertPath(state, state->getPath()); splash->clipToPath(path, gTrue); delete path;}SplashPath *SplashOutputDev::convertPath(GfxState *state, GfxPath *path) { SplashPath *sPath; GfxSubpath *subpath; double x1, y1, x2, y2, x3, y3; int i, j; sPath = new SplashPath(); for (i = 0; i < path->getNumSubpaths(); ++i) { subpath = path->getSubpath(i); if (subpath->getNumPoints() > 0) { state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1); sPath->moveTo((SplashCoord)x1, (SplashCoord)y1); j = 1; while (j < subpath->getNumPoints()) { if (subpath->getCurve(j)) { state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1); state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2); state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3); sPath->curveTo((SplashCoord)x1, (SplashCoord)y1, (SplashCoord)x2, (SplashCoord)y2, (SplashCoord)x3, (SplashCoord)y3); j += 3; } else { state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1); sPath->lineTo((SplashCoord)x1, (SplashCoord)y1); ++j; } } if (subpath->isClosed()) { sPath->close(); } } } return sPath;}void SplashOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, Unicode *u, int uLen) { double x1, y1; SplashPath *path; int render; if (needFontUpdate) { updateFont(state); } if (!font) { return; } // check for invisible text -- this is used by Acrobat Capture render = state->getRender(); if (render == 3) { return; } x -= originX; y -= originY; state->transform(x, y, &x1, &y1); // fill if (!(render & 1)) { splash->fillChar((SplashCoord)x1, (SplashCoord)y1, code, font); } // stroke if ((render & 3) == 1 || (render & 3) == 2) { if ((path = font->getGlyphPath(code))) { path->offset((SplashCoord)x1, (SplashCoord)y1); splash->stroke(path); delete path; } } // clip if (render & 4) { path = font->getGlyphPath(code); path->offset((SplashCoord)x1, (SplashCoord)y1); if (textClipPath) { textClipPath->append(path); delete path; } else { textClipPath = path; } }}GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen) { GfxFont *gfxFont; Ref *fontID; double *ctm, *bbox; T3FontCache *t3Font; T3GlyphStack *t3gs; double x1, y1, xMin, yMin, xMax, yMax, xt, yt; int i, j; if (!(gfxFont = state->getFont())) { return gFalse; } fontID = gfxFont->getID(); ctm = state->getCTM(); state->transform(0, 0, &xt, &yt); // is it the first (MRU) font in the cache? if (!(nT3Fonts > 0 && t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) { // is the font elsewhere in the cache? for (i = 1; i < nT3Fonts; ++i) { if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) { t3Font = t3FontCache[i]; for (j = i; j > 0; --j) { t3FontCache[j] = t3FontCache[j - 1]; } t3FontCache[0] = t3Font; break; } } if (i >= nT3Fonts) { // create new entry in the font cache if (nT3Fonts == splashOutT3FontCacheSize) { delete t3FontCache[nT3Fonts - 1]; --nT3Fonts; } for (j = nT3Fonts; j > 0; --j) { t3FontCache[j] = t3FontCache[j - 1]; } ++nT3Fonts; bbox = gfxFont->getFontBBox(); if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) { // broken bounding box -- just take a guess xMin = xt - 5; xMax = xMin + 30; yMax = yt + 15; yMin = yMax - 45; } else { state->transform(bbox[0], bbox[1], &x1, &y1); xMin = xMax = x1; yMin = yMax = y1; state->transform(bbox[0], bbox[3], &x1, &y1); if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } state->transform(bbox[2], bbox[1], &x1, &y1); if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } state->transform(bbox[2], bbox[3], &x1, &y1); if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } } 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, colorMode != splashModeMono1); } } t3Font = t3FontCache[0]; // is the glyph in the cache? i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc; 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], t3Font->cacheData + (i+j) * t3Font->glyphSize, xt, yt); return gTrue; } } // push a new Type 3 glyph record t3gs = new T3GlyphStack(); t3gs->next = t3GlyphStack; t3GlyphStack = t3gs; t3GlyphStack->code = code; t3GlyphStack->x = xt; t3GlyphStack->y = yt; t3GlyphStack->cache = t3Font; t3GlyphStack->cacheTag = NULL; t3GlyphStack->cacheData = NULL; return gFalse;}void SplashOutputDev::endType3Char(GfxState *state) { T3GlyphStack *t3gs; double *ctm; if (t3GlyphStack->cacheTag) { memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(), t3GlyphStack->cache->glyphSize); delete bitmap; delete splash; bitmap = t3GlyphStack->origBitmap; splash = t3GlyphStack->origSplash; ctm = state->getCTM(); state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], t3GlyphStack->origCTM4, t3GlyphStack->origCTM5); drawType3Glyph(t3GlyphStack->cache, t3GlyphStack->cacheTag, t3GlyphStack->cacheData, t3GlyphStack->x, t3GlyphStack->y); } t3gs = t3GlyphStack; t3GlyphStack = t3gs->next; delete t3gs;}void SplashOutputDev::type3D0(GfxState *state, double wx, double wy) {}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -