X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=pdf%2Fxpdf%2FT1Font.cc;h=a03351d2355d20d20597c0f34497a5dcefcb82b0;hb=884f739665dc56e66f51e104350f2affd33f2dd8;hp=a9a67b64e6b3b03d0f7412534fb5f5ba9464c075;hpb=7aac8dc8533347e21311b15186e0af82f1b22fd6;p=evince.git diff --git a/pdf/xpdf/T1Font.cc b/pdf/xpdf/T1Font.cc index a9a67b64..a03351d2 100644 --- a/pdf/xpdf/T1Font.cc +++ b/pdf/xpdf/T1Font.cc @@ -2,68 +2,88 @@ // // T1Font.cc // +// Copyright 2001-2003 Glyph & Cog, LLC +// //======================================================================== -#ifdef __GNUC__ -#pragma implementation -#endif +#include #if HAVE_T1LIB_H +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + #include #include #include #include "gmem.h" -#include "FontEncoding.h" +#include "GfxState.h" #include "T1Font.h" //------------------------------------------------------------------------ -T1FontEngine::T1FontEngine(Display *display, Visual *visual, int depth, - Colormap colormap, GBool aa, GBool aaHigh): - SFontEngine(display, visual, depth, colormap) +int T1FontEngine::t1libInitCount = 0; + +//------------------------------------------------------------------------ + +T1FontEngine::T1FontEngine(Display *displayA, Visual *visualA, int depthA, + Colormap colormapA, GBool aaA, GBool aaHighA): + SFontEngine(displayA, visualA, depthA, colormapA) { static unsigned long grayVals[17] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; ok = gFalse; - T1_SetBitmapPad(8); - if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE | - T1_NO_AFM)) { - return; - } - this->aa = aa; - this->aaHigh = aaHigh; - if (aa) { - T1_AASetBitsPerPixel(8); - if (aaHigh) { - T1_AASetLevel(T1_AA_HIGH); - T1_AAHSetGrayValues(grayVals); + aa = aaA; + aaHigh = aaHighA; + //~ for multithreading: need a mutex here + if (t1libInitCount == 0) { + T1_SetBitmapPad(8); + if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE | + T1_NO_AFM)) { + return; + } + if (aa) { + T1_AASetBitsPerPixel(8); + if (aaHigh) { + T1_AASetLevel(T1_AA_HIGH); + T1_AAHSetGrayValues(grayVals); + } else { + T1_AASetLevel(T1_AA_LOW); + T1_AASetGrayValues(0, 1, 2, 3, 4); + } } else { - T1_AASetLevel(T1_AA_LOW); - T1_AASetGrayValues(0, 1, 2, 3, 4); + T1_AANSetGrayValues(0, 1); } - } else { - T1_AANSetGrayValues(0, 1); } + ++t1libInitCount; ok = gTrue; } T1FontEngine::~T1FontEngine() { - T1_CloseLib(); + //~ for multithreading: need a mutex here + if (--t1libInitCount == 0) { + T1_CloseLib(); + } } //------------------------------------------------------------------------ -T1FontFile::T1FontFile(T1FontEngine *engine, char *fontFileName, - FontEncoding *fontEnc) { +T1FontFile::T1FontFile(T1FontEngine *engineA, char *fontFileName, + char **fontEnc, double *bboxA) { int encStrSize; char *encPtr; int i; ok = gFalse; - this->engine = engine; + engine = engineA; + enc = NULL; + encStr = NULL; + for (i = 0; i < 4; ++i) { + bbox[i] = bboxA[i]; + } // load the font file if ((id = T1_AddFont(fontFileName)) < 0) { @@ -73,26 +93,23 @@ T1FontFile::T1FontFile(T1FontEngine *engine, char *fontFileName, // reencode it encStrSize = 0; - for (i = 0; i < 256 && i < fontEnc->getSize(); ++i) { - if (fontEnc->getCharName(i)) { - encStrSize += strlen(fontEnc->getCharName(i)) + 1; + for (i = 0; i < 256; ++i) { + if (fontEnc[i]) { + encStrSize += strlen(fontEnc[i]) + 1; } } enc = (char **)gmalloc(257 * sizeof(char *)); encStr = (char *)gmalloc(encStrSize * sizeof(char)); encPtr = encStr; - for (i = 0; i < 256 && i < fontEnc->getSize(); ++i) { - if (fontEnc->getCharName(i)) { - strcpy(encPtr, fontEnc->getCharName(i)); + for (i = 0; i < 256; ++i) { + if (fontEnc[i]) { + strcpy(encPtr, fontEnc[i]); enc[i] = encPtr; encPtr += strlen(encPtr) + 1; } else { enc[i] = ".notdef"; } } - for (; i < 256; ++i) { - enc[i] = ".notdef"; - } enc[256] = "custom"; T1_ReencodeFont(id, enc); @@ -102,21 +119,24 @@ T1FontFile::T1FontFile(T1FontEngine *engine, char *fontFileName, T1FontFile::~T1FontFile() { gfree(enc); gfree(encStr); - T1_DeleteFont(id); + if (id >= 0) { + T1_DeleteFont(id); + } } //------------------------------------------------------------------------ -T1Font::T1Font(T1FontFile *fontFile, double *m) { +T1Font::T1Font(T1FontFile *fontFileA, double *m) { T1FontEngine *engine; T1_TMATRIX matrix; BBox bbox; + double bbx0, bby0, bbx1, bby1; int x, y, xMin, xMax, yMin, yMax; int i; ok = gFalse; + fontFile = fontFileA; engine = fontFile->engine; - this->fontFile = fontFile; id = T1_CopyFont(fontFile->id); @@ -125,50 +145,73 @@ T1Font::T1Font(T1FontFile *fontFile, double *m) { // transform the four corners of the font bounding box -- the min // and max values form the bounding box of the transformed font + bbx0 = fontFile->bbox[0]; + bby0 = fontFile->bbox[1]; + bbx1 = fontFile->bbox[2]; + bby1 = fontFile->bbox[3]; + // some fonts in PDF files have bboxes which are just plain wrong, + // so we check the font file's bbox too bbox = T1_GetFontBBox(id); - x = (int)((m[0] * bbox.llx + m[2] * bbox.lly) * 0.001); + if (0.001 * bbox.llx < bbx0) { + bbx0 = 0.001 * bbox.llx; + } + if (0.001 * bbox.lly < bby0) { + bby0 = 0.001 * bbox.lly; + } + if (0.001 * bbox.urx > bbx1) { + bbx1 = 0.001 * bbox.urx; + } + if (0.001 * bbox.ury > bby1) { + bby1 = 0.001 * bbox.ury; + } + // some fonts are completely broken, so we fake it (with values + // large enough that most glyphs should fit) + if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) { + bbx0 = bby0 = -0.5; + bbx1 = bby1 = 1.5; + } + x = (int)(m[0] * bbx0 + m[2] * bby0); xMin = xMax = x; - y = (int)((m[1] * bbox.llx + m[3] * bbox.lly) * 0.001); + y = (int)(m[1] * bbx0 + m[3] * bby0); yMin = yMax = y; - x = (int)((m[0] * bbox.llx + m[2] * bbox.ury) * 0.001); + x = (int)(m[0] * bbx0 + m[2] * bby1); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } - y = (int)((m[1] * bbox.llx + m[3] * bbox.ury) * 0.001); + y = (int)(m[1] * bbx0 + m[3] * bby1); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } - x = (int)((m[0] * bbox.urx + m[2] * bbox.lly) * 0.001); + x = (int)(m[0] * bbx1 + m[2] * bby0); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } - y = (int)((m[1] * bbox.urx + m[3] * bbox.lly) * 0.001); + y = (int)(m[1] * bbx1 + m[3] * bby0); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } - x = (int)((m[0] * bbox.urx + m[2] * bbox.ury) * 0.001); + x = (int)(m[0] * bbx1 + m[2] * bby1); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } - y = (int)((m[1] * bbox.urx + m[3] * bbox.ury) * 0.001); + y = (int)(m[1] * bbx1 + m[3] * bby1); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } -#if 1 //~ - //~ This is a kludge: some buggy PDF generators embed fonts with - //~ zero bounding boxes. + // This is a kludge: some buggy PDF generators embed fonts with + // zero bounding boxes. if (xMax == xMin) { xMin = 0; xMax = (int)size; @@ -177,7 +220,24 @@ T1Font::T1Font(T1FontFile *fontFile, double *m) { yMin = 0; yMax = (int)(1.2 * size); } -#endif + // Another kludge: an unusually large xMin or yMin coordinate is + // probably wrong. + if (xMin > 0) { + xMin = 0; + } + if (yMin > 0) { + yMin = 0; + } + // Another kludge: t1lib doesn't correctly handle fonts with + // real (non-integer) bounding box coordinates. + if (xMax - xMin > 5000) { + xMin = 0; + xMax = (int)size; + } + if (yMax - yMin > 5000) { + yMin = 0; + yMax = (int)(1.2 * size); + } // this should be (max - min + 1), but we add some padding to // deal with rounding errors glyphW = xMax - xMin + 3; @@ -235,12 +295,15 @@ T1Font::~T1Font() { } GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, - int x, int y, int r, int g, int b, Gushort c) { + int x, int y, int r, int g, int b, + CharCode c, Unicode u) { T1FontEngine *engine; XColor xcolor; int bgR, bgG, bgB; Gulong colors[17]; - Guchar *p; + Guchar *bitmap, *p; + GBool tempBitmap; + XImage *img; int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0; int xx, yy, xx1; Guchar pix, mPix; @@ -249,7 +312,8 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, engine = fontFile->engine; // generate the glyph pixmap - if (!(p = getGlyphPixmap(c, &xOffset, &yOffset, &gw, &gh))) { + if (!(bitmap = getGlyphPixmap(c, &xOffset, &yOffset, &gw, &gh, + &tempBitmap))) { return gFalse; } @@ -271,7 +335,7 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, w0 = w - x0; } if (w0 < 0) { - return gTrue; + goto done; } if (y0 < 0) { y1 = -y0; @@ -282,17 +346,29 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, h0 = h - y0; } if (h0 < 0) { - return gTrue; + goto done; + } + + // getGlyphPixmap may have returned a larger-than-cache-entry + // bitmap, in which case we need to allocate a temporary XImage here + if (tempBitmap) { + if (!(img = XCreateImage(engine->display, engine->visual, engine->depth, + ZPixmap, 0, NULL, gw, gh, 8, 0))) { + goto done; + } + img->data = (char *)gmalloc(gh * img->bytes_per_line); + } else { + img = image; } // read the X image XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1, - ZPixmap, image, x1, y1); + ZPixmap, img, x1, y1); if (engine->aa) { // compute the colors - xcolor.pixel = XGetPixel(image, x1, y1); + xcolor.pixel = XGetPixel(img, x1 + w0/2, y1 + h0/2); XQueryColor(engine->display, engine->colormap, &xcolor); bgR = xcolor.red; bgG = xcolor.green; @@ -319,6 +395,7 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, } // stuff the glyph pixmap into the X image + p = bitmap; for (yy = 0; yy < gh; ++yy) { for (xx = 0; xx < gw; ++xx) { pix = *p++; @@ -326,7 +403,7 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, if (pix > mPix) { pix = mPix; } - XPutPixel(image, xx, yy, colors[pix]); + XPutPixel(img, xx, yy, colors[pix]); } } } @@ -337,12 +414,13 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, colors[1] = engine->findColor(r, g, b); // stuff the glyph bitmap into the X image + p = bitmap; for (yy = 0; yy < gh; ++yy) { for (xx = 0; xx < gw; xx += 8) { pix = *p++; for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) { if (pix & 0x01) { - XPutPixel(image, xx1, yy, colors[1]); + XPutPixel(img, xx1, yy, colors[1]); } pix >>= 1; } @@ -352,12 +430,22 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, } // draw the X image - XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0); + XPutImage(engine->display, d, gc, img, x1, y1, x0, y0, w0, h0); + if (tempBitmap) { + gfree(img->data); + img->data = NULL; + XDestroyImage(img); + } + done: + if (tempBitmap) { + gfree(bitmap); + } return gTrue; } -Guchar *T1Font::getGlyphPixmap(Gushort c, int *x, int *y, int *w, int *h) { +Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h, + GBool *tempBitmap) { T1FontEngine *engine; GLYPH *glyph; int gSize; @@ -381,6 +469,7 @@ Guchar *T1Font::getGlyphPixmap(Gushort c, int *x, int *y, int *w, int *h) { } } cacheTags[i+j].mru = 0x8000; + *tempBitmap = gFalse; return cache + (i+j) * glyphSize; } } @@ -394,44 +483,84 @@ Guchar *T1Font::getGlyphPixmap(Gushort c, int *x, int *y, int *w, int *h) { if (!glyph) { return NULL; } + + // copy the glyph into the cache or a temporary bitmap *x = -glyph->metrics.leftSideBearing; *y = glyph->metrics.ascent; *w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing; *h = glyph->metrics.ascent - glyph->metrics.descent; - if (*w > glyphW || *h > glyphH) { -#if 1 //~ - fprintf(stderr, "Weird t1lib glyph size: %d > %d or %d > %d\n", - *w, glyphW, *h, glyphH); -#endif - return NULL; + if (engine->aa) { + gSize = *w * *h; + } else { + gSize = ((*w + 7) >> 3) * *h; } - - // store glyph pixmap in cache - ret = NULL; - for (j = 0; j < cacheAssoc; ++j) { - if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) { - cacheTags[i+j].mru = 0x8000; - cacheTags[i+j].code = c; - cacheTags[i+j].x = *x; - cacheTags[i+j].y = *y; - cacheTags[i+j].w = *w; - cacheTags[i+j].h = *h; - if (engine->aa) { - gSize = *w * *h; - } else { - gSize = ((*w + 7) >> 3) * *h; - } - ret = cache + (i+j) * glyphSize; - if (glyph->bits) { - memcpy(ret, glyph->bits, gSize); + if (*w > glyphW || *h > glyphH) { + // the glyph doesn't fit in the bounding box -- return a + // temporary, uncached bitmap (this shouldn't happen but some + // fonts have incorrect bboxes) + ret = (Guchar *)gmalloc(gSize); + *tempBitmap = gTrue; + } else { + // store glyph pixmap in cache + ret = NULL; // make gcc happy + for (j = 0; j < cacheAssoc; ++j) { + if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) { + cacheTags[i+j].mru = 0x8000; + cacheTags[i+j].code = c; + cacheTags[i+j].x = *x; + cacheTags[i+j].y = *y; + cacheTags[i+j].w = *w; + cacheTags[i+j].h = *h; + ret = cache + (i+j) * glyphSize; } else { - memset(ret, 0, gSize); + ++cacheTags[i+j].mru; } - } else { - ++cacheTags[i+j].mru; } + *tempBitmap = gFalse; + } + if (glyph->bits) { + memcpy(ret, glyph->bits, gSize); + } else { + memset(ret, 0, gSize); } return ret; } +GBool T1Font::getCharPath(CharCode c, Unicode u, GfxState *state) { + T1_OUTLINE *outline; + T1_PATHSEGMENT *seg; + T1_BEZIERSEGMENT *bez; + double x, y, x1, y1; + + outline = T1_GetCharOutline(id, c, size, NULL); + x = 0; + y = 0; + for (seg = outline; seg; seg = seg->link) { + switch (seg->type) { + case T1_PATHTYPE_MOVE: + x += seg->dest.x / 65536.0; + y += seg->dest.y / 65536.0; + state->moveTo(x, y); + break; + case T1_PATHTYPE_LINE: + x += seg->dest.x / 65536.0; + y += seg->dest.y / 65536.0; + state->lineTo(x, y); + break; + case T1_PATHTYPE_BEZIER: + bez = (T1_BEZIERSEGMENT *)seg; + x1 = x + bez->dest.x / 65536.0; + y1 = y + bez->dest.y / 65536.0; + state->curveTo(x + bez->B.x / 65536.0, y + bez->B.y / 65536.0, + x + bez->C.x / 65536.0, y + bez->C.y / 65536.0, + x1, y1); + x = x1; + y = y1; + break; + } + } + T1_FreeOutline(outline); + return gTrue; +} + #endif // HAVE_T1LIB_H