1 //========================================================================
5 //========================================================================
11 #if HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H
17 //------------------------------------------------------------------------
19 TTFontEngine::TTFontEngine(Display *display, Visual *visual, int depth,
20 Colormap colormap, GBool aa):
21 SFontEngine(display, visual, depth, colormap) {
22 static TT_Byte ttPalette[5] = {0, 1, 2, 3, 4};
25 if (TT_Init_FreeType(&engine)) {
30 if (TT_Set_Raster_Gray_Palette(engine, ttPalette)) {
37 TTFontEngine::~TTFontEngine() {
38 TT_Done_FreeType(engine);
41 //------------------------------------------------------------------------
43 TTFontFile::TTFontFile(TTFontEngine *engine, char *fontFileName) {
44 TT_Face_Properties props;
45 TT_UShort platform, encoding, i;
48 this->engine = engine;
49 if (TT_Open_Face(engine->engine, fontFileName, &face)) {
52 if (TT_Get_Face_Properties(face, &props)) {
57 // 1. If the font contains a Windows-symbol cmap, use it.
58 // 2. Otherwise, use the first cmap in the TTF file.
59 // 3. If the Windows-Symbol cmap is used (from either step 1 or step
60 // 2), offset all character indexes by 0xf000.
61 // This seems to match what acroread does, but may need further
63 for (i = 0; i < props.num_CharMaps; ++i) {
64 if (!TT_Get_CharMap_ID(face, i, &platform, &encoding)) {
65 if (platform == 3 && encoding == 0) {
70 if (i >= props.num_CharMaps) {
72 TT_Get_CharMap_ID(face, i, &platform, &encoding);
74 if (platform == 3 && encoding == 0) {
75 charMapOffset = 0xf000;
79 TT_Get_CharMap(face, i, &charMap);
84 TTFontFile::~TTFontFile() {
88 //------------------------------------------------------------------------
90 TTFont::TTFont(TTFontFile *fontFile, double *m) {
92 TT_Face_Properties props;
93 TT_Instance_Metrics metrics;
99 this->fontFile = fontFile;
100 engine = fontFile->engine;
101 if (TT_New_Instance(fontFile->face, &instance) ||
102 TT_Set_Instance_Resolutions(instance, 72, 72) ||
103 TT_Set_Instance_CharSize(instance, 1000 * 64) ||
104 TT_New_Glyph(fontFile->face, &glyph) ||
105 TT_Get_Face_Properties(fontFile->face, &props) ||
106 TT_Get_Instance_Metrics(instance, &metrics)) {
110 // transform the four corners of the font bounding box -- the min
111 // and max values form the bounding box of the transformed font
112 x = (int)((m[0] * props.header->xMin + m[2] * props.header->yMin) *
113 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
115 y = (int)((m[1] * props.header->xMin + m[3] * props.header->yMin) *
116 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
118 x = (int)((m[0] * props.header->xMin + m[2] * props.header->yMax) *
119 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
122 } else if (x > xMax) {
125 y = (int)((m[1] * props.header->xMin + m[3] * props.header->yMax) *
126 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
129 } else if (y > yMax) {
132 x = (int)((m[0] * props.header->xMax + m[2] * props.header->yMin) *
133 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
136 } else if (x > xMax) {
139 y = (int)((m[1] * props.header->xMax + m[3] * props.header->yMin) *
140 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
143 } else if (y > yMax) {
146 x = (int)((m[0] * props.header->xMax + m[2] * props.header->yMax) *
147 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
150 } else if (x > xMax) {
153 y = (int)((m[1] * props.header->xMax + m[3] * props.header->yMax) *
154 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
157 } else if (y > yMax) {
162 ras.width = xMax - xMin + 1;
163 ras.rows = yMax - yMin + 1;
165 // set up the Raster_Map structure
167 ras.width = (ras.width + 3) & ~3;
168 ras.cols = ras.width;
170 ras.width = (ras.width + 7) & ~7;
171 ras.cols = ras.width >> 3;
173 ras.flow = TT_Flow_Down;
174 ras.size = ras.rows * ras.cols;
175 ras.bitmap = gmalloc(ras.size);
177 // set up the glyph pixmap cache
179 if (ras.size <= 256) {
181 } else if (ras.size <= 512) {
183 } else if (ras.size <= 1024) {
188 cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * ras.size);
189 cacheTags = (TTFontCacheTag *)gmalloc(cacheSets * cacheAssoc *
190 sizeof(TTFontCacheTag));
191 for (i = 0; i < cacheSets * cacheAssoc; ++i) {
192 cacheTags[i].mru = i & (cacheAssoc - 1);
196 if (!(image = XCreateImage(engine->display, engine->visual, engine->depth,
197 ZPixmap, 0, NULL, ras.width, ras.rows, 8, 0))) {
200 image->data = (char *)gmalloc(ras.rows * image->bytes_per_line);
202 // compute the transform matrix
203 matrix.xx = (TT_Fixed)(m[0] * 65.536);
204 matrix.yx = (TT_Fixed)(m[1] * 65.536);
205 matrix.xy = (TT_Fixed)(m[2] * 65.536);
206 matrix.yy = (TT_Fixed)(m[3] * 65.536);
216 XDestroyImage(image);
218 TT_Done_Glyph(glyph);
219 TT_Done_Instance(instance);
222 GBool TTFont::drawChar(Drawable d, int w, int h, GC gc,
223 int x, int y, int r, int g, int b, Gushort c) {
224 TTFontEngine *engine;
231 int x0, y0, x1, y1, w0, h0;
233 engine = fontFile->engine;
235 // compute: (x0,y0) = position in destination drawable
236 // (x1,y1) = position in glyph image
237 // (w0,h0) = size of image transfer
239 y0 = y - (ras.rows - yOffset);
268 XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
269 ZPixmap, image, x1, y1);
271 // generate the glyph pixmap
272 if (!getGlyphPixmap(c)) {
278 // compute the colors
279 xcolor.pixel = XGetPixel(image, x1, y1);
280 XQueryColor(engine->display, engine->colormap, &xcolor);
284 colors[1] = engine->findColor((r + 3*bgR) / 4,
287 colors[2] = engine->findColor((r + bgR) / 2,
290 colors[3] = engine->findColor((3*r + bgR) / 4,
293 colors[4] = engine->findColor(r, g, b);
295 // stuff the glyph pixmap into the X image
296 p = (TT_Byte *)ras.bitmap;
297 for (yy = 0; yy < ras.rows; ++yy) {
298 for (xx = 0; xx < ras.width; ++xx) {
304 XPutPixel(image, xx, yy, colors[pix]);
312 colors[1] = engine->findColor(r, g, b);
314 // stuff the glyph bitmap into the X image
315 p = (TT_Byte *)ras.bitmap;
316 for (yy = 0; yy < ras.rows; ++yy) {
317 for (xx = 0; xx < ras.width; xx += 8) {
319 for (xx1 = xx; xx1 < xx + 8 && xx1 < ras.width; ++xx1) {
321 XPutPixel(image, xx1, yy, colors[1]);
331 XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0);
336 GBool TTFont::getGlyphPixmap(Gushort c) {
342 i = (c & (cacheSets - 1)) * cacheAssoc;
343 for (j = 0; j < cacheAssoc; ++j) {
344 if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) {
345 memcpy(ras.bitmap, cache + (i+j) * ras.size, ras.size);
346 for (k = 0; k < cacheAssoc; ++k) {
348 (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) {
349 ++cacheTags[i+k].mru;
352 cacheTags[i+j].mru = 0x8000;
357 // generate the glyph pixmap or bitmap
358 idx = TT_Char_Index(fontFile->charMap, fontFile->charMapOffset + c);
359 if (TT_Load_Glyph(instance, glyph, idx, TTLOAD_DEFAULT) ||
360 TT_Get_Glyph_Outline(glyph, &outline)) {
363 TT_Transform_Outline(&outline, &matrix);
364 memset(ras.bitmap, 0, ras.size);
365 if (fontFile->engine->aa) {
366 if (TT_Get_Glyph_Pixmap(glyph, &ras, xOffset * 64, yOffset * 64)) {
370 if (TT_Get_Glyph_Bitmap(glyph, &ras, xOffset * 64, yOffset * 64)) {
375 // store glyph pixmap in cache
376 for (j = 0; j < cacheAssoc; ++j) {
377 if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
378 cacheTags[i+j].mru = 0x8000;
379 cacheTags[i+j].code = c;
380 memcpy(cache + (i+j) * ras.size, ras.bitmap, ras.size);
382 ++cacheTags[i+j].mru;
389 #endif // HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H