]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/T1Font.cc
Reused eog HIG dialog in GPdf.
[evince.git] / pdf / xpdf / T1Font.cc
index a9a67b64e6b3b03d0f7412534fb5f5ba9464c075..a03351d2355d20d20597c0f34497a5dcefcb82b0 100644 (file)
@@ -2,68 +2,88 @@
 //
 // T1Font.cc
 //
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
 //========================================================================
 
-#ifdef __GNUC__
-#pragma implementation
-#endif
+#include <aconf.h>
 
 #if HAVE_T1LIB_H
 
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
 #include <math.h>
 #include <string.h>
 #include <X11/Xlib.h>
 #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