]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/T1Font.cc
a9a67b64e6b3b03d0f7412534fb5f5ba9464c075
[evince.git] / pdf / xpdf / T1Font.cc
1 //========================================================================
2 //
3 // T1Font.cc
4 //
5 //========================================================================
6
7 #ifdef __GNUC__
8 #pragma implementation
9 #endif
10
11 #if HAVE_T1LIB_H
12
13 #include <math.h>
14 #include <string.h>
15 #include <X11/Xlib.h>
16 #include "gmem.h"
17 #include "FontEncoding.h"
18 #include "T1Font.h"
19
20 //------------------------------------------------------------------------
21
22 T1FontEngine::T1FontEngine(Display *display, Visual *visual, int depth,
23                            Colormap colormap, GBool aa, GBool aaHigh):
24   SFontEngine(display, visual, depth, colormap)
25 {
26   static unsigned long grayVals[17] = {
27     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
28   };
29
30   ok = gFalse;
31   T1_SetBitmapPad(8);
32   if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE |
33                   T1_NO_AFM)) {
34     return;
35   }
36   this->aa = aa;
37   this->aaHigh = aaHigh;
38   if (aa) {
39     T1_AASetBitsPerPixel(8);
40     if (aaHigh) {
41       T1_AASetLevel(T1_AA_HIGH);
42       T1_AAHSetGrayValues(grayVals);
43     } else {
44       T1_AASetLevel(T1_AA_LOW);
45       T1_AASetGrayValues(0, 1, 2, 3, 4);
46     }
47   } else {
48     T1_AANSetGrayValues(0, 1);
49   }
50   ok = gTrue;
51 }
52
53 T1FontEngine::~T1FontEngine() {
54   T1_CloseLib();
55 }
56
57 //------------------------------------------------------------------------
58
59 T1FontFile::T1FontFile(T1FontEngine *engine, char *fontFileName,
60                        FontEncoding *fontEnc) {
61   int encStrSize;
62   char *encPtr;
63   int i;
64
65   ok = gFalse;
66   this->engine = engine;
67
68   // load the font file
69   if ((id = T1_AddFont(fontFileName)) < 0) {
70     return;
71   }
72   T1_LoadFont(id);
73
74   // reencode it
75   encStrSize = 0;
76   for (i = 0; i < 256 && i < fontEnc->getSize(); ++i) {
77     if (fontEnc->getCharName(i)) {
78       encStrSize += strlen(fontEnc->getCharName(i)) + 1;
79     }
80   }
81   enc = (char **)gmalloc(257 * sizeof(char *));
82   encStr = (char *)gmalloc(encStrSize * sizeof(char));
83   encPtr = encStr;
84   for (i = 0; i < 256 && i < fontEnc->getSize(); ++i) {
85     if (fontEnc->getCharName(i)) {
86       strcpy(encPtr, fontEnc->getCharName(i));
87       enc[i] = encPtr;
88       encPtr += strlen(encPtr) + 1;
89     } else {
90       enc[i] = ".notdef";
91     }
92   }
93   for (; i < 256; ++i) {
94     enc[i] = ".notdef";
95   }
96   enc[256] = "custom";
97   T1_ReencodeFont(id, enc);
98
99   ok = gTrue;
100 }
101
102 T1FontFile::~T1FontFile() {
103   gfree(enc);
104   gfree(encStr);
105   T1_DeleteFont(id);
106 }
107
108 //------------------------------------------------------------------------
109
110 T1Font::T1Font(T1FontFile *fontFile, double *m) {
111   T1FontEngine *engine;
112   T1_TMATRIX matrix;
113   BBox bbox;
114   int x, y, xMin, xMax, yMin, yMax;
115   int i;
116
117   ok = gFalse;
118   engine = fontFile->engine;
119   this->fontFile = fontFile;
120
121   id = T1_CopyFont(fontFile->id);
122
123   // compute font size
124   size = (float)sqrt(m[2]*m[2] + m[3]*m[3]);
125
126   // transform the four corners of the font bounding box -- the min
127   // and max values form the bounding box of the transformed font
128   bbox = T1_GetFontBBox(id);
129   x = (int)((m[0] * bbox.llx + m[2] * bbox.lly) * 0.001);
130   xMin = xMax = x;
131   y = (int)((m[1] * bbox.llx + m[3] * bbox.lly) * 0.001);
132   yMin = yMax = y;
133   x = (int)((m[0] * bbox.llx + m[2] * bbox.ury) * 0.001);
134   if (x < xMin) {
135     xMin = x;
136   } else if (x > xMax) {
137     xMax = x;
138   }
139   y = (int)((m[1] * bbox.llx + m[3] * bbox.ury) * 0.001);
140   if (y < yMin) {
141     yMin = y;
142   } else if (y > yMax) {
143     yMax = y;
144   }
145   x = (int)((m[0] * bbox.urx + m[2] * bbox.lly) * 0.001);
146   if (x < xMin) {
147     xMin = x;
148   } else if (x > xMax) {
149     xMax = x;
150   }
151   y = (int)((m[1] * bbox.urx + m[3] * bbox.lly) * 0.001);
152   if (y < yMin) {
153     yMin = y;
154   } else if (y > yMax) {
155     yMax = y;
156   }
157   x = (int)((m[0] * bbox.urx + m[2] * bbox.ury) * 0.001);
158   if (x < xMin) {
159     xMin = x;
160   } else if (x > xMax) {
161     xMax = x;
162   }
163   y = (int)((m[1] * bbox.urx + m[3] * bbox.ury) * 0.001);
164   if (y < yMin) {
165     yMin = y;
166   } else if (y > yMax) {
167     yMax = y;
168   }
169 #if 1 //~
170   //~ This is a kludge: some buggy PDF generators embed fonts with
171   //~ zero bounding boxes.
172   if (xMax == xMin) {
173     xMin = 0;
174     xMax = (int)size;
175   }
176   if (yMax == yMin) {
177     yMin = 0;
178     yMax = (int)(1.2 * size);
179   }
180 #endif
181   // this should be (max - min + 1), but we add some padding to
182   // deal with rounding errors
183   glyphW = xMax - xMin + 3;
184   glyphH = yMax - yMin + 3;
185   if (engine->aa) {
186     glyphSize = glyphW * glyphH;
187   } else {
188     glyphSize = ((glyphW + 7) >> 3) * glyphH;
189   }
190
191   // set up the glyph pixmap cache
192   cacheAssoc = 8;
193   if (glyphSize <= 256) {
194     cacheSets = 8;
195   } else if (glyphSize <= 512) {
196     cacheSets = 4;
197   } else if (glyphSize <= 1024) {
198     cacheSets = 2;
199   } else {
200     cacheSets = 1;
201   }
202   cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
203   cacheTags = (T1FontCacheTag *)gmalloc(cacheSets * cacheAssoc *
204                                         sizeof(T1FontCacheTag));
205   for (i = 0; i < cacheSets * cacheAssoc; ++i) {
206     cacheTags[i].mru = i & (cacheAssoc - 1);
207   }
208
209   // create the XImage
210   if (!(image = XCreateImage(engine->display, engine->visual, engine->depth,
211                              ZPixmap, 0, NULL, glyphW, glyphH, 8, 0))) {
212     return;
213   }
214   image->data = (char *)gmalloc(glyphH * image->bytes_per_line);
215
216   // transform the font
217   matrix.cxx = m[0] / size;
218   matrix.cxy = m[1] / size;
219   matrix.cyx = m[2] / size;
220   matrix.cyy = m[3] / size;
221   T1_TransformFont(id, &matrix);
222
223   ok = gTrue;
224 }
225
226 T1Font::~T1Font() {
227   gfree(cacheTags);
228   gfree(cache);
229   if (image) {
230     gfree(image->data);
231     image->data = NULL;
232     XDestroyImage(image);
233   }
234   T1_DeleteFont(id);
235 }
236
237 GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
238                        int x, int y, int r, int g, int b, Gushort c) {
239   T1FontEngine *engine;
240   XColor xcolor;
241   int bgR, bgG, bgB;
242   Gulong colors[17];
243   Guchar *p;
244   int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0;
245   int xx, yy, xx1;
246   Guchar pix, mPix;
247   int i;
248
249   engine = fontFile->engine;
250
251   // generate the glyph pixmap
252   if (!(p = getGlyphPixmap(c, &xOffset, &yOffset, &gw, &gh))) {
253     return gFalse;
254   }
255
256   // compute: (x0,y0) = position in destination drawable
257   //          (x1,y1) = position in glyph image
258   //          (w0,h0) = size of image transfer
259   x0 = x - xOffset;
260   y0 = y - yOffset;
261   x1 = 0;
262   y1 = 0;
263   w0 = gw;
264   h0 = gh;
265   if (x0 < 0) {
266     x1 = -x0;
267     w0 += x0;
268     x0 = 0;
269   }
270   if (x0 + w0 > w) {
271     w0 = w - x0;
272   }
273   if (w0 < 0) {
274     return gTrue;
275   }
276   if (y0 < 0) {
277     y1 = -y0;
278     h0 += y0;
279     y0 = 0;
280   }
281   if (y0 + h0 > h) {
282     h0 = h - y0;
283   }
284   if (h0 < 0) {
285     return gTrue;
286   }
287
288   // read the X image
289   XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
290                ZPixmap, image, x1, y1);
291
292   if (engine->aa) {
293
294     // compute the colors
295     xcolor.pixel = XGetPixel(image, x1, y1);
296     XQueryColor(engine->display, engine->colormap, &xcolor);
297     bgR = xcolor.red;
298     bgG = xcolor.green;
299     bgB = xcolor.blue;
300     if (engine->aaHigh) {
301       mPix = 16;
302       for (i = 1; i <= 16; ++i) {
303         colors[i] = engine->findColor((i * r + (16 - i) * bgR) / 16,
304                                       (i * g + (16 - i) * bgG) / 16,
305                                       (i * b + (16 - i) * bgB) / 16);
306       }
307     } else {
308       mPix = 4;
309       colors[1] = engine->findColor((r + 3*bgR) / 4,
310                                     (g + 3*bgG) / 4,
311                                     (b + 3*bgB) / 4);
312       colors[2] = engine->findColor((r + bgR) / 2,
313                                     (g + bgG) / 2,
314                                     (b + bgB) / 2);
315       colors[3] = engine->findColor((3*r + bgR) / 4,
316                                     (3*g + bgG) / 4,
317                                     (3*b + bgB) / 4);
318       colors[4] = engine->findColor(r, g, b);
319     }
320
321     // stuff the glyph pixmap into the X image
322     for (yy = 0; yy < gh; ++yy) {
323       for (xx = 0; xx < gw; ++xx) {
324         pix = *p++;
325         if (pix > 0) {
326           if (pix > mPix) {
327             pix = mPix;
328           }
329           XPutPixel(image, xx, yy, colors[pix]);
330         }
331       }
332     }
333
334   } else {
335
336     // one color
337     colors[1] = engine->findColor(r, g, b);
338
339     // stuff the glyph bitmap into the X image
340     for (yy = 0; yy < gh; ++yy) {
341       for (xx = 0; xx < gw; xx += 8) {
342         pix = *p++;
343         for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
344           if (pix & 0x01) {
345             XPutPixel(image, xx1, yy, colors[1]);
346           }
347           pix >>= 1;
348         }
349       }
350     }
351
352   }
353
354   // draw the X image
355   XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0);
356
357   return gTrue;
358 }
359
360 Guchar *T1Font::getGlyphPixmap(Gushort c, int *x, int *y, int *w, int *h) {
361   T1FontEngine *engine;
362   GLYPH *glyph;
363   int gSize;
364   int i, j, k;
365   Guchar *ret;
366
367   engine = fontFile->engine;
368
369   // check the cache
370   i = (c & (cacheSets - 1)) * cacheAssoc;
371   for (j = 0; j < cacheAssoc; ++j) {
372     if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) {
373       *x = cacheTags[i+j].x;
374       *y = cacheTags[i+j].y;
375       *w = cacheTags[i+j].w;
376       *h = cacheTags[i+j].h;
377       for (k = 0; k < cacheAssoc; ++k) {
378         if (k != j &&
379             (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) {
380           ++cacheTags[i+k].mru;
381         }
382       }
383       cacheTags[i+j].mru = 0x8000;
384       return cache + (i+j) * glyphSize;
385     }
386   }
387
388   // generate the glyph pixmap
389   if (engine->aa) {
390     glyph = T1_AASetChar(id, c, size, NULL);
391   } else {
392     glyph = T1_SetChar(id, c, size, NULL);
393   }
394   if (!glyph) {
395     return NULL;
396   }
397   *x = -glyph->metrics.leftSideBearing;
398   *y = glyph->metrics.ascent;
399   *w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing;
400   *h = glyph->metrics.ascent - glyph->metrics.descent;
401   if (*w > glyphW || *h > glyphH) {
402 #if 1 //~
403     fprintf(stderr, "Weird t1lib glyph size: %d > %d or %d > %d\n",
404             *w, glyphW, *h, glyphH);
405 #endif
406     return NULL;
407   }
408
409   // store glyph pixmap in cache
410   ret = NULL;
411   for (j = 0; j < cacheAssoc; ++j) {
412     if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
413       cacheTags[i+j].mru = 0x8000;
414       cacheTags[i+j].code = c;
415       cacheTags[i+j].x = *x;
416       cacheTags[i+j].y = *y;
417       cacheTags[i+j].w = *w;
418       cacheTags[i+j].h = *h;
419       if (engine->aa) {
420         gSize = *w * *h;
421       } else {
422         gSize = ((*w + 7) >> 3) * *h;
423       }
424       ret = cache + (i+j) * glyphSize;
425       if (glyph->bits) {
426         memcpy(ret, glyph->bits, gSize);
427       } else {
428         memset(ret, 0, gSize);
429       }
430     } else {
431       ++cacheTags[i+j].mru;
432     }
433   }
434   return ret;
435 }
436
437 #endif // HAVE_T1LIB_H