00001
00002
00003
00004
00005
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
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
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
00170
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
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
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
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
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
00296
00297
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
00328 XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
00329 ZPixmap, image, x1, y1);
00330
00331
00332 if (!getGlyphPixmap(c, u)) {
00333 return gFalse;
00334 }
00335
00336 if (engine->aa) {
00337
00338
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
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
00372 colors[1] = engine->findColor(r, g, b);
00373
00374
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
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
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
00418 idx = 0;
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
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)