]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/TTFont.cc
Import of Xpdf 2.00 for merge
[evince.git] / pdf / xpdf / TTFont.cc
1 //========================================================================
2 //
3 // TTFont.cc
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
24 TTFontEngine::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
42 TTFontEngine::~TTFontEngine() {
43   TT_Done_FreeType(engine);
44 }
45
46 //------------------------------------------------------------------------
47
48 TTFontFile::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
126 TTFontFile::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
140 TTFontFile::~TTFontFile() {
141   TT_Close_Face(face);
142   if (codeMap) {
143     gfree(codeMap);
144   }
145 }
146
147 //------------------------------------------------------------------------
148
149 TTFont::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
270 TTFont::~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
281 GBool 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
396 GBool 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)