filters

T1Font.cc

00001 //========================================================================
00002 //
00003 // T1Font.cc
00004 //
00005 // Copyright 2001-2002 Glyph & Cog, LLC
00006 //
00007 //========================================================================
00008 
00009 #include <aconf.h>
00010 
00011 #if HAVE_T1LIB_H
00012 
00013 #ifdef USE_GCC_PRAGMAS
00014 #pragma implementation
00015 #endif
00016 
00017 #include <math.h>
00018 #include <string.h>
00019 #include <X11/Xlib.h>
00020 #include "gmem.h"
00021 #include "GfxState.h"
00022 #include "T1Font.h"
00023 
00024 //------------------------------------------------------------------------
00025 
00026 int T1FontEngine::t1libInitCount = 0;
00027 
00028 //------------------------------------------------------------------------
00029 
00030 T1FontEngine::T1FontEngine(Display *displayA, Visual *visualA, int depthA,
00031                Colormap colormapA, GBool aaA, GBool aaHighA):
00032   SFontEngine(displayA, visualA, depthA, colormapA)
00033 {
00034   static unsigned long grayVals[17] = {
00035     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
00036   };
00037 
00038   ok = gFalse;
00039   aa = aaA;
00040   aaHigh = aaHighA;
00041   //~ for multithreading: need a mutex here
00042   if (t1libInitCount == 0) {
00043     T1_SetBitmapPad(8);
00044     if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE |
00045             T1_NO_AFM)) {
00046       return;
00047     }
00048     if (aa) {
00049       T1_AASetBitsPerPixel(8);
00050       if (aaHigh) {
00051     T1_AASetLevel(T1_AA_HIGH);
00052     T1_AAHSetGrayValues(grayVals);
00053       } else {
00054     T1_AASetLevel(T1_AA_LOW);
00055     T1_AASetGrayValues(0, 1, 2, 3, 4);
00056       }
00057     } else {
00058       T1_AANSetGrayValues(0, 1);
00059     }
00060   }
00061   ++t1libInitCount;
00062   ok = gTrue;
00063 }
00064 
00065 T1FontEngine::~T1FontEngine() {
00066   //~ for multithreading: need a mutex here
00067   if (--t1libInitCount == 0) {
00068     T1_CloseLib();
00069   }
00070 }
00071 
00072 //------------------------------------------------------------------------
00073 
00074 T1FontFile::T1FontFile(T1FontEngine *engineA, char *fontFileName,
00075                char **fontEnc, double *bboxA) {
00076   int encStrSize;
00077   char *encPtr;
00078   int i;
00079 
00080   ok = gFalse;
00081   engine = engineA;
00082   enc = NULL;
00083   encStr = NULL;
00084   for (i = 0; i < 4; ++i) {
00085     bbox[i] = bboxA[i];
00086   }
00087 
00088   // load the font file
00089   if ((id = T1_AddFont(fontFileName)) < 0) {
00090     return;
00091   }
00092   T1_LoadFont(id);
00093 
00094   // reencode it
00095   encStrSize = 0;
00096   for (i = 0; i < 256; ++i) {
00097     if (fontEnc[i]) {
00098       encStrSize += strlen(fontEnc[i]) + 1;
00099     }
00100   }
00101   enc = (char **)gmalloc(257 * sizeof(char *));
00102   encStr = (char *)gmalloc(encStrSize * sizeof(char));
00103   encPtr = encStr;
00104   for (i = 0; i < 256; ++i) {
00105     if (fontEnc[i]) {
00106       strcpy(encPtr, fontEnc[i]);
00107       enc[i] = encPtr;
00108       encPtr += strlen(encPtr) + 1;
00109     } else {
00110       enc[i] = ".notdef";
00111     }
00112   }
00113   enc[256] = "custom";
00114   T1_ReencodeFont(id, enc);
00115 
00116   ok = gTrue;
00117 }
00118 
00119 T1FontFile::~T1FontFile() {
00120   gfree(enc);
00121   gfree(encStr);
00122   if (id >= 0) {
00123     T1_DeleteFont(id);
00124   }
00125 }
00126 
00127 //------------------------------------------------------------------------
00128 
00129 T1Font::T1Font(T1FontFile *fontFileA, double *m) {
00130   T1FontEngine *engine;
00131   T1_TMATRIX matrix;
00132   BBox bbox;
00133   double bbx0, bby0, bbx1, bby1;
00134   int x, y, xMin, xMax, yMin, yMax;
00135   int i;
00136 
00137   ok = gFalse;
00138   fontFile = fontFileA;
00139   engine = fontFile->engine;
00140 
00141   id = T1_CopyFont(fontFile->id);
00142 
00143   // compute font size
00144   size = (float)sqrt(m[2]*m[2] + m[3]*m[3]);
00145 
00146   // transform the four corners of the font bounding box -- the min
00147   // and max values form the bounding box of the transformed font
00148   bbx0 = fontFile->bbox[0];
00149   bby0 = fontFile->bbox[1];
00150   bbx1 = fontFile->bbox[2];
00151   bby1 = fontFile->bbox[3];
00152   // some fonts in PDF files have bboxes which are just plain wrong,
00153   // so we check the font file's bbox too
00154   bbox = T1_GetFontBBox(id);
00155   if (0.001 * bbox.llx < bbx0) {
00156     bbx0 = 0.001 * bbox.llx;
00157   }
00158   if (0.001 * bbox.lly < bby0) {
00159     bby0 = 0.001 * bbox.lly;
00160   }
00161   if (0.001 * bbox.urx > bbx1) {
00162     bbx1 = 0.001 * bbox.urx;
00163   }
00164   if (0.001 * bbox.ury > bby1) {
00165     bby1 = 0.001 * bbox.ury;
00166   }
00167   // some fonts are completely broken, so we fake it (with values
00168   // large enough that most glyphs should fit)
00169   if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) {
00170     bbx0 = bby0 = -0.5;
00171     bbx1 = bby1 = 1.5;
00172   }
00173   x = (int)(m[0] * bbx0 + m[2] * bby0);
00174   xMin = xMax = x;
00175   y = (int)(m[1] * bbx0 + m[3] * bby0);
00176   yMin = yMax = y;
00177   x = (int)(m[0] * bbx0 + m[2] * bby1);
00178   if (x < xMin) {
00179     xMin = x;
00180   } else if (x > xMax) {
00181     xMax = x;
00182   }
00183   y = (int)(m[1] * bbx0 + m[3] * bby1);
00184   if (y < yMin) {
00185     yMin = y;
00186   } else if (y > yMax) {
00187     yMax = y;
00188   }
00189   x = (int)(m[0] * bbx1 + m[2] * bby0);
00190   if (x < xMin) {
00191     xMin = x;
00192   } else if (x > xMax) {
00193     xMax = x;
00194   }
00195   y = (int)(m[1] * bbx1 + m[3] * bby0);
00196   if (y < yMin) {
00197     yMin = y;
00198   } else if (y > yMax) {
00199     yMax = y;
00200   }
00201   x = (int)(m[0] * bbx1 + m[2] * bby1);
00202   if (x < xMin) {
00203     xMin = x;
00204   } else if (x > xMax) {
00205     xMax = x;
00206   }
00207   y = (int)(m[1] * bbx1 + m[3] * bby1);
00208   if (y < yMin) {
00209     yMin = y;
00210   } else if (y > yMax) {
00211     yMax = y;
00212   }
00213   // This is a kludge: some buggy PDF generators embed fonts with
00214   // zero bounding boxes.
00215   if (xMax == xMin) {
00216     xMin = 0;
00217     xMax = (int)size;
00218   }
00219   if (yMax == yMin) {
00220     yMin = 0;
00221     yMax = (int)(1.2 * size);
00222   }
00223   // Another kludge: an unusually large xMin or yMin coordinate is
00224   // probably wrong.
00225   if (xMin > 0) {
00226     xMin = 0;
00227   }
00228   if (yMin > 0) {
00229     yMin = 0;
00230   }
00231   // Another kludge: t1lib doesn't correctly handle fonts with
00232   // real (non-integer) bounding box coordinates.
00233   if (xMax - xMin > 5000) {
00234     xMin = 0;
00235     xMax = (int)size;
00236   }
00237   if (yMax - yMin > 5000) {
00238     yMin = 0;
00239     yMax = (int)(1.2 * size);
00240   }
00241   // this should be (max - min + 1), but we add some padding to
00242   // deal with rounding errors
00243   glyphW = xMax - xMin + 3;
00244   glyphH = yMax - yMin + 3;
00245   if (engine->aa) {
00246     glyphSize = glyphW * glyphH;
00247   } else {
00248     glyphSize = ((glyphW + 7) >> 3) * glyphH;
00249   }
00250 
00251   // set up the glyph pixmap cache
00252   cacheAssoc = 8;
00253   if (glyphSize <= 256) {
00254     cacheSets = 8;
00255   } else if (glyphSize <= 512) {
00256     cacheSets = 4;
00257   } else if (glyphSize <= 1024) {
00258     cacheSets = 2;
00259   } else {
00260     cacheSets = 1;
00261   }
00262   cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
00263   cacheTags = (T1FontCacheTag *)gmalloc(cacheSets * cacheAssoc *
00264                     sizeof(T1FontCacheTag));
00265   for (i = 0; i < cacheSets * cacheAssoc; ++i) {
00266     cacheTags[i].mru = i & (cacheAssoc - 1);
00267   }
00268 
00269   // create the XImage
00270   if (!(image = XCreateImage(engine->display, engine->visual, engine->depth,
00271                  ZPixmap, 0, NULL, glyphW, glyphH, 8, 0))) {
00272     return;
00273   }
00274   image->data = (char *)gmalloc(glyphH * image->bytes_per_line);
00275 
00276   // transform the font
00277   matrix.cxx = m[0] / size;
00278   matrix.cxy = m[1] / size;
00279   matrix.cyx = m[2] / size;
00280   matrix.cyy = m[3] / size;
00281   T1_TransformFont(id, &matrix);
00282 
00283   ok = gTrue;
00284 }
00285 
00286 T1Font::~T1Font() {
00287   gfree(cacheTags);
00288   gfree(cache);
00289   if (image) {
00290     gfree(image->data);
00291     image->data = NULL;
00292     XDestroyImage(image);
00293   }
00294   T1_DeleteFont(id);
00295 }
00296 
00297 GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
00298                int x, int y, int r, int g, int b,
00299                CharCode c, Unicode u) {
00300   T1FontEngine *engine;
00301   XColor xcolor;
00302   int bgR, bgG, bgB;
00303   Gulong colors[17];
00304   Guchar *p;
00305   int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0;
00306   int xx, yy, xx1;
00307   Guchar pix, mPix;
00308   int i;
00309 
00310   engine = fontFile->engine;
00311 
00312   // generate the glyph pixmap
00313   if (!(p = getGlyphPixmap(c, &xOffset, &yOffset, &gw, &gh))) {
00314     return gFalse;
00315   }
00316 
00317   // compute: (x0,y0) = position in destination drawable
00318   //          (x1,y1) = position in glyph image
00319   //          (w0,h0) = size of image transfer
00320   x0 = x - xOffset;
00321   y0 = y - yOffset;
00322   x1 = 0;
00323   y1 = 0;
00324   w0 = gw;
00325   h0 = gh;
00326   if (x0 < 0) {
00327     x1 = -x0;
00328     w0 += x0;
00329     x0 = 0;
00330   }
00331   if (x0 + w0 > w) {
00332     w0 = w - x0;
00333   }
00334   if (w0 < 0) {
00335     return gTrue;
00336   }
00337   if (y0 < 0) {
00338     y1 = -y0;
00339     h0 += y0;
00340     y0 = 0;
00341   }
00342   if (y0 + h0 > h) {
00343     h0 = h - y0;
00344   }
00345   if (h0 < 0) {
00346     return gTrue;
00347   }
00348 
00349   // read the X image
00350   XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
00351            ZPixmap, image, x1, y1);
00352 
00353   if (engine->aa) {
00354 
00355     // compute the colors
00356     xcolor.pixel = XGetPixel(image, x1 + w0/2, y1 + h0/2);
00357     XQueryColor(engine->display, engine->colormap, &xcolor);
00358     bgR = xcolor.red;
00359     bgG = xcolor.green;
00360     bgB = xcolor.blue;
00361     if (engine->aaHigh) {
00362       mPix = 16;
00363       for (i = 1; i <= 16; ++i) {
00364     colors[i] = engine->findColor((i * r + (16 - i) * bgR) / 16,
00365                       (i * g + (16 - i) * bgG) / 16,
00366                       (i * b + (16 - i) * bgB) / 16);
00367       }
00368     } else {
00369       mPix = 4;
00370       colors[1] = engine->findColor((r + 3*bgR) / 4,
00371                     (g + 3*bgG) / 4,
00372                     (b + 3*bgB) / 4);
00373       colors[2] = engine->findColor((r + bgR) / 2,
00374                     (g + bgG) / 2,
00375                     (b + bgB) / 2);
00376       colors[3] = engine->findColor((3*r + bgR) / 4,
00377                     (3*g + bgG) / 4,
00378                     (3*b + bgB) / 4);
00379       colors[4] = engine->findColor(r, g, b);
00380     }
00381 
00382     // stuff the glyph pixmap into the X image
00383     for (yy = 0; yy < gh; ++yy) {
00384       for (xx = 0; xx < gw; ++xx) {
00385     pix = *p++;
00386     if (pix > 0) {
00387       if (pix > mPix) {
00388         pix = mPix;
00389       }
00390       XPutPixel(image, xx, yy, colors[pix]);
00391     }
00392       }
00393     }
00394 
00395   } else {
00396 
00397     // one color
00398     colors[1] = engine->findColor(r, g, b);
00399 
00400     // stuff the glyph bitmap into the X image
00401     for (yy = 0; yy < gh; ++yy) {
00402       for (xx = 0; xx < gw; xx += 8) {
00403     pix = *p++;
00404     for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
00405       if (pix & 0x01) {
00406         XPutPixel(image, xx1, yy, colors[1]);
00407       }
00408       pix >>= 1;
00409     }
00410       }
00411     }
00412 
00413   }
00414 
00415   // draw the X image
00416   XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0);
00417 
00418   return gTrue;
00419 }
00420 
00421 Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h) {
00422   T1FontEngine *engine;
00423   GLYPH *glyph;
00424   int gSize;
00425   int i, j, k;
00426   Guchar *ret;
00427 
00428   engine = fontFile->engine;
00429 
00430   // check the cache
00431   i = (c & (cacheSets - 1)) * cacheAssoc;
00432   for (j = 0; j < cacheAssoc; ++j) {
00433     if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) {
00434       *x = cacheTags[i+j].x;
00435       *y = cacheTags[i+j].y;
00436       *w = cacheTags[i+j].w;
00437       *h = cacheTags[i+j].h;
00438       for (k = 0; k < cacheAssoc; ++k) {
00439     if (k != j &&
00440         (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) {
00441       ++cacheTags[i+k].mru;
00442     }
00443       }
00444       cacheTags[i+j].mru = 0x8000;
00445       return cache + (i+j) * glyphSize;
00446     }
00447   }
00448 
00449   // generate the glyph pixmap
00450   if (engine->aa) {
00451     glyph = T1_AASetChar(id, c, size, NULL);
00452   } else {
00453     glyph = T1_SetChar(id, c, size, NULL);
00454   }
00455   if (!glyph) {
00456     return NULL;
00457   }
00458   *x = -glyph->metrics.leftSideBearing;
00459   *y = glyph->metrics.ascent;
00460   *w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing;
00461   *h = glyph->metrics.ascent - glyph->metrics.descent;
00462   if (*w > glyphW || *h > glyphH) {
00463 #if 1 //~ debug
00464     fprintf(stderr, "Weird t1lib glyph size: %d > %d or %d > %d\n",
00465         *w, glyphW, *h, glyphH);
00466 #endif
00467     return NULL;
00468   }
00469 
00470   // store glyph pixmap in cache
00471   ret = NULL;
00472   for (j = 0; j < cacheAssoc; ++j) {
00473     if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
00474       cacheTags[i+j].mru = 0x8000;
00475       cacheTags[i+j].code = c;
00476       cacheTags[i+j].x = *x;
00477       cacheTags[i+j].y = *y;
00478       cacheTags[i+j].w = *w;
00479       cacheTags[i+j].h = *h;
00480       if (engine->aa) {
00481     gSize = *w * *h;
00482       } else {
00483     gSize = ((*w + 7) >> 3) * *h;
00484       }
00485       ret = cache + (i+j) * glyphSize;
00486       if (glyph->bits) {
00487     memcpy(ret, glyph->bits, gSize);
00488       } else {
00489     memset(ret, 0, gSize);
00490       }
00491     } else {
00492       ++cacheTags[i+j].mru;
00493     }
00494   }
00495   return ret;
00496 }
00497 
00498 GBool T1Font::getCharPath(CharCode c, Unicode u, GfxState *state) {
00499   T1_OUTLINE *outline;
00500   T1_PATHSEGMENT *seg;
00501   T1_BEZIERSEGMENT *bez;
00502   double x, y, x1, y1;
00503 
00504   outline = T1_GetCharOutline(id, c, size, NULL);
00505   x = 0;
00506   y = 0;
00507   for (seg = outline; seg; seg = seg->link) {
00508     switch (seg->type) {
00509     case T1_PATHTYPE_MOVE:
00510       x += seg->dest.x / 65536.0;
00511       y += seg->dest.y / 65536.0;
00512       state->moveTo(x, y);
00513       break;
00514     case T1_PATHTYPE_LINE:
00515       x += seg->dest.x / 65536.0;
00516       y += seg->dest.y / 65536.0;
00517       state->lineTo(x, y);
00518       break;
00519     case T1_PATHTYPE_BEZIER:
00520       bez = (T1_BEZIERSEGMENT *)seg;
00521       x1 = x + bez->dest.x / 65536.0;
00522       y1 = y + bez->dest.y / 65536.0;
00523       state->curveTo(x + bez->B.x / 65536.0, y + bez->B.y / 65536.0,
00524              x + bez->C.x / 65536.0, y + bez->C.y / 65536.0,
00525              x1, y1);
00526       x = x1;
00527       y = y1;
00528       break;
00529     }
00530   }
00531   T1_FreeOutline(outline);
00532   return gTrue;
00533 }
00534 
00535 #endif // HAVE_T1LIB_H
KDE Home | KDE Accessibility Home | Description of Access Keys