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 <math.h>
00018 #include <string.h>
00019 #include "gmem.h"
00020 #include "freetype/ftoutln.h"
00021 #include "freetype/internal/ftobjs.h"
00022 #if 1 //~ cff cid->gid map
00023 #include "freetype/internal/cfftypes.h"
00024 #include "freetype/internal/tttypes.h"
00025 #endif
00026 #include "GlobalParams.h"
00027 #include "GfxState.h"
00028 #include "FTFont.h"
00029
00030
00031
00032 FTFontEngine::FTFontEngine(Display *displayA, Visual *visualA, int depthA,
00033 Colormap colormapA, GBool aaA):
00034 SFontEngine(displayA, visualA, depthA, colormapA) {
00035
00036 ok = gFalse;
00037 if (FT_Init_FreeType(&lib)) {
00038 return;
00039 }
00040 aa = aaA;
00041 ok = gTrue;
00042 }
00043
00044 FTFontEngine::~FTFontEngine() {
00045 FT_Done_FreeType(lib);
00046 }
00047
00048
00049
00050 FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
00051 char **fontEnc, GBool pdfFontHasEncoding) {
00052 char *name;
00053 int unicodeCmap, macRomanCmap, msSymbolCmap;
00054 int i, j;
00055
00056 ok = gFalse;
00057 engine = engineA;
00058 codeMap = NULL;
00059 if (FT_New_Face(engine->lib, fontFileName, 0, &face)) {
00060 return;
00061 }
00062
00063 if (!strcmp(face->driver->root.clazz->module_name, "type1") ||
00064 !strcmp(face->driver->root.clazz->module_name, "cff")) {
00065
00066 mode = ftFontModeCodeMapDirect;
00067 codeMap = (Guint *)gmalloc(256 * sizeof(Guint));
00068 for (i = 0; i < 256; ++i) {
00069 codeMap[i] = 0;
00070 if ((name = fontEnc[i])) {
00071 codeMap[i] = FT_Get_Name_Index(face, name);
00072 }
00073 }
00074
00075 } else {
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 unicodeCmap = macRomanCmap = msSymbolCmap = 0xffff;
00093 for (i = 0; i < face->num_charmaps; ++i) {
00094 if (face->charmaps[i]->platform_id == 3 &&
00095 face->charmaps[i]->encoding_id == 1) {
00096 unicodeCmap = i;
00097 } else if (face->charmaps[i]->platform_id == 1 &&
00098 face->charmaps[i]->encoding_id == 0) {
00099 macRomanCmap = i;
00100 } else if (face->charmaps[i]->platform_id == 3 &&
00101 face->charmaps[i]->encoding_id == 0) {
00102 msSymbolCmap = i;
00103 }
00104 }
00105 i = 0;
00106 mode = ftFontModeCharCode;
00107 charMapOffset = 0;
00108 if (pdfFontHasEncoding) {
00109 if (unicodeCmap != 0xffff) {
00110 i = unicodeCmap;
00111 mode = ftFontModeUnicode;
00112 } else if (macRomanCmap != 0xffff) {
00113 i = macRomanCmap;
00114 mode = ftFontModeCodeMap;
00115 codeMap = (Guint *)gmalloc(256 * sizeof(Guint));
00116 for (j = 0; j < 256; ++j) {
00117 if (fontEnc[j]) {
00118 codeMap[j] = globalParams->getMacRomanCharCode(fontEnc[j]);
00119 } else {
00120 codeMap[j] = 0;
00121 }
00122 }
00123 }
00124 } else {
00125 if (macRomanCmap != 0xffff) {
00126 i = macRomanCmap;
00127 mode = ftFontModeCharCode;
00128 } else if (msSymbolCmap != 0xffff) {
00129 i = msSymbolCmap;
00130 mode = ftFontModeCharCodeOffset;
00131 charMapOffset = 0xf000;
00132 }
00133 }
00134 if (FT_Set_Charmap(face, face->charmaps[i])) {
00135 return;
00136 }
00137 }
00138
00139 ok = gTrue;
00140 }
00141
00142 FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
00143 Gushort *cidToGIDA, int cidToGIDLenA) {
00144 ok = gFalse;
00145 engine = engineA;
00146 codeMap = NULL;
00147 if (FT_New_Face(engine->lib, fontFileName, 0, &face)) {
00148 return;
00149 }
00150 cidToGID = cidToGIDA;
00151 cidToGIDLen = cidToGIDLenA;
00152 mode = ftFontModeCIDToGIDMap;
00153 ok = gTrue;
00154 }
00155
00156 FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName) {
00157 ok = gFalse;
00158 engine = engineA;
00159 codeMap = NULL;
00160 if (FT_New_Face(engine->lib, fontFileName, 0, &face)) {
00161 return;
00162 }
00163 cidToGID = NULL;
00164 cidToGIDLen = 0;
00165 mode = ftFontModeCFFCharset;
00166 ok = gTrue;
00167 }
00168
00169 FTFontFile::~FTFontFile() {
00170 if (face) {
00171 FT_Done_Face(face);
00172 }
00173 if (codeMap) {
00174 gfree(codeMap);
00175 }
00176 }
00177
00178
00179
00180 FTFont::FTFont(FTFontFile *fontFileA, double *m) {
00181 FTFontEngine *engine;
00182 FT_Face face;
00183 double size, div;
00184 int x, xMin, xMax;
00185 int y, yMin, yMax;
00186 int i;
00187
00188 ok = gFalse;
00189 fontFile = fontFileA;
00190 engine = fontFile->engine;
00191 face = fontFile->face;
00192 if (FT_New_Size(face, &sizeObj)) {
00193 return;
00194 }
00195 face->size = sizeObj;
00196 size = sqrt(m[2]*m[2] + m[3]*m[3]);
00197 if (FT_Set_Pixel_Sizes(face, 0, (int)size)) {
00198 return;
00199 }
00200
00201 div = face->bbox.xMax > 20000 ? 65536 : 1;
00202
00203
00204
00205 x = (int)((m[0] * face->bbox.xMin + m[2] * face->bbox.yMin) /
00206 (div * face->units_per_EM));
00207 xMin = xMax = x;
00208 y = (int)((m[1] * face->bbox.xMin + m[3] * face->bbox.yMin) /
00209 (div * face->units_per_EM));
00210 yMin = yMax = y;
00211 x = (int)((m[0] * face->bbox.xMin + m[2] * face->bbox.yMax) /
00212 (div * face->units_per_EM));
00213 if (x < xMin) {
00214 xMin = x;
00215 } else if (x > xMax) {
00216 xMax = x;
00217 }
00218 y = (int)((m[1] * face->bbox.xMin + m[3] * face->bbox.yMax) /
00219 (div * face->units_per_EM));
00220 if (y < yMin) {
00221 yMin = y;
00222 } else if (y > yMax) {
00223 yMax = y;
00224 }
00225 x = (int)((m[0] * face->bbox.xMax + m[2] * face->bbox.yMin) /
00226 (div * face->units_per_EM));
00227 if (x < xMin) {
00228 xMin = x;
00229 } else if (x > xMax) {
00230 xMax = x;
00231 }
00232 y = (int)((m[1] * face->bbox.xMax + m[3] * face->bbox.yMin) /
00233 (div * face->units_per_EM));
00234 if (y < yMin) {
00235 yMin = y;
00236 } else if (y > yMax) {
00237 yMax = y;
00238 }
00239 x = (int)((m[0] * face->bbox.xMax + m[2] * face->bbox.yMax) /
00240 (div * face->units_per_EM));
00241 if (x < xMin) {
00242 xMin = x;
00243 } else if (x > xMax) {
00244 xMax = x;
00245 }
00246 y = (int)((m[1] * face->bbox.xMax + m[3] * face->bbox.yMax) /
00247 (div * face->units_per_EM));
00248 if (y < yMin) {
00249 yMin = y;
00250 } else if (y > yMax) {
00251 yMax = y;
00252 }
00253
00254
00255 if (xMax == xMin) {
00256 xMin = 0;
00257 xMax = (int)size;
00258 }
00259 if (yMax == yMin) {
00260 yMin = 0;
00261 yMax = (int)(1.2 * size);
00262 }
00263
00264
00265 glyphW = xMax - xMin + 3;
00266 glyphW += glyphW >> 1;
00267 glyphH = yMax - yMin + 3;
00268 glyphH += glyphH >> 1;
00269 if (engine->aa) {
00270 glyphSize = glyphW * glyphH;
00271 } else {
00272 glyphSize = ((glyphW + 7) >> 3) * glyphH;
00273 }
00274
00275
00276 cacheAssoc = 8;
00277 if (glyphSize <= 256) {
00278 cacheSets = 8;
00279 } else if (glyphSize <= 512) {
00280 cacheSets = 4;
00281 } else if (glyphSize <= 1024) {
00282 cacheSets = 2;
00283 } else {
00284 cacheSets = 1;
00285 }
00286 cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
00287 cacheTags = (FTFontCacheTag *)gmalloc(cacheSets * cacheAssoc *
00288 sizeof(FTFontCacheTag));
00289 for (i = 0; i < cacheSets * cacheAssoc; ++i) {
00290 cacheTags[i].mru = i & (cacheAssoc - 1);
00291 }
00292
00293
00294 if (!(image = XCreateImage(engine->display, engine->visual, engine->depth,
00295 ZPixmap, 0, NULL, glyphW, glyphH, 8, 0))) {
00296 return;
00297 }
00298 image->data = (char *)gmalloc(glyphH * image->bytes_per_line);
00299
00300
00301 matrix.xx = (FT_Fixed)((m[0] / size) * 65536);
00302 matrix.yx = (FT_Fixed)((m[1] / size) * 65536);
00303 matrix.xy = (FT_Fixed)((m[2] / size) * 65536);
00304 matrix.yy = (FT_Fixed)((m[3] / size) * 65536);
00305
00306 ok = gTrue;
00307 }
00308
00309 FTFont::~FTFont() {
00310 gfree(cacheTags);
00311 gfree(cache);
00312 gfree(image->data);
00313 image->data = NULL;
00314 XDestroyImage(image);
00315 }
00316
00317 GBool FTFont::drawChar(Drawable d, int w, int h, GC gc,
00318 int x, int y, int r, int g, int b,
00319 CharCode c, Unicode u) {
00320 FTFontEngine *engine;
00321 XColor xcolor;
00322 int bgR, bgG, bgB;
00323 Gulong colors[5];
00324 Guchar *p;
00325 int pix;
00326 int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0;
00327 int xx, yy, xx1;
00328
00329 engine = fontFile->engine;
00330
00331
00332 if (fontFile->mode == ftFontModeUnicode && u == 0) {
00333 return gFalse;
00334 }
00335
00336
00337 if (!(p = getGlyphPixmap(c, u, &xOffset, &yOffset, &gw, &gh))) {
00338 return gFalse;
00339 }
00340
00341
00342
00343
00344 x0 = x - xOffset;
00345 y0 = y - yOffset;
00346 x1 = 0;
00347 y1 = 0;
00348 w0 = gw;
00349 h0 = gh;
00350 if (x0 < 0) {
00351 x1 = -x0;
00352 w0 += x0;
00353 x0 = 0;
00354 }
00355 if (x0 + w0 > w) {
00356 w0 = w - x0;
00357 }
00358 if (w0 < 0) {
00359 return gTrue;
00360 }
00361 if (y0 < 0) {
00362 y1 = -y0;
00363 h0 += y0;
00364 y0 = 0;
00365 }
00366 if (y0 + h0 > h) {
00367 h0 = h - y0;
00368 }
00369 if (h0 < 0) {
00370 return gTrue;
00371 }
00372
00373
00374 XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
00375 ZPixmap, image, x1, y1);
00376
00377 if (engine->aa) {
00378
00379
00380 xcolor.pixel = XGetPixel(image, x1 + w0/2, y1 + h0/2);
00381 XQueryColor(engine->display, engine->colormap, &xcolor);
00382 bgR = xcolor.red;
00383 bgG = xcolor.green;
00384 bgB = xcolor.blue;
00385 colors[1] = engine->findColor((r + 3*bgR) / 4,
00386 (g + 3*bgG) / 4,
00387 (b + 3*bgB) / 4);
00388 colors[2] = engine->findColor((r + bgR) / 2,
00389 (g + bgG) / 2,
00390 (b + bgB) / 2);
00391 colors[3] = engine->findColor((3*r + bgR) / 4,
00392 (3*g + bgG) / 4,
00393 (3*b + bgB) / 4);
00394 colors[4] = engine->findColor(r, g, b);
00395
00396
00397 for (yy = 0; yy < gh; ++yy) {
00398 for (xx = 0; xx < gw; ++xx) {
00399 pix = *p++ & 0xff;
00400
00401
00402
00403 pix = ((pix + 10) * 5) / 256;
00404 if (pix > 4) {
00405 pix = 4;
00406 }
00407 if (pix > 0) {
00408 XPutPixel(image, xx, yy, colors[pix]);
00409 }
00410 }
00411 }
00412
00413 } else {
00414
00415
00416 colors[1] = engine->findColor(r, g, b);
00417
00418
00419 for (yy = 0; yy < gh; ++yy) {
00420 for (xx = 0; xx < gw; xx += 8) {
00421 pix = *p++;
00422 for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
00423 if (pix & 0x80) {
00424 XPutPixel(image, xx1, yy, colors[1]);
00425 }
00426 pix <<= 1;
00427 }
00428 }
00429 }
00430
00431 }
00432
00433
00434 XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0);
00435
00436 return gTrue;
00437 }
00438
00439 Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u,
00440 int *x, int *y, int *w, int *h) {
00441 FT_GlyphSlot slot;
00442 FT_UInt idx;
00443 int rowSize;
00444 int i, j, k;
00445 Guchar *ret, *p, *q;
00446
00447
00448 i = (c & (cacheSets - 1)) * cacheAssoc;
00449 for (j = 0; j < cacheAssoc; ++j) {
00450 if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) {
00451 *x = cacheTags[i+j].x;
00452 *y = cacheTags[i+j].y;
00453 *w = cacheTags[i+j].w;
00454 *h = cacheTags[i+j].h;
00455 for (k = 0; k < cacheAssoc; ++k) {
00456 if (k != j &&
00457 (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) {
00458 ++cacheTags[i+k].mru;
00459 }
00460 }
00461 cacheTags[i+j].mru = 0x8000;
00462 return cache + (i+j) * glyphSize;
00463 }
00464 }
00465
00466
00467 fontFile->face->size = sizeObj;
00468 FT_Set_Transform(fontFile->face, &matrix, NULL);
00469 slot = fontFile->face->glyph;
00470 idx = getGlyphIndex(c, u);
00471
00472 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
00473 if (FT_Load_Glyph(fontFile->face, idx, FT_LOAD_DEFAULT)) {
00474 return gFalse;
00475 }
00476 #else
00477
00478
00479
00480
00481 if (FT_Load_Glyph(fontFile->face, idx,
00482 fontFile->engine->aa ? FT_LOAD_NO_HINTING
00483 : FT_LOAD_DEFAULT)) {
00484 return gFalse;
00485 }
00486 #endif
00487 if (FT_Render_Glyph(slot,
00488 fontFile->engine->aa ? ft_render_mode_normal :
00489 ft_render_mode_mono)) {
00490 return gFalse;
00491 }
00492 *x = -slot->bitmap_left;
00493 *y = slot->bitmap_top;
00494 *w = slot->bitmap.width;
00495 *h = slot->bitmap.rows;
00496 if (*w > glyphW || *h > glyphH) {
00497 #if 1 //~ debug
00498 fprintf(stderr, "Weird FreeType glyph size: %d > %d or %d > %d\n",
00499 *w, glyphW, *h, glyphH);
00500 #endif
00501 return NULL;
00502 }
00503
00504
00505 ret = NULL;
00506 for (j = 0; j < cacheAssoc; ++j) {
00507 if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
00508 cacheTags[i+j].mru = 0x8000;
00509 cacheTags[i+j].code = c;
00510 cacheTags[i+j].x = *x;
00511 cacheTags[i+j].y = *y;
00512 cacheTags[i+j].w = *w;
00513 cacheTags[i+j].h = *h;
00514 if (fontFile->engine->aa) {
00515 rowSize = *w;
00516 } else {
00517 rowSize = (*w + 7) >> 3;
00518 }
00519 ret = cache + (i+j) * glyphSize;
00520 for (k = 0, p = ret, q = slot->bitmap.buffer;
00521 k < slot->bitmap.rows;
00522 ++k, p += rowSize, q += slot->bitmap.pitch) {
00523 memcpy(p, q, rowSize);
00524 }
00525 } else {
00526 ++cacheTags[i+j].mru;
00527 }
00528 }
00529 return ret;
00530 }
00531
00532 GBool FTFont::getCharPath(CharCode c, Unicode u, GfxState *state) {
00533 static FT_Outline_Funcs outlineFuncs = {
00534 &charPathMoveTo,
00535 &charPathLineTo,
00536 &charPathConicTo,
00537 &charPathCubicTo,
00538 0, 0
00539 };
00540 FT_GlyphSlot slot;
00541 FT_UInt idx;
00542 FT_Glyph glyph;
00543
00544 fontFile->face->size = sizeObj;
00545 FT_Set_Transform(fontFile->face, &matrix, NULL);
00546 slot = fontFile->face->glyph;
00547 idx = getGlyphIndex(c, u);
00548 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
00549 if (FT_Load_Glyph(fontFile->face, idx, FT_LOAD_DEFAULT)) {
00550 return gFalse;
00551 }
00552 #else
00553
00554
00555
00556
00557 if (FT_Load_Glyph(fontFile->face, idx,
00558 fontFile->engine->aa ? FT_LOAD_NO_HINTING
00559 : FT_LOAD_DEFAULT)) {
00560 return gFalse;
00561 }
00562 #endif
00563 if (FT_Get_Glyph(slot, &glyph)) {
00564 return gFalse;
00565 }
00566 FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
00567 &outlineFuncs, state);
00568 return gTrue;
00569 }
00570
00571 int FTFont::charPathMoveTo(FT_Vector *pt, void *state) {
00572 ((GfxState *)state)->moveTo(pt->x / 64.0, -pt->y / 64.0);
00573 return 0;
00574 }
00575
00576 int FTFont::charPathLineTo(FT_Vector *pt, void *state) {
00577 ((GfxState *)state)->lineTo(pt->x / 64.0, -pt->y / 64.0);
00578 return 0;
00579 }
00580
00581 int FTFont::charPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *state) {
00582 double x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
00583
00584 x0 = ((GfxState *)state)->getCurX();
00585 y0 = ((GfxState *)state)->getCurY();
00586 xc = ctrl->x / 64.0;
00587 yc = -ctrl->y / 64.0;
00588 x3 = pt->x / 64.0;
00589 y3 = -pt->y / 64.0;
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607 x1 = (1.0 / 3.0) * (x0 + 2 * xc);
00608 y1 = (1.0 / 3.0) * (y0 + 2 * yc);
00609 x2 = (1.0 / 3.0) * (2 * xc + x3);
00610 y2 = (1.0 / 3.0) * (2 * yc + y3);
00611
00612 ((GfxState *)state)->curveTo(x1, y1, x2, y2, x3, y3);
00613 return 0;
00614 }
00615
00616 int FTFont::charPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2,
00617 FT_Vector *pt, void *state) {
00618 ((GfxState *)state)->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0,
00619 ctrl2->x / 64.0, -ctrl2->y / 64.0,
00620 pt->x / 64.0, -pt->y / 64.0);
00621 return 0;
00622 }
00623
00624 FT_UInt FTFont::getGlyphIndex(CharCode c, Unicode u) {
00625 FT_UInt idx;
00626 int j;
00627
00628 idx = 0;
00629 switch (fontFile->mode) {
00630 case ftFontModeUnicode:
00631 idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)u);
00632 break;
00633 case ftFontModeCharCode:
00634 idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)c);
00635 break;
00636 case ftFontModeCharCodeOffset:
00637 idx = FT_Get_Char_Index(fontFile->face,
00638 (FT_ULong)(c + fontFile->charMapOffset));
00639 break;
00640 case ftFontModeCodeMap:
00641 if (c <= 0xff) {
00642 idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)fontFile->codeMap[c]);
00643 } else {
00644 idx = 0;
00645 }
00646 break;
00647 case ftFontModeCodeMapDirect:
00648 if (c <= 0xff) {
00649 idx = (FT_UInt)fontFile->codeMap[c];
00650 } else {
00651 idx = 0;
00652 }
00653 break;
00654 case ftFontModeCIDToGIDMap:
00655 if (fontFile->cidToGIDLen) {
00656 if ((int)c < fontFile->cidToGIDLen) {
00657 idx = (FT_UInt)fontFile->cidToGID[c];
00658 } else {
00659 idx = (FT_UInt)0;
00660 }
00661 } else {
00662 idx = (FT_UInt)c;
00663 }
00664 break;
00665 case ftFontModeCFFCharset:
00666 #if 1 //~ cff cid->gid map
00667 #if FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 0
00668 CFF_Font *cff = (CFF_Font *)((TT_Face)fontFile->face)->extra.data;
00669 #else
00670 CFF_Font cff = (CFF_Font)((TT_Face)fontFile->face)->extra.data;
00671 #endif
00672 idx = 0;
00673 for (j = 0; j < (int)cff->num_glyphs; ++j) {
00674 if (cff->charset.sids[j] == c) {
00675 idx = j;
00676 break;
00677 }
00678 }
00679 #endif
00680 break;
00681 }
00682 return idx;
00683 }
00684
00685 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)