1 //========================================================================
5 // Copyright 2001-2003 Glyph & Cog, LLC
7 //========================================================================
11 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
13 #ifdef USE_GCC_PRAGMAS
14 #pragma implementation
20 #include "freetype/ftoutln.h"
21 #include "freetype/internal/ftobjs.h"
22 #if 1 //~ cff cid->gid map
23 #include "freetype/internal/cfftypes.h"
24 #include "freetype/internal/tttypes.h"
26 #include "GlobalParams.h"
30 //------------------------------------------------------------------------
32 FTFontEngine::FTFontEngine(Display *displayA, Visual *visualA, int depthA,
33 Colormap colormapA, GBool aaA):
34 SFontEngine(displayA, visualA, depthA, colormapA) {
37 if (FT_Init_FreeType(&lib)) {
44 FTFontEngine::~FTFontEngine() {
45 FT_Done_FreeType(lib);
48 //------------------------------------------------------------------------
50 FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
51 char **fontEnc, Gushort *codeToGID) {
61 if (FT_New_Face(engine->lib, fontFileName, 0, &face)) {
65 if (!strcmp(face->driver->root.clazz->module_name, "type1") ||
66 !strcmp(face->driver->root.clazz->module_name, "cff")) {
67 mode = ftFontModeCodeMapDirect;
68 codeMap = (Guint *)gmalloc(256 * sizeof(Guint));
69 for (i = 0; i < 256; ++i) {
71 if ((name = fontEnc[i])) {
72 codeMap[i] = FT_Get_Name_Index(face, name);
77 mode = ftFontModeCodeMapDirect;
78 codeMap = (Guint *)gmalloc(256 * sizeof(Guint));
79 for (i = 0; i < 256; ++i) {
80 codeMap[i] = (int)codeToGID[i];
87 FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
88 Gushort *cidToGIDA, int cidToGIDLenA, GBool embedded) {
97 if (FT_New_Face(engine->lib, fontFileName, 0, &face)) {
100 cidToGIDLen = cidToGIDLenA;
101 cidToGID = (Gushort *)gmalloc(cidToGIDLen * sizeof(Gushort));
102 memcpy(cidToGID, cidToGIDA, cidToGIDLen * sizeof(Gushort));
103 if (!strcmp(face->driver->root.clazz->module_name, "t1cid")) {
104 mode = ftFontModeCID;
105 } else if (!strcmp(face->driver->root.clazz->module_name, "cff")) {
106 mode = ftFontModeCFFCharset;
107 } else if (embedded) {
108 mode = ftFontModeCIDToGIDMap;
110 mode = ftFontModeUnicode;
111 for (i = 0; i < face->num_charmaps; ++i) {
112 if ((face->charmaps[i]->platform_id == 3 &&
113 face->charmaps[i]->encoding_id == 1) ||
114 face->charmaps[i]->platform_id == 0) {
118 if (i == face->num_charmaps) {
121 FT_Set_Charmap(face, face->charmaps[i]);
126 FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
136 if (FT_New_Face(engine->lib, fontFileName, 0, &face)) {
139 if (!strcmp(face->driver->root.clazz->module_name, "t1cid")) {
140 mode = ftFontModeCID;
141 } else if (embedded) {
142 mode = ftFontModeCFFCharset;
144 mode = ftFontModeUnicode;
145 for (i = 0; i < face->num_charmaps; ++i) {
146 if ((face->charmaps[i]->platform_id == 3 &&
147 face->charmaps[i]->encoding_id == 1) ||
148 face->charmaps[i]->platform_id == 0) {
152 if (i == face->num_charmaps) {
155 FT_Set_Charmap(face, face->charmaps[i]);
160 FTFontFile::~FTFontFile() {
172 //------------------------------------------------------------------------
174 FTFont::FTFont(FTFontFile *fontFileA, double *m) {
175 FTFontEngine *engine;
183 fontFile = fontFileA;
184 engine = fontFile->engine;
185 face = fontFile->face;
186 if (FT_New_Size(face, &sizeObj)) {
189 face->size = sizeObj;
190 size = sqrt(m[2]*m[2] + m[3]*m[3]);
191 if (FT_Set_Pixel_Sizes(face, 0, (int)size)) {
195 div = face->bbox.xMax > 20000 ? 65536 : 1;
197 // transform the four corners of the font bounding box -- the min
198 // and max values form the bounding box of the transformed font
199 x = (int)((m[0] * face->bbox.xMin + m[2] * face->bbox.yMin) /
200 (div * face->units_per_EM));
202 y = (int)((m[1] * face->bbox.xMin + m[3] * face->bbox.yMin) /
203 (div * face->units_per_EM));
205 x = (int)((m[0] * face->bbox.xMin + m[2] * face->bbox.yMax) /
206 (div * face->units_per_EM));
209 } else if (x > xMax) {
212 y = (int)((m[1] * face->bbox.xMin + m[3] * face->bbox.yMax) /
213 (div * face->units_per_EM));
216 } else if (y > yMax) {
219 x = (int)((m[0] * face->bbox.xMax + m[2] * face->bbox.yMin) /
220 (div * face->units_per_EM));
223 } else if (x > xMax) {
226 y = (int)((m[1] * face->bbox.xMax + m[3] * face->bbox.yMin) /
227 (div * face->units_per_EM));
230 } else if (y > yMax) {
233 x = (int)((m[0] * face->bbox.xMax + m[2] * face->bbox.yMax) /
234 (div * face->units_per_EM));
237 } else if (x > xMax) {
240 y = (int)((m[1] * face->bbox.xMax + m[3] * face->bbox.yMax) /
241 (div * face->units_per_EM));
244 } else if (y > yMax) {
247 // This is a kludge: some buggy PDF generators embed fonts with
248 // zero bounding boxes.
255 yMax = (int)(1.2 * size);
257 // this should be (max - min + 1), but we add some padding to
258 // deal with rounding errors, bogus bboxes, etc.
259 glyphW = xMax - xMin + 3;
260 glyphW += glyphW >> 1;
261 glyphH = yMax - yMin + 3;
262 glyphH += glyphH >> 1;
264 glyphSize = glyphW * glyphH;
266 glyphSize = ((glyphW + 7) >> 3) * glyphH;
269 // set up the glyph pixmap cache
271 if (glyphSize <= 256) {
273 } else if (glyphSize <= 512) {
275 } else if (glyphSize <= 1024) {
280 cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
281 cacheTags = (FTFontCacheTag *)gmalloc(cacheSets * cacheAssoc *
282 sizeof(FTFontCacheTag));
283 for (i = 0; i < cacheSets * cacheAssoc; ++i) {
284 cacheTags[i].mru = i & (cacheAssoc - 1);
288 if (!(image = XCreateImage(engine->display, engine->visual, engine->depth,
289 ZPixmap, 0, NULL, glyphW, glyphH, 8, 0))) {
292 image->data = (char *)gmalloc(glyphH * image->bytes_per_line);
294 // compute the transform matrix
295 matrix.xx = (FT_Fixed)((m[0] / size) * 65536);
296 matrix.yx = (FT_Fixed)((m[1] / size) * 65536);
297 matrix.xy = (FT_Fixed)((m[2] / size) * 65536);
298 matrix.yy = (FT_Fixed)((m[3] / size) * 65536);
308 XDestroyImage(image);
311 GBool FTFont::drawChar(Drawable d, int w, int h, GC gc,
312 int x, int y, int r, int g, int b,
313 CharCode c, Unicode u) {
314 FTFontEngine *engine;
322 int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0;
325 engine = fontFile->engine;
327 // no Unicode index for this char - don't draw anything
328 if (fontFile->mode == ftFontModeUnicode && u == 0) {
332 // generate the glyph pixmap
333 if (!(bitmap = getGlyphPixmap(c, u, &xOffset, &yOffset, &gw, &gh,
338 // compute: (x0,y0) = position in destination drawable
339 // (x1,y1) = position in glyph image
340 // (w0,h0) = size of image transfer
370 // getGlyphPixmap may have returned a larger-than-cache-entry
371 // bitmap, in which case we need to allocate a temporary XImage here
373 if (!(img = XCreateImage(engine->display, engine->visual, engine->depth,
374 ZPixmap, 0, NULL, gw, gh, 8, 0))) {
377 img->data = (char *)gmalloc(gh * img->bytes_per_line);
383 XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
384 ZPixmap, img, x1, y1);
388 // compute the colors
389 xcolor.pixel = XGetPixel(img, x1 + w0/2, y1 + h0/2);
390 XQueryColor(engine->display, engine->colormap, &xcolor);
394 colors[1] = engine->findColor((r + 3*bgR) / 4,
397 colors[2] = engine->findColor((r + bgR) / 2,
400 colors[3] = engine->findColor((3*r + bgR) / 4,
403 colors[4] = engine->findColor(r, g, b);
405 // stuff the glyph pixmap into the X image
407 for (yy = 0; yy < gh; ++yy) {
408 for (xx = 0; xx < gw; ++xx) {
410 // this is a heuristic which seems to produce decent
411 // results -- the linear mapping would be:
412 // pix = (pix * 5) / 256;
413 pix = ((pix + 10) * 5) / 256;
418 XPutPixel(img, xx, yy, colors[pix]);
426 colors[1] = engine->findColor(r, g, b);
428 // stuff the glyph bitmap into the X image
430 for (yy = 0; yy < gh; ++yy) {
431 for (xx = 0; xx < gw; xx += 8) {
433 for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
435 XPutPixel(img, xx1, yy, colors[1]);
445 XPutImage(engine->display, d, gc, img, x1, y1, x0, y0, w0, h0);
459 Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u,
460 int *x, int *y, int *w, int *h,
469 i = (c & (cacheSets - 1)) * cacheAssoc;
470 for (j = 0; j < cacheAssoc; ++j) {
471 if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) {
472 *x = cacheTags[i+j].x;
473 *y = cacheTags[i+j].y;
474 *w = cacheTags[i+j].w;
475 *h = cacheTags[i+j].h;
476 for (k = 0; k < cacheAssoc; ++k) {
478 (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) {
479 ++cacheTags[i+k].mru;
482 cacheTags[i+j].mru = 0x8000;
483 *tempBitmap = gFalse;
484 return cache + (i+j) * glyphSize;
488 // generate the glyph pixmap or bitmap
489 fontFile->face->size = sizeObj;
490 FT_Set_Transform(fontFile->face, &matrix, NULL);
491 slot = fontFile->face->glyph;
492 idx = getGlyphIndex(c, u);
493 // if we have the FT2 bytecode interpreter, autohinting won't be used
494 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
495 if (FT_Load_Glyph(fontFile->face, idx,
496 fontFile->engine->aa ? FT_LOAD_NO_BITMAP
497 : FT_LOAD_DEFAULT)) {
501 // FT2's autohinting doesn't always work very well (especially with
502 // font subsets), so turn it off if anti-aliasing is enabled; if
503 // anti-aliasing is disabled, this seems to be a tossup - some fonts
504 // look better with hinting, some without, so leave hinting on
505 if (FT_Load_Glyph(fontFile->face, idx,
506 fontFile->engine->aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP
507 : FT_LOAD_DEFAULT)) {
511 if (FT_Render_Glyph(slot,
512 fontFile->engine->aa ? ft_render_mode_normal :
513 ft_render_mode_mono)) {
517 // copy the glyph into the cache or a temporary bitmap
518 *x = -slot->bitmap_left;
519 *y = slot->bitmap_top;
520 *w = slot->bitmap.width;
521 *h = slot->bitmap.rows;
522 if (fontFile->engine->aa) {
525 rowSize = (*w + 7) >> 3;
527 if (*w > glyphW || *h > glyphH) {
528 // the glyph doesn't fit in the bounding box -- return a
529 // temporary, uncached bitmap (this shouldn't happen but some
530 // fonts have incorrect bboxes)
531 ret = (Guchar *)gmalloc(*h * rowSize);
534 // store glyph pixmap in cache
535 ret = NULL; // make gcc happy
536 for (j = 0; j < cacheAssoc; ++j) {
537 if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
538 cacheTags[i+j].mru = 0x8000;
539 cacheTags[i+j].code = c;
540 cacheTags[i+j].x = *x;
541 cacheTags[i+j].y = *y;
542 cacheTags[i+j].w = *w;
543 cacheTags[i+j].h = *h;
544 ret = cache + (i+j) * glyphSize;
546 ++cacheTags[i+j].mru;
549 *tempBitmap = gFalse;
551 for (k = 0, p = ret, q = slot->bitmap.buffer;
552 k < slot->bitmap.rows;
553 ++k, p += rowSize, q += slot->bitmap.pitch) {
554 memcpy(p, q, rowSize);
559 GBool FTFont::getCharPath(CharCode c, Unicode u, GfxState *state) {
560 static FT_Outline_Funcs outlineFuncs = {
571 fontFile->face->size = sizeObj;
572 FT_Set_Transform(fontFile->face, &matrix, NULL);
573 slot = fontFile->face->glyph;
574 idx = getGlyphIndex(c, u);
575 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
576 if (FT_Load_Glyph(fontFile->face, idx, FT_LOAD_DEFAULT)) {
580 // FT2's autohinting doesn't always work very well (especially with
581 // font subsets), so turn it off if anti-aliasing is enabled; if
582 // anti-aliasing is disabled, this seems to be a tossup - some fonts
583 // look better with hinting, some without, so leave hinting on
584 if (FT_Load_Glyph(fontFile->face, idx,
585 fontFile->engine->aa ? FT_LOAD_NO_HINTING
586 : FT_LOAD_DEFAULT)) {
590 if (FT_Get_Glyph(slot, &glyph)) {
593 FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
594 &outlineFuncs, state);
598 int FTFont::charPathMoveTo(FT_Vector *pt, void *state) {
599 ((GfxState *)state)->moveTo(pt->x / 64.0, -pt->y / 64.0);
603 int FTFont::charPathLineTo(FT_Vector *pt, void *state) {
604 ((GfxState *)state)->lineTo(pt->x / 64.0, -pt->y / 64.0);
608 int FTFont::charPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *state) {
609 double x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
611 x0 = ((GfxState *)state)->getCurX();
612 y0 = ((GfxState *)state)->getCurY();
614 yc = -ctrl->y / 64.0;
618 // A second-order Bezier curve is defined by two endpoints, p0 and
619 // p3, and one control point, pc:
621 // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
623 // A third-order Bezier curve is defined by the same two endpoints,
624 // p0 and p3, and two control points, p1 and p2:
626 // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
628 // Applying some algebra, we can convert a second-order curve to a
629 // third-order curve:
631 // p1 = (1/3) * (p0 + 2pc)
632 // p2 = (1/3) * (2pc + p3)
634 x1 = (1.0 / 3.0) * (x0 + 2 * xc);
635 y1 = (1.0 / 3.0) * (y0 + 2 * yc);
636 x2 = (1.0 / 3.0) * (2 * xc + x3);
637 y2 = (1.0 / 3.0) * (2 * yc + y3);
639 ((GfxState *)state)->curveTo(x1, y1, x2, y2, x3, y3);
643 int FTFont::charPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2,
644 FT_Vector *pt, void *state) {
645 ((GfxState *)state)->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0,
646 ctrl2->x / 64.0, -ctrl2->y / 64.0,
647 pt->x / 64.0, -pt->y / 64.0);
651 FT_UInt FTFont::getGlyphIndex(CharCode c, Unicode u) {
655 idx = 0; // make gcc happy
656 switch (fontFile->mode) {
657 case ftFontModeUnicode:
658 idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)u);
660 case ftFontModeCodeMapDirect:
662 idx = (FT_UInt)fontFile->codeMap[c];
667 case ftFontModeCIDToGIDMap:
668 if (fontFile->cidToGIDLen) {
669 if ((int)c < fontFile->cidToGIDLen) {
670 idx = (FT_UInt)fontFile->cidToGID[c];
678 case ftFontModeCFFCharset:
679 #if 1 //~ cff cid->gid map
681 #if FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 0
682 CFF_Font *cff = (CFF_Font *)((TT_Face)fontFile->face)->extra.data;
684 CFF_Font cff = (CFF_Font)((TT_Face)fontFile->face)->extra.data;
687 for (j = 0; j < (int)cff->num_glyphs; ++j) {
688 if (cff->charset.sids[j] == c) {
703 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)