TTFont.cpp
1//========================================================================
2//
3// TTFont.cpp
4//
5// Copyright 2001-2002 Glyph & Cog, LLC
6//
7//========================================================================
8
9#include <aconf.h>
10
11#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
12
13#ifdef USE_GCC_PRAGMAS
14#pragma implementation
15#endif
16
17#include <string.h>
18#include "gmem.h"
19#include "GlobalParams.h"
20#include "TTFont.h"
21
22//------------------------------------------------------------------------
23
24TTFontEngine::TTFontEngine(Display *displayA, Visual *visualA, int depthA,
25 Colormap colormapA, GBool aaA):
26 SFontEngine(displayA, visualA, depthA, colormapA) {
27 static TT_Byte ttPalette[5] = {0, 1, 2, 3, 4};
28
29 ok = gFalse;
30 if (TT_Init_FreeType(&engine)) {
31 return;
32 }
33 aa = aaA;
34 if (aa) {
35 if (TT_Set_Raster_Gray_Palette(engine, ttPalette)) {
36 return;
37 }
38 }
39 ok = gTrue;
40}
41
42TTFontEngine::~TTFontEngine() {
43 TT_Done_FreeType(engine);
44}
45
46//------------------------------------------------------------------------
47
48TTFontFile::TTFontFile(TTFontEngine *engineA, char *fontFileName,
49 char **fontEnc, GBool pdfFontHasEncoding) {
50 TT_Face_Properties props;
51 TT_UShort unicodeCmap, macRomanCmap, msSymbolCmap;
52 TT_UShort platform, encoding, i;
53 int j;
54
55 ok = gFalse;
56 engine = engineA;
57 codeMap = NULL;
58 if (TT_Open_Face(engine->engine, fontFileName, &face)) {
59 return;
60 }
61 if (TT_Get_Face_Properties(face, &props)) {
62 return;
63 }
64
65 // To match up with the Adobe-defined behaviour, we choose a cmap
66 // like this:
67 // 1. If the PDF font has an encoding:
68 // 1a. If the TrueType font has a Microsoft Unicode cmap, use it,
69 // and use the Unicode indexes, not the char codes.
70 // 1b. If the TrueType font has a Macintosh Roman cmap, use it,
71 // and reverse map the char names through MacRomanEncoding to
72 // get char codes.
73 // 2. If the PDF font does not have an encoding:
74 // 2a. If the TrueType font has a Macintosh Roman cmap, use it,
75 // and use char codes directly.
76 // 2b. If the TrueType font has a Microsoft Symbol cmap, use it,
77 // and use (0xf000 + char code).
78 // 3. If none of these rules apply, use the first cmap and hope for
79 // the best (this shouldn't happen).
80 unicodeCmap = macRomanCmap = msSymbolCmap = 0xffff;
81 for (i = 0; i < props.num_CharMaps; ++i) {
82 if (!TT_Get_CharMap_ID(face, i, &platform, &encoding)) {
83 if (platform == 3 && encoding == 1) {
84 unicodeCmap = i;
85 } else if (platform == 1 && encoding == 0) {
86 macRomanCmap = i;
87 } else if (platform == 3 && encoding == 0) {
88 msSymbolCmap = i;
89 }
90 }
91 }
92 i = 0;
93 mode = ttFontModeCharCode;
94 charMapOffset = 0;
95 if (pdfFontHasEncoding) {
96 if (unicodeCmap != 0xffff) {
97 i = unicodeCmap;
98 mode = ttFontModeUnicode;
99 } else if (macRomanCmap != 0xffff) {
100 i = macRomanCmap;
101 mode = ttFontModeCodeMap;
102 codeMap = (Guchar *)gmalloc(256 * sizeof(Guchar));
103 for (j = 0; j < 256; ++j) {
104 if (fontEnc[j]) {
105 codeMap[j] = (Guchar)globalParams->getMacRomanCharCode(fontEnc[j]);
106 } else {
107 codeMap[j] = 0;
108 }
109 }
110 }
111 } else {
112 if (macRomanCmap != 0xffff) {
113 i = macRomanCmap;
114 mode = ttFontModeCharCode;
115 } else if (msSymbolCmap != 0xffff) {
116 i = msSymbolCmap;
117 mode = ttFontModeCharCodeOffset;
118 charMapOffset = 0xf000;
119 }
120 }
121 TT_Get_CharMap(face, i, &charMap);
122
123 ok = gTrue;
124}
125
126TTFontFile::TTFontFile(TTFontEngine *engineA, char *fontFileName,
127 Gushort *cidToGIDA, int cidToGIDLenA) {
128 ok = gFalse;
129 engine = engineA;
130 codeMap = NULL;
131 cidToGID = cidToGIDA;
132 cidToGIDLen = cidToGIDLenA;
133 if (TT_Open_Face(engine->engine, fontFileName, &face)) {
134 return;
135 }
136 mode = ttFontModeCIDToGIDMap;
137 ok = gTrue;
138}
139
140TTFontFile::~TTFontFile() {
141 TT_Close_Face(face);
142 if (codeMap) {
143 gfree(codeMap);
144 }
145}
146
147//------------------------------------------------------------------------
148
149TTFont::TTFont(TTFontFile *fontFileA, double *m) {
150 TTFontEngine *engine;
151 TT_Face_Properties props;
152 TT_Instance_Metrics metrics;
153 int x, xMin, xMax;
154 int y, yMin, yMax;
155 int i;
156
157 ok = gFalse;
158 fontFile = fontFileA;
159 engine = fontFile->engine;
160 if (TT_New_Instance(fontFile->face, &instance) ||
161 TT_Set_Instance_Resolutions(instance, 72, 72) ||
162 TT_Set_Instance_CharSize(instance, 1000 * 64) ||
163 TT_New_Glyph(fontFile->face, &glyph) ||
164 TT_Get_Face_Properties(fontFile->face, &props) ||
165 TT_Get_Instance_Metrics(instance, &metrics)) {
166 return;
167 }
168
169 // transform the four corners of the font bounding box -- the min
170 // and max values form the bounding box of the transformed font
171 x = (int)((m[0] * props.header->xMin + m[2] * props.header->yMin) *
172 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
173 xMin = xMax = x;
174 y = (int)((m[1] * props.header->xMin + m[3] * props.header->yMin) *
175 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
176 yMin = yMax = y;
177 x = (int)((m[0] * props.header->xMin + m[2] * props.header->yMax) *
178 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
179 if (x < xMin) {
180 xMin = x;
181 } else if (x > xMax) {
182 xMax = x;
183 }
184 y = (int)((m[1] * props.header->xMin + m[3] * props.header->yMax) *
185 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
186 if (y < yMin) {
187 yMin = y;
188 } else if (y > yMax) {
189 yMax = y;
190 }
191 x = (int)((m[0] * props.header->xMax + m[2] * props.header->yMin) *
192 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
193 if (x < xMin) {
194 xMin = x;
195 } else if (x > xMax) {
196 xMax = x;
197 }
198 y = (int)((m[1] * props.header->xMax + m[3] * props.header->yMin) *
199 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
200 if (y < yMin) {
201 yMin = y;
202 } else if (y > yMax) {
203 yMax = y;
204 }
205 x = (int)((m[0] * props.header->xMax + m[2] * props.header->yMax) *
206 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
207 if (x < xMin) {
208 xMin = x;
209 } else if (x > xMax) {
210 xMax = x;
211 }
212 y = (int)((m[1] * props.header->xMax + m[3] * props.header->yMax) *
213 0.001 * metrics.x_ppem / props.header->Units_Per_EM);
214 if (y < yMin) {
215 yMin = y;
216 } else if (y > yMax) {
217 yMax = y;
218 }
219 xOffset = -xMin;
220 yOffset = -yMin;
221 ras.width = xMax - xMin + 1;
222 ras.rows = yMax - yMin + 1;
223
224 // set up the Raster_Map structure
225 if (engine->aa) {
226 ras.width = (ras.width + 3) & ~3;
227 ras.cols = ras.width;
228 } else {
229 ras.width = (ras.width + 7) & ~7;
230 ras.cols = ras.width >> 3;
231 }
232 ras.flow = TT_Flow_Down;
233 ras.size = ras.rows * ras.cols;
234 ras.bitmap = gmalloc(ras.size);
235
236 // set up the glyph pixmap cache
237 cacheAssoc = 8;
238 if (ras.size <= 256) {
239 cacheSets = 8;
240 } else if (ras.size <= 512) {
241 cacheSets = 4;
242 } else if (ras.size <= 1024) {
243 cacheSets = 2;
244 } else {
245 cacheSets = 1;
246 }
247 cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * ras.size);
248 cacheTags = (TTFontCacheTag *)gmalloc(cacheSets * cacheAssoc *
249 sizeof(TTFontCacheTag));
250 for (i = 0; i < cacheSets * cacheAssoc; ++i) {
251 cacheTags[i].mru = i & (cacheAssoc - 1);
252 }
253
254 // create the XImage
255 if (!(image = XCreateImage(engine->display, engine->visual, engine->depth,
256 ZPixmap, 0, NULL, ras.width, ras.rows, 8, 0))) {
257 return;
258 }
259 image->data = (char *)gmalloc(ras.rows * image->bytes_per_line);
260
261 // compute the transform matrix
262 matrix.xx = (TT_Fixed)(m[0] * 65.536);
263 matrix.yx = (TT_Fixed)(m[1] * 65.536);
264 matrix.xy = (TT_Fixed)(m[2] * 65.536);
265 matrix.yy = (TT_Fixed)(m[3] * 65.536);
266
267 ok = gTrue;
268}
269
270TTFont::~TTFont() {
271 gfree(cacheTags);
272 gfree(cache);
273 gfree(image->data);
274 image->data = NULL;
275 XDestroyImage(image);
276 gfree(ras.bitmap);
277 TT_Done_Glyph(glyph);
278 TT_Done_Instance(instance);
279}
280
281GBool TTFont::drawChar(Drawable d, int w, int h, GC gc,
282 int x, int y, int r, int g, int b,
283 CharCode c, Unicode u) {
284 TTFontEngine *engine;
285 XColor xcolor;
286 int bgR, bgG, bgB;
287 Gulong colors[5];
288 TT_Byte *p;
289 TT_Byte pix;
290 int xx, yy, xx1;
291 int x0, y0, x1, y1, w0, h0;
292
293 engine = fontFile->engine;
294
295 // compute: (x0,y0) = position in destination drawable
296 // (x1,y1) = position in glyph image
297 // (w0,h0) = size of image transfer
298 x0 = x - xOffset;
299 y0 = y - (ras.rows - yOffset);
300 x1 = 0;
301 y1 = 0;
302 w0 = ras.width;
303 h0 = ras.rows;
304 if (x0 < 0) {
305 x1 = -x0;
306 w0 += x0;
307 x0 = 0;
308 }
309 if (x0 + w0 > w) {
310 w0 = w - x0;
311 }
312 if (w0 < 0) {
313 return gTrue;
314 }
315 if (y0 < 0) {
316 y1 = -y0;
317 h0 += y0;
318 y0 = 0;
319 }
320 if (y0 + h0 > h) {
321 h0 = h - y0;
322 }
323 if (h0 < 0) {
324 return gTrue;
325 }
326
327 // read the X image
328 XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
329 ZPixmap, image, x1, y1);
330
331 // generate the glyph pixmap
332 if (!getGlyphPixmap(c, u)) {
333 return gFalse;
334 }
335
336 if (engine->aa) {
337
338 // compute the colors
339 xcolor.pixel = XGetPixel(image, x1 + w0/2, y1 + h0/2);
340 XQueryColor(engine->display, engine->colormap, &xcolor);
341 bgR = xcolor.red;
342 bgG = xcolor.green;
343 bgB = xcolor.blue;
344 colors[1] = engine->findColor((r + 3*bgR) / 4,
345 (g + 3*bgG) / 4,
346 (b + 3*bgB) / 4);
347 colors[2] = engine->findColor((r + bgR) / 2,
348 (g + bgG) / 2,
349 (b + bgB) / 2);
350 colors[3] = engine->findColor((3*r + bgR) / 4,
351 (3*g + bgG) / 4,
352 (3*b + bgB) / 4);
353 colors[4] = engine->findColor(r, g, b);
354
355 // stuff the glyph pixmap into the X image
356 p = (TT_Byte *)ras.bitmap;
357 for (yy = 0; yy < ras.rows; ++yy) {
358 for (xx = 0; xx < ras.width; ++xx) {
359 pix = *p++;
360 if (pix > 0) {
361 if (pix > 4) {
362 pix = 4;
363 }
364 XPutPixel(image, xx, yy, colors[pix]);
365 }
366 }
367 }
368
369 } else {
370
371 // one color
372 colors[1] = engine->findColor(r, g, b);
373
374 // stuff the glyph bitmap into the X image
375 p = (TT_Byte *)ras.bitmap;
376 for (yy = 0; yy < ras.rows; ++yy) {
377 for (xx = 0; xx < ras.width; xx += 8) {
378 pix = *p++;
379 for (xx1 = xx; xx1 < xx + 8 && xx1 < ras.width; ++xx1) {
380 if (pix & 0x80) {
381 XPutPixel(image, xx1, yy, colors[1]);
382 }
383 pix <<= 1;
384 }
385 }
386 }
387
388 }
389
390 // draw the X image
391 XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0);
392
393 return gTrue;
394}
395
396GBool TTFont::getGlyphPixmap(CharCode c, Unicode u) {
397 TT_UShort idx;
398 TT_Outline outline;
399 int i, j, k;
400
401 // check the cache
402 i = (c & (cacheSets - 1)) * cacheAssoc;
403 for (j = 0; j < cacheAssoc; ++j) {
404 if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) {
405 memcpy(ras.bitmap, cache + (i+j) * ras.size, ras.size);
406 for (k = 0; k < cacheAssoc; ++k) {
407 if (k != j &&
408 (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) {
409 ++cacheTags[i+k].mru;
410 }
411 }
412 cacheTags[i+j].mru = 0x8000;
413 return gTrue;
414 }
415 }
416
417 // generate the glyph pixmap or bitmap
418 idx = 0; // make gcc happy
419 switch (fontFile->mode) {
420 case ttFontModeUnicode:
421 idx = TT_Char_Index(fontFile->charMap, (TT_UShort)u);
422 break;
423 case ttFontModeCharCode:
424 idx = TT_Char_Index(fontFile->charMap, (TT_UShort)c);
425 break;
426 case ttFontModeCharCodeOffset:
427 idx = TT_Char_Index(fontFile->charMap,
428 (TT_UShort)(c + fontFile->charMapOffset));
429 break;
430 case ttFontModeCodeMap:
431 if (c <= 0xff) {
432 idx = TT_Char_Index(fontFile->charMap,
433 (TT_UShort)(fontFile->codeMap[c] & 0xff));
434 } else {
435 idx = 0;
436 }
437 break;
438 case ttFontModeCIDToGIDMap:
439 if (fontFile->cidToGIDLen) {
440 if ((int)c < fontFile->cidToGIDLen) {
441 idx = (TT_UShort)fontFile->cidToGID[c];
442 } else {
443 idx = (TT_UShort)0;
444 }
445 } else {
446 idx = (TT_UShort)c;
447 }
448 break;
449 }
450 if (TT_Load_Glyph(instance, glyph, idx, TTLOAD_DEFAULT) ||
451 TT_Get_Glyph_Outline(glyph, &outline)) {
452 return gFalse;
453 }
454 TT_Transform_Outline(&outline, &matrix);
455 memset(ras.bitmap, 0, ras.size);
456 if (fontFile->engine->aa) {
457 if (TT_Get_Glyph_Pixmap(glyph, &ras, xOffset * 64, yOffset * 64)) {
458 return gFalse;
459 }
460 } else {
461 if (TT_Get_Glyph_Bitmap(glyph, &ras, xOffset * 64, yOffset * 64)) {
462 return gFalse;
463 }
464 }
465
466 // store glyph pixmap in cache
467 for (j = 0; j < cacheAssoc; ++j) {
468 if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
469 cacheTags[i+j].mru = 0x8000;
470 cacheTags[i+j].code = c;
471 memcpy(cache + (i+j) * ras.size, ras.bitmap, ras.size);
472 } else {
473 ++cacheTags[i+j].mru;
474 }
475 }
476
477 return gTrue;
478}
479
480#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)