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