filters

TTFont.cc

00001 //========================================================================
00002 //
00003 // TTFont.cc
00004 //
00005 // Copyright 2001-2002 Glyph & Cog, LLC
00006 //
00007 //========================================================================
00008 
00009 #include <aconf.h>
00010 
00011 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00012 
00013 #ifdef USE_GCC_PRAGMAS
00014 #pragma implementation
00015 #endif
00016 
00017 #include <string.h>
00018 #include "gmem.h"
00019 #include "GlobalParams.h"
00020 #include "TTFont.h"
00021 
00022 //------------------------------------------------------------------------
00023 
00024 TTFontEngine::TTFontEngine(Display *displayA, Visual *visualA, int depthA,
00025                Colormap colormapA, GBool aaA):
00026   SFontEngine(displayA, visualA, depthA, colormapA) {
00027   static TT_Byte ttPalette[5] = {0, 1, 2, 3, 4};
00028 
00029   ok = gFalse;
00030   if (TT_Init_FreeType(&engine)) {
00031     return;
00032   }
00033   aa = aaA;
00034   if (aa) {
00035     if (TT_Set_Raster_Gray_Palette(engine, ttPalette)) {
00036       return;
00037     }
00038   }
00039   ok = gTrue;
00040 }
00041 
00042 TTFontEngine::~TTFontEngine() {
00043   TT_Done_FreeType(engine);
00044 }
00045 
00046 //------------------------------------------------------------------------
00047 
00048 TTFontFile::TTFontFile(TTFontEngine *engineA, char *fontFileName,
00049                char **fontEnc, GBool pdfFontHasEncoding) {
00050   TT_Face_Properties props;
00051   TT_UShort unicodeCmap, macRomanCmap, msSymbolCmap;
00052   TT_UShort platform, encoding, i;
00053   int j;
00054 
00055   ok = gFalse;
00056   engine = engineA;
00057   codeMap = NULL;
00058   if (TT_Open_Face(engine->engine, fontFileName, &face)) {
00059     return;
00060   }
00061   if (TT_Get_Face_Properties(face, &props)) {
00062     return;
00063   }
00064 
00065   // To match up with the Adobe-defined behaviour, we choose a cmap
00066   // like this:
00067   // 1. If the PDF font has an encoding:
00068   //    1a. If the TrueType font has a Microsoft Unicode cmap, use it,
00069   //        and use the Unicode indexes, not the char codes.
00070   //    1b. If the TrueType font has a Macintosh Roman cmap, use it,
00071   //        and reverse map the char names through MacRomanEncoding to
00072   //        get char codes.
00073   // 2. If the PDF font does not have an encoding:
00074   //    2a. If the TrueType font has a Macintosh Roman cmap, use it,
00075   //        and use char codes directly.
00076   //    2b. If the TrueType font has a Microsoft Symbol cmap, use it,
00077   //        and use (0xf000 + char code).
00078   // 3. If none of these rules apply, use the first cmap and hope for
00079   //    the best (this shouldn't happen).
00080   unicodeCmap = macRomanCmap = msSymbolCmap = 0xffff;
00081   for (i = 0; i < props.num_CharMaps; ++i) {
00082     if (!TT_Get_CharMap_ID(face, i, &platform, &encoding)) {
00083       if (platform == 3 && encoding == 1) {
00084     unicodeCmap = i;
00085       } else if (platform == 1 && encoding == 0) {
00086     macRomanCmap = i;
00087       } else if (platform == 3 && encoding == 0) {
00088     msSymbolCmap = i;
00089       }
00090     }
00091   }
00092   i = 0;
00093   mode = ttFontModeCharCode;
00094   charMapOffset = 0;
00095   if (pdfFontHasEncoding) {
00096     if (unicodeCmap != 0xffff) {
00097       i = unicodeCmap;
00098       mode = ttFontModeUnicode;
00099     } else if (macRomanCmap != 0xffff) {
00100       i = macRomanCmap;
00101       mode = ttFontModeCodeMap;
00102       codeMap = (Guchar *)gmalloc(256 * sizeof(Guchar));
00103       for (j = 0; j < 256; ++j) {
00104     if (fontEnc[j]) {
00105       codeMap[j] = (Guchar)globalParams->getMacRomanCharCode(fontEnc[j]);
00106     } else {
00107       codeMap[j] = 0;
00108     }
00109       }
00110     }
00111   } else {
00112     if (macRomanCmap != 0xffff) {
00113       i = macRomanCmap;
00114       mode = ttFontModeCharCode;
00115     } else if (msSymbolCmap != 0xffff) {
00116       i = msSymbolCmap;
00117       mode = ttFontModeCharCodeOffset;
00118       charMapOffset = 0xf000;
00119     }
00120   }
00121   TT_Get_CharMap(face, i, &charMap);
00122 
00123   ok = gTrue;
00124 }
00125 
00126 TTFontFile::TTFontFile(TTFontEngine *engineA, char *fontFileName,
00127                Gushort *cidToGIDA, int cidToGIDLenA) {
00128   ok = gFalse;
00129   engine = engineA;
00130   codeMap = NULL;
00131   cidToGID = cidToGIDA;
00132   cidToGIDLen = cidToGIDLenA;
00133   if (TT_Open_Face(engine->engine, fontFileName, &face)) {
00134     return;
00135   }
00136   mode = ttFontModeCIDToGIDMap;
00137   ok = gTrue;
00138 }
00139 
00140 TTFontFile::~TTFontFile() {
00141   TT_Close_Face(face);
00142   if (codeMap) {
00143     gfree(codeMap);
00144   }
00145 }
00146 
00147 //------------------------------------------------------------------------
00148 
00149 TTFont::TTFont(TTFontFile *fontFileA, double *m) {
00150   TTFontEngine *engine;
00151   TT_Face_Properties props;
00152   TT_Instance_Metrics metrics;
00153   int x, xMin, xMax;
00154   int y, yMin, yMax;
00155   int i;
00156 
00157   ok = gFalse;
00158   fontFile = fontFileA;
00159   engine = fontFile->engine;
00160   if (TT_New_Instance(fontFile->face, &instance) ||
00161       TT_Set_Instance_Resolutions(instance, 72, 72) ||
00162       TT_Set_Instance_CharSize(instance, 1000 * 64) ||
00163       TT_New_Glyph(fontFile->face, &glyph) ||
00164       TT_Get_Face_Properties(fontFile->face, &props) ||
00165       TT_Get_Instance_Metrics(instance, &metrics)) {
00166     return;
00167   }
00168 
00169   // transform the four corners of the font bounding box -- the min
00170   // and max values form the bounding box of the transformed font
00171   x = (int)((m[0] * props.header->xMin + m[2] * props.header->yMin) *
00172         0.001 * metrics.x_ppem / props.header->Units_Per_EM);
00173   xMin = xMax = x;
00174   y = (int)((m[1] * props.header->xMin + m[3] * props.header->yMin) *
00175         0.001 * metrics.x_ppem / props.header->Units_Per_EM);
00176   yMin = yMax = y;
00177   x = (int)((m[0] * props.header->xMin + m[2] * props.header->yMax) *
00178         0.001 * metrics.x_ppem / props.header->Units_Per_EM);
00179   if (x < xMin) {
00180     xMin = x;
00181   } else if (x > xMax) {
00182     xMax = x;
00183   }
00184   y = (int)((m[1] * props.header->xMin + m[3] * props.header->yMax) *
00185         0.001 * metrics.x_ppem / props.header->Units_Per_EM);
00186   if (y < yMin) {
00187     yMin = y;
00188   } else if (y > yMax) {
00189     yMax = y;
00190   }
00191   x = (int)((m[0] * props.header->xMax + m[2] * props.header->yMin) *
00192         0.001 * metrics.x_ppem / props.header->Units_Per_EM);
00193   if (x < xMin) {
00194     xMin = x;
00195   } else if (x > xMax) {
00196     xMax = x;
00197   }
00198   y = (int)((m[1] * props.header->xMax + m[3] * props.header->yMin) *
00199         0.001 * metrics.x_ppem / props.header->Units_Per_EM);
00200   if (y < yMin) {
00201     yMin = y;
00202   } else if (y > yMax) {
00203     yMax = y;
00204   }
00205   x = (int)((m[0] * props.header->xMax + m[2] * props.header->yMax) *
00206         0.001 * metrics.x_ppem / props.header->Units_Per_EM);
00207   if (x < xMin) {
00208     xMin = x;
00209   } else if (x > xMax) {
00210     xMax = x;
00211   }
00212   y = (int)((m[1] * props.header->xMax + m[3] * props.header->yMax) *
00213         0.001 * metrics.x_ppem / props.header->Units_Per_EM);
00214   if (y < yMin) {
00215     yMin = y;
00216   } else if (y > yMax) {
00217     yMax = y;
00218   }
00219   xOffset = -xMin;
00220   yOffset = -yMin;
00221   ras.width = xMax - xMin + 1;
00222   ras.rows = yMax - yMin + 1;
00223 
00224   // set up the Raster_Map structure
00225   if (engine->aa) {
00226     ras.width = (ras.width + 3) & ~3;
00227     ras.cols = ras.width;
00228   } else {
00229     ras.width = (ras.width + 7) & ~7;
00230     ras.cols = ras.width >> 3;
00231   }
00232   ras.flow = TT_Flow_Down;
00233   ras.size = ras.rows * ras.cols;
00234   ras.bitmap = gmalloc(ras.size);
00235 
00236   // set up the glyph pixmap cache
00237   cacheAssoc = 8;
00238   if (ras.size <= 256) {
00239     cacheSets = 8;
00240   } else if (ras.size <= 512) {
00241     cacheSets = 4;
00242   } else if (ras.size <= 1024) {
00243     cacheSets = 2;
00244   } else {
00245     cacheSets = 1;
00246   }
00247   cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * ras.size);
00248   cacheTags = (TTFontCacheTag *)gmalloc(cacheSets * cacheAssoc *
00249                     sizeof(TTFontCacheTag));
00250   for (i = 0; i < cacheSets * cacheAssoc; ++i) {
00251     cacheTags[i].mru = i & (cacheAssoc - 1);
00252   }
00253 
00254   // create the XImage
00255   if (!(image = XCreateImage(engine->display, engine->visual, engine->depth,
00256                  ZPixmap, 0, NULL, ras.width, ras.rows, 8, 0))) {
00257     return;
00258   }
00259   image->data = (char *)gmalloc(ras.rows * image->bytes_per_line);
00260 
00261   // compute the transform matrix
00262   matrix.xx = (TT_Fixed)(m[0] * 65.536);
00263   matrix.yx = (TT_Fixed)(m[1] * 65.536);
00264   matrix.xy = (TT_Fixed)(m[2] * 65.536);
00265   matrix.yy = (TT_Fixed)(m[3] * 65.536);
00266 
00267   ok = gTrue;
00268 }
00269 
00270 TTFont::~TTFont() {
00271   gfree(cacheTags);
00272   gfree(cache);
00273   gfree(image->data);
00274   image->data = NULL;
00275   XDestroyImage(image);
00276   gfree(ras.bitmap);
00277   TT_Done_Glyph(glyph);
00278   TT_Done_Instance(instance);
00279 }
00280 
00281 GBool TTFont::drawChar(Drawable d, int w, int h, GC gc,
00282                int x, int y, int r, int g, int b,
00283                CharCode c, Unicode u) {
00284   TTFontEngine *engine;
00285   XColor xcolor;
00286   int bgR, bgG, bgB;
00287   Gulong colors[5];
00288   TT_Byte *p;
00289   TT_Byte pix;
00290   int xx, yy, xx1;
00291   int x0, y0, x1, y1, w0, h0;
00292 
00293   engine = fontFile->engine;
00294 
00295   // compute: (x0,y0) = position in destination drawable
00296   //          (x1,y1) = position in glyph image
00297   //          (w0,h0) = size of image transfer
00298   x0 = x - xOffset;
00299   y0 = y - (ras.rows - yOffset);
00300   x1 = 0;
00301   y1 = 0;
00302   w0 = ras.width;
00303   h0 = ras.rows;
00304   if (x0 < 0) {
00305     x1 = -x0;
00306     w0 += x0;
00307     x0 = 0;
00308   }
00309   if (x0 + w0 > w) {
00310     w0 = w - x0;
00311   }
00312   if (w0 < 0) {
00313     return gTrue;
00314   }
00315   if (y0 < 0) {
00316     y1 = -y0;
00317     h0 += y0;
00318     y0 = 0;
00319   }
00320   if (y0 + h0 > h) {
00321     h0 = h - y0;
00322   }
00323   if (h0 < 0) {
00324     return gTrue;
00325   }
00326 
00327   // read the X image
00328   XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
00329            ZPixmap, image, x1, y1);
00330 
00331   // generate the glyph pixmap
00332   if (!getGlyphPixmap(c, u)) {
00333     return gFalse;
00334   }
00335 
00336   if (engine->aa) {
00337 
00338     // compute the colors
00339     xcolor.pixel = XGetPixel(image, x1 + w0/2, y1 + h0/2);
00340     XQueryColor(engine->display, engine->colormap, &xcolor);
00341     bgR = xcolor.red;
00342     bgG = xcolor.green;
00343     bgB = xcolor.blue;
00344     colors[1] = engine->findColor((r + 3*bgR) / 4,
00345                   (g + 3*bgG) / 4,
00346                   (b + 3*bgB) / 4);
00347     colors[2] = engine->findColor((r + bgR) / 2,
00348                   (g + bgG) / 2,
00349                   (b + bgB) / 2);
00350     colors[3] = engine->findColor((3*r + bgR) / 4,
00351                   (3*g + bgG) / 4,
00352                   (3*b + bgB) / 4);
00353     colors[4] = engine->findColor(r, g, b);
00354 
00355     // stuff the glyph pixmap into the X image
00356     p = (TT_Byte *)ras.bitmap;
00357     for (yy = 0; yy < ras.rows; ++yy) {
00358       for (xx = 0; xx < ras.width; ++xx) {
00359     pix = *p++;
00360     if (pix > 0) {
00361       if (pix > 4) {
00362         pix = 4;
00363       }
00364       XPutPixel(image, xx, yy, colors[pix]);
00365     }
00366       }
00367     }
00368 
00369   } else {
00370 
00371     // one color
00372     colors[1] = engine->findColor(r, g, b);
00373 
00374     // stuff the glyph bitmap into the X image
00375     p = (TT_Byte *)ras.bitmap;
00376     for (yy = 0; yy < ras.rows; ++yy) {
00377       for (xx = 0; xx < ras.width; xx += 8) {
00378     pix = *p++;
00379     for (xx1 = xx; xx1 < xx + 8 && xx1 < ras.width; ++xx1) {
00380       if (pix & 0x80) {
00381         XPutPixel(image, xx1, yy, colors[1]);
00382       }
00383       pix <<= 1;
00384     }
00385       }
00386     }
00387 
00388   }
00389 
00390   // draw the X image
00391   XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0);
00392 
00393   return gTrue;
00394 }
00395 
00396 GBool TTFont::getGlyphPixmap(CharCode c, Unicode u) {
00397   TT_UShort idx;
00398   TT_Outline outline;
00399   int i, j, k;
00400 
00401   // check the cache
00402   i = (c & (cacheSets - 1)) * cacheAssoc;
00403   for (j = 0; j < cacheAssoc; ++j) {
00404     if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) {
00405       memcpy(ras.bitmap, cache + (i+j) * ras.size, ras.size);
00406       for (k = 0; k < cacheAssoc; ++k) {
00407     if (k != j &&
00408         (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) {
00409       ++cacheTags[i+k].mru;
00410     }
00411       }
00412       cacheTags[i+j].mru = 0x8000;
00413       return gTrue;
00414     }
00415   }
00416 
00417   // generate the glyph pixmap or bitmap
00418   idx = 0; // make gcc happy
00419   switch (fontFile->mode) {
00420   case ttFontModeUnicode:
00421     idx = TT_Char_Index(fontFile->charMap, (TT_UShort)u);
00422     break;
00423   case ttFontModeCharCode:
00424     idx = TT_Char_Index(fontFile->charMap, (TT_UShort)c);
00425     break;
00426   case ttFontModeCharCodeOffset:
00427     idx = TT_Char_Index(fontFile->charMap,
00428             (TT_UShort)(c + fontFile->charMapOffset));
00429     break;
00430   case ttFontModeCodeMap:
00431     if (c <= 0xff) {
00432       idx = TT_Char_Index(fontFile->charMap,
00433               (TT_UShort)(fontFile->codeMap[c] & 0xff));
00434     } else {
00435       idx = 0;
00436     }
00437     break;
00438   case ttFontModeCIDToGIDMap:
00439     if (fontFile->cidToGIDLen) {
00440       if ((int)c < fontFile->cidToGIDLen) {
00441     idx = (TT_UShort)fontFile->cidToGID[c];
00442       } else {
00443     idx = (TT_UShort)0;
00444       }
00445     } else {
00446       idx = (TT_UShort)c;
00447     }
00448     break;
00449   }
00450   if (TT_Load_Glyph(instance, glyph, idx, TTLOAD_DEFAULT) ||
00451       TT_Get_Glyph_Outline(glyph, &outline)) {
00452     return gFalse;
00453   }
00454   TT_Transform_Outline(&outline, &matrix);
00455   memset(ras.bitmap, 0, ras.size);
00456   if (fontFile->engine->aa) {
00457     if (TT_Get_Glyph_Pixmap(glyph, &ras, xOffset * 64, yOffset * 64)) {
00458       return gFalse;
00459     }
00460   } else {
00461     if (TT_Get_Glyph_Bitmap(glyph, &ras, xOffset * 64, yOffset * 64)) {
00462       return gFalse;
00463     }
00464   }
00465 
00466   // store glyph pixmap in cache
00467   for (j = 0; j < cacheAssoc; ++j) {
00468     if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
00469       cacheTags[i+j].mru = 0x8000;
00470       cacheTags[i+j].code = c;
00471       memcpy(cache + (i+j) * ras.size, ras.bitmap, ras.size);
00472     } else {
00473       ++cacheTags[i+j].mru;
00474     }
00475   }
00476 
00477   return gTrue;
00478 }
00479 
00480 #endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
KDE Home | KDE Accessibility Home | Description of Access Keys