]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/TTFont.cc
Synched with Xpdf 0.92
[evince.git] / pdf / xpdf / TTFont.cc
1 //========================================================================
2 //
3 // TTFont.cc
4 //
5 //========================================================================
6
7 #ifdef __GNUC__
8 #pragma implementation
9 #endif
10
11 #if HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H
12
13 #include <string.h>
14 #include "gmem.h"
15 #include "TTFont.h"
16
17 //------------------------------------------------------------------------
18
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};
23
24   ok = gFalse;
25   if (TT_Init_FreeType(&engine)) {
26     return;
27   }
28   this->aa = aa;
29   if (aa) {
30     if (TT_Set_Raster_Gray_Palette(engine, ttPalette)) {
31       return;
32     }
33   }
34   ok = gTrue;
35 }
36
37 TTFontEngine::~TTFontEngine() {
38   TT_Done_FreeType(engine);
39 }
40
41 //------------------------------------------------------------------------
42
43 TTFontFile::TTFontFile(TTFontEngine *engine, char *fontFileName) {
44   TT_Face_Properties props;
45   TT_UShort platform, encoding, i;
46
47   ok = gFalse;
48   this->engine = engine;
49   if (TT_Open_Face(engine->engine, fontFileName, &face)) {
50     return;
51   }
52   if (TT_Get_Face_Properties(face, &props)) {
53     return;
54   }
55
56   // Choose a cmap:
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
62   // tweaking.
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) {
66         break;
67       }
68     }
69   }
70   if (i >= props.num_CharMaps) {
71     i = 0;
72     TT_Get_CharMap_ID(face, i, &platform, &encoding);
73   }
74   if (platform == 3 && encoding == 0) {
75     charMapOffset = 0xf000;
76   } else {
77     charMapOffset = 0;
78   }
79   TT_Get_CharMap(face, i, &charMap);
80
81   ok = gTrue;
82 }
83
84 TTFontFile::~TTFontFile() {
85   TT_Close_Face(face);
86 }
87
88 //------------------------------------------------------------------------
89
90 TTFont::TTFont(TTFontFile *fontFile, double *m) {
91   TTFontEngine *engine;
92   TT_Face_Properties props;
93   TT_Instance_Metrics metrics;
94   int x, xMin, xMax;
95   int y, yMin, yMax;
96   int i;
97
98   ok = gFalse;
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)) {
107     return;
108   }
109
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);
114   xMin = xMax = x;
115   y = (int)((m[1] * props.header->xMin + m[3] * props.header->yMin) *
116             0.001 * metrics.x_ppem / props.header->Units_Per_EM);
117   yMin = yMax = y;
118   x = (int)((m[0] * props.header->xMin + m[2] * props.header->yMax) *
119             0.001 * metrics.x_ppem / props.header->Units_Per_EM);
120   if (x < xMin) {
121     xMin = x;
122   } else if (x > xMax) {
123     xMax = x;
124   }
125   y = (int)((m[1] * props.header->xMin + m[3] * props.header->yMax) *
126             0.001 * metrics.x_ppem / props.header->Units_Per_EM);
127   if (y < yMin) {
128     yMin = y;
129   } else if (y > yMax) {
130     yMax = y;
131   }
132   x = (int)((m[0] * props.header->xMax + m[2] * props.header->yMin) *
133             0.001 * metrics.x_ppem / props.header->Units_Per_EM);
134   if (x < xMin) {
135     xMin = x;
136   } else if (x > xMax) {
137     xMax = x;
138   }
139   y = (int)((m[1] * props.header->xMax + m[3] * props.header->yMin) *
140             0.001 * metrics.x_ppem / props.header->Units_Per_EM);
141   if (y < yMin) {
142     yMin = y;
143   } else if (y > yMax) {
144     yMax = y;
145   }
146   x = (int)((m[0] * props.header->xMax + m[2] * props.header->yMax) *
147             0.001 * metrics.x_ppem / props.header->Units_Per_EM);
148   if (x < xMin) {
149     xMin = x;
150   } else if (x > xMax) {
151     xMax = x;
152   }
153   y = (int)((m[1] * props.header->xMax + m[3] * props.header->yMax) *
154             0.001 * metrics.x_ppem / props.header->Units_Per_EM);
155   if (y < yMin) {
156     yMin = y;
157   } else if (y > yMax) {
158     yMax = y;
159   }
160   xOffset = -xMin;
161   yOffset = -yMin;
162   ras.width = xMax - xMin + 1;
163   ras.rows = yMax - yMin + 1;
164
165   // set up the Raster_Map structure
166   if (engine->aa) {
167     ras.width = (ras.width + 3) & ~3;
168     ras.cols = ras.width;
169   } else {
170     ras.width = (ras.width + 7) & ~7;
171     ras.cols = ras.width >> 3;
172   }
173   ras.flow = TT_Flow_Down;
174   ras.size = ras.rows * ras.cols;
175   ras.bitmap = gmalloc(ras.size);
176
177   // set up the glyph pixmap cache
178   cacheAssoc = 8;
179   if (ras.size <= 256) {
180     cacheSets = 8;
181   } else if (ras.size <= 512) {
182     cacheSets = 4;
183   } else if (ras.size <= 1024) {
184     cacheSets = 2;
185   } else {
186     cacheSets = 1;
187   }
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);
193   }
194
195   // create the XImage
196   if (!(image = XCreateImage(engine->display, engine->visual, engine->depth,
197                              ZPixmap, 0, NULL, ras.width, ras.rows, 8, 0))) {
198     return;
199   }
200   image->data = (char *)gmalloc(ras.rows * image->bytes_per_line);
201
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);
207
208   ok = gTrue;
209 }
210
211 TTFont::~TTFont() {
212   gfree(cacheTags);
213   gfree(cache);
214   gfree(image->data);
215   image->data = NULL;
216   XDestroyImage(image);
217   gfree(ras.bitmap);
218   TT_Done_Glyph(glyph);
219   TT_Done_Instance(instance);
220 }
221
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;
225   XColor xcolor;
226   int bgR, bgG, bgB;
227   Gulong colors[5];
228   TT_Byte *p;
229   TT_Byte pix;
230   int xx, yy, xx1;
231   int x0, y0, x1, y1, w0, h0;
232
233   engine = fontFile->engine;
234
235   // compute: (x0,y0) = position in destination drawable
236   //          (x1,y1) = position in glyph image
237   //          (w0,h0) = size of image transfer
238   x0 = x - xOffset;
239   y0 = y - (ras.rows - yOffset);
240   x1 = 0;
241   y1 = 0;
242   w0 = ras.width;
243   h0 = ras.rows;
244   if (x0 < 0) {
245     x1 = -x0;
246     w0 += x0;
247     x0 = 0;
248   }
249   if (x0 + w0 > w) {
250     w0 = w - x0;
251   }
252   if (w0 < 0) {
253     return gTrue;
254   }
255   if (y0 < 0) {
256     y1 = -y0;
257     h0 += y0;
258     y0 = 0;
259   }
260   if (y0 + h0 > h) {
261     h0 = h - y0;
262   }
263   if (h0 < 0) {
264     return gTrue;
265   }
266
267   // read the X image
268   XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
269                ZPixmap, image, x1, y1);
270
271   // generate the glyph pixmap
272   if (!getGlyphPixmap(c)) {
273     return gFalse;
274   }
275
276   if (engine->aa) {
277
278     // compute the colors
279     xcolor.pixel = XGetPixel(image, x1, y1);
280     XQueryColor(engine->display, engine->colormap, &xcolor);
281     bgR = xcolor.red;
282     bgG = xcolor.green;
283     bgB = xcolor.blue;
284     colors[1] = engine->findColor((r + 3*bgR) / 4,
285                                   (g + 3*bgG) / 4,
286                                   (b + 3*bgB) / 4);
287     colors[2] = engine->findColor((r + bgR) / 2,
288                                   (g + bgG) / 2,
289                                   (b + bgB) / 2);
290     colors[3] = engine->findColor((3*r + bgR) / 4,
291                                   (3*g + bgG) / 4,
292                                   (3*b + bgB) / 4);
293     colors[4] = engine->findColor(r, g, b);
294
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) {
299         pix = *p++;
300         if (pix > 0) {
301           if (pix > 4) {
302             pix = 4;
303           }
304           XPutPixel(image, xx, yy, colors[pix]);
305         }
306       }
307     }
308
309   } else {
310
311     // one color
312     colors[1] = engine->findColor(r, g, b);
313
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) {
318         pix = *p++;
319         for (xx1 = xx; xx1 < xx + 8 && xx1 < ras.width; ++xx1) {
320           if (pix & 0x80) {
321             XPutPixel(image, xx1, yy, colors[1]);
322           }
323           pix <<= 1;
324         }
325       }
326     }
327
328   }
329
330   // draw the X image
331   XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0);
332
333   return gTrue;
334 }
335
336 GBool TTFont::getGlyphPixmap(Gushort c) {
337   TT_UShort idx;
338   TT_Outline outline;
339   int i, j, k;
340
341   // check the cache
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) {
347         if (k != j &&
348             (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) {
349           ++cacheTags[i+k].mru;
350         }
351       }
352       cacheTags[i+j].mru = 0x8000;
353       return gTrue;
354     }
355   }
356
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)) {
361     return gFalse;
362   }
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)) {
367       return gFalse;
368     }
369   } else {
370     if (TT_Get_Glyph_Bitmap(glyph, &ras, xOffset * 64, yOffset * 64)) {
371       return gFalse;
372     }
373   }
374
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);
381     } else {
382       ++cacheTags[i+j].mru;
383     }
384   }
385
386   return gTrue;
387 }
388
389 #endif // HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H