]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/T1Font.cc
a03351d2355d20d20597c0f34497a5dcefcb82b0
[evince.git] / pdf / xpdf / T1Font.cc
1 //========================================================================
2 //
3 // T1Font.cc
4 //
5 // Copyright 2001-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #if HAVE_T1LIB_H
12
13 #ifdef USE_GCC_PRAGMAS
14 #pragma implementation
15 #endif
16
17 #include <math.h>
18 #include <string.h>
19 #include <X11/Xlib.h>
20 #include "gmem.h"
21 #include "GfxState.h"
22 #include "T1Font.h"
23
24 //------------------------------------------------------------------------
25
26 int T1FontEngine::t1libInitCount = 0;
27
28 //------------------------------------------------------------------------
29
30 T1FontEngine::T1FontEngine(Display *displayA, Visual *visualA, int depthA,
31                            Colormap colormapA, GBool aaA, GBool aaHighA):
32   SFontEngine(displayA, visualA, depthA, colormapA)
33 {
34   static unsigned long grayVals[17] = {
35     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
36   };
37
38   ok = gFalse;
39   aa = aaA;
40   aaHigh = aaHighA;
41   //~ for multithreading: need a mutex here
42   if (t1libInitCount == 0) {
43     T1_SetBitmapPad(8);
44     if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE |
45                     T1_NO_AFM)) {
46       return;
47     }
48     if (aa) {
49       T1_AASetBitsPerPixel(8);
50       if (aaHigh) {
51         T1_AASetLevel(T1_AA_HIGH);
52         T1_AAHSetGrayValues(grayVals);
53       } else {
54         T1_AASetLevel(T1_AA_LOW);
55         T1_AASetGrayValues(0, 1, 2, 3, 4);
56       }
57     } else {
58       T1_AANSetGrayValues(0, 1);
59     }
60   }
61   ++t1libInitCount;
62   ok = gTrue;
63 }
64
65 T1FontEngine::~T1FontEngine() {
66   //~ for multithreading: need a mutex here
67   if (--t1libInitCount == 0) {
68     T1_CloseLib();
69   }
70 }
71
72 //------------------------------------------------------------------------
73
74 T1FontFile::T1FontFile(T1FontEngine *engineA, char *fontFileName,
75                        char **fontEnc, double *bboxA) {
76   int encStrSize;
77   char *encPtr;
78   int i;
79
80   ok = gFalse;
81   engine = engineA;
82   enc = NULL;
83   encStr = NULL;
84   for (i = 0; i < 4; ++i) {
85     bbox[i] = bboxA[i];
86   }
87
88   // load the font file
89   if ((id = T1_AddFont(fontFileName)) < 0) {
90     return;
91   }
92   T1_LoadFont(id);
93
94   // reencode it
95   encStrSize = 0;
96   for (i = 0; i < 256; ++i) {
97     if (fontEnc[i]) {
98       encStrSize += strlen(fontEnc[i]) + 1;
99     }
100   }
101   enc = (char **)gmalloc(257 * sizeof(char *));
102   encStr = (char *)gmalloc(encStrSize * sizeof(char));
103   encPtr = encStr;
104   for (i = 0; i < 256; ++i) {
105     if (fontEnc[i]) {
106       strcpy(encPtr, fontEnc[i]);
107       enc[i] = encPtr;
108       encPtr += strlen(encPtr) + 1;
109     } else {
110       enc[i] = ".notdef";
111     }
112   }
113   enc[256] = "custom";
114   T1_ReencodeFont(id, enc);
115
116   ok = gTrue;
117 }
118
119 T1FontFile::~T1FontFile() {
120   gfree(enc);
121   gfree(encStr);
122   if (id >= 0) {
123     T1_DeleteFont(id);
124   }
125 }
126
127 //------------------------------------------------------------------------
128
129 T1Font::T1Font(T1FontFile *fontFileA, double *m) {
130   T1FontEngine *engine;
131   T1_TMATRIX matrix;
132   BBox bbox;
133   double bbx0, bby0, bbx1, bby1;
134   int x, y, xMin, xMax, yMin, yMax;
135   int i;
136
137   ok = gFalse;
138   fontFile = fontFileA;
139   engine = fontFile->engine;
140
141   id = T1_CopyFont(fontFile->id);
142
143   // compute font size
144   size = (float)sqrt(m[2]*m[2] + m[3]*m[3]);
145
146   // transform the four corners of the font bounding box -- the min
147   // and max values form the bounding box of the transformed font
148   bbx0 = fontFile->bbox[0];
149   bby0 = fontFile->bbox[1];
150   bbx1 = fontFile->bbox[2];
151   bby1 = fontFile->bbox[3];
152   // some fonts in PDF files have bboxes which are just plain wrong,
153   // so we check the font file's bbox too
154   bbox = T1_GetFontBBox(id);
155   if (0.001 * bbox.llx < bbx0) {
156     bbx0 = 0.001 * bbox.llx;
157   }
158   if (0.001 * bbox.lly < bby0) {
159     bby0 = 0.001 * bbox.lly;
160   }
161   if (0.001 * bbox.urx > bbx1) {
162     bbx1 = 0.001 * bbox.urx;
163   }
164   if (0.001 * bbox.ury > bby1) {
165     bby1 = 0.001 * bbox.ury;
166   }
167   // some fonts are completely broken, so we fake it (with values
168   // large enough that most glyphs should fit)
169   if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) {
170     bbx0 = bby0 = -0.5;
171     bbx1 = bby1 = 1.5;
172   }
173   x = (int)(m[0] * bbx0 + m[2] * bby0);
174   xMin = xMax = x;
175   y = (int)(m[1] * bbx0 + m[3] * bby0);
176   yMin = yMax = y;
177   x = (int)(m[0] * bbx0 + m[2] * bby1);
178   if (x < xMin) {
179     xMin = x;
180   } else if (x > xMax) {
181     xMax = x;
182   }
183   y = (int)(m[1] * bbx0 + m[3] * bby1);
184   if (y < yMin) {
185     yMin = y;
186   } else if (y > yMax) {
187     yMax = y;
188   }
189   x = (int)(m[0] * bbx1 + m[2] * bby0);
190   if (x < xMin) {
191     xMin = x;
192   } else if (x > xMax) {
193     xMax = x;
194   }
195   y = (int)(m[1] * bbx1 + m[3] * bby0);
196   if (y < yMin) {
197     yMin = y;
198   } else if (y > yMax) {
199     yMax = y;
200   }
201   x = (int)(m[0] * bbx1 + m[2] * bby1);
202   if (x < xMin) {
203     xMin = x;
204   } else if (x > xMax) {
205     xMax = x;
206   }
207   y = (int)(m[1] * bbx1 + m[3] * bby1);
208   if (y < yMin) {
209     yMin = y;
210   } else if (y > yMax) {
211     yMax = y;
212   }
213   // This is a kludge: some buggy PDF generators embed fonts with
214   // zero bounding boxes.
215   if (xMax == xMin) {
216     xMin = 0;
217     xMax = (int)size;
218   }
219   if (yMax == yMin) {
220     yMin = 0;
221     yMax = (int)(1.2 * size);
222   }
223   // Another kludge: an unusually large xMin or yMin coordinate is
224   // probably wrong.
225   if (xMin > 0) {
226     xMin = 0;
227   }
228   if (yMin > 0) {
229     yMin = 0;
230   }
231   // Another kludge: t1lib doesn't correctly handle fonts with
232   // real (non-integer) bounding box coordinates.
233   if (xMax - xMin > 5000) {
234     xMin = 0;
235     xMax = (int)size;
236   }
237   if (yMax - yMin > 5000) {
238     yMin = 0;
239     yMax = (int)(1.2 * size);
240   }
241   // this should be (max - min + 1), but we add some padding to
242   // deal with rounding errors
243   glyphW = xMax - xMin + 3;
244   glyphH = yMax - yMin + 3;
245   if (engine->aa) {
246     glyphSize = glyphW * glyphH;
247   } else {
248     glyphSize = ((glyphW + 7) >> 3) * glyphH;
249   }
250
251   // set up the glyph pixmap cache
252   cacheAssoc = 8;
253   if (glyphSize <= 256) {
254     cacheSets = 8;
255   } else if (glyphSize <= 512) {
256     cacheSets = 4;
257   } else if (glyphSize <= 1024) {
258     cacheSets = 2;
259   } else {
260     cacheSets = 1;
261   }
262   cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
263   cacheTags = (T1FontCacheTag *)gmalloc(cacheSets * cacheAssoc *
264                                         sizeof(T1FontCacheTag));
265   for (i = 0; i < cacheSets * cacheAssoc; ++i) {
266     cacheTags[i].mru = i & (cacheAssoc - 1);
267   }
268
269   // create the XImage
270   if (!(image = XCreateImage(engine->display, engine->visual, engine->depth,
271                              ZPixmap, 0, NULL, glyphW, glyphH, 8, 0))) {
272     return;
273   }
274   image->data = (char *)gmalloc(glyphH * image->bytes_per_line);
275
276   // transform the font
277   matrix.cxx = m[0] / size;
278   matrix.cxy = m[1] / size;
279   matrix.cyx = m[2] / size;
280   matrix.cyy = m[3] / size;
281   T1_TransformFont(id, &matrix);
282
283   ok = gTrue;
284 }
285
286 T1Font::~T1Font() {
287   gfree(cacheTags);
288   gfree(cache);
289   if (image) {
290     gfree(image->data);
291     image->data = NULL;
292     XDestroyImage(image);
293   }
294   T1_DeleteFont(id);
295 }
296
297 GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
298                        int x, int y, int r, int g, int b,
299                        CharCode c, Unicode u) {
300   T1FontEngine *engine;
301   XColor xcolor;
302   int bgR, bgG, bgB;
303   Gulong colors[17];
304   Guchar *bitmap, *p;
305   GBool tempBitmap;
306   XImage *img;
307   int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0;
308   int xx, yy, xx1;
309   Guchar pix, mPix;
310   int i;
311
312   engine = fontFile->engine;
313
314   // generate the glyph pixmap
315   if (!(bitmap = getGlyphPixmap(c, &xOffset, &yOffset, &gw, &gh,
316                                 &tempBitmap))) {
317     return gFalse;
318   }
319
320   // compute: (x0,y0) = position in destination drawable
321   //          (x1,y1) = position in glyph image
322   //          (w0,h0) = size of image transfer
323   x0 = x - xOffset;
324   y0 = y - yOffset;
325   x1 = 0;
326   y1 = 0;
327   w0 = gw;
328   h0 = gh;
329   if (x0 < 0) {
330     x1 = -x0;
331     w0 += x0;
332     x0 = 0;
333   }
334   if (x0 + w0 > w) {
335     w0 = w - x0;
336   }
337   if (w0 < 0) {
338     goto done;
339   }
340   if (y0 < 0) {
341     y1 = -y0;
342     h0 += y0;
343     y0 = 0;
344   }
345   if (y0 + h0 > h) {
346     h0 = h - y0;
347   }
348   if (h0 < 0) {
349     goto done;
350   }
351
352   // getGlyphPixmap may have returned a larger-than-cache-entry
353   // bitmap, in which case we need to allocate a temporary XImage here
354   if (tempBitmap) {
355     if (!(img = XCreateImage(engine->display, engine->visual, engine->depth,
356                              ZPixmap, 0, NULL, gw, gh, 8, 0))) {
357       goto done;
358     }
359     img->data = (char *)gmalloc(gh * img->bytes_per_line);
360   } else {
361     img = image;
362   }
363
364   // read the X image
365   XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
366                ZPixmap, img, x1, y1);
367
368   if (engine->aa) {
369
370     // compute the colors
371     xcolor.pixel = XGetPixel(img, x1 + w0/2, y1 + h0/2);
372     XQueryColor(engine->display, engine->colormap, &xcolor);
373     bgR = xcolor.red;
374     bgG = xcolor.green;
375     bgB = xcolor.blue;
376     if (engine->aaHigh) {
377       mPix = 16;
378       for (i = 1; i <= 16; ++i) {
379         colors[i] = engine->findColor((i * r + (16 - i) * bgR) / 16,
380                                       (i * g + (16 - i) * bgG) / 16,
381                                       (i * b + (16 - i) * bgB) / 16);
382       }
383     } else {
384       mPix = 4;
385       colors[1] = engine->findColor((r + 3*bgR) / 4,
386                                     (g + 3*bgG) / 4,
387                                     (b + 3*bgB) / 4);
388       colors[2] = engine->findColor((r + bgR) / 2,
389                                     (g + bgG) / 2,
390                                     (b + bgB) / 2);
391       colors[3] = engine->findColor((3*r + bgR) / 4,
392                                     (3*g + bgG) / 4,
393                                     (3*b + bgB) / 4);
394       colors[4] = engine->findColor(r, g, b);
395     }
396
397     // stuff the glyph pixmap into the X image
398     p = bitmap;
399     for (yy = 0; yy < gh; ++yy) {
400       for (xx = 0; xx < gw; ++xx) {
401         pix = *p++;
402         if (pix > 0) {
403           if (pix > mPix) {
404             pix = mPix;
405           }
406           XPutPixel(img, xx, yy, colors[pix]);
407         }
408       }
409     }
410
411   } else {
412
413     // one color
414     colors[1] = engine->findColor(r, g, b);
415
416     // stuff the glyph bitmap into the X image
417     p = bitmap;
418     for (yy = 0; yy < gh; ++yy) {
419       for (xx = 0; xx < gw; xx += 8) {
420         pix = *p++;
421         for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
422           if (pix & 0x01) {
423             XPutPixel(img, xx1, yy, colors[1]);
424           }
425           pix >>= 1;
426         }
427       }
428     }
429
430   }
431
432   // draw the X image
433   XPutImage(engine->display, d, gc, img, x1, y1, x0, y0, w0, h0);
434
435   if (tempBitmap) {
436     gfree(img->data);
437     img->data = NULL;
438     XDestroyImage(img);
439   }
440  done:
441   if (tempBitmap) {
442     gfree(bitmap);
443   }
444   return gTrue;
445 }
446
447 Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h,
448                                GBool *tempBitmap) {
449   T1FontEngine *engine;
450   GLYPH *glyph;
451   int gSize;
452   int i, j, k;
453   Guchar *ret;
454
455   engine = fontFile->engine;
456
457   // check the cache
458   i = (c & (cacheSets - 1)) * cacheAssoc;
459   for (j = 0; j < cacheAssoc; ++j) {
460     if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) {
461       *x = cacheTags[i+j].x;
462       *y = cacheTags[i+j].y;
463       *w = cacheTags[i+j].w;
464       *h = cacheTags[i+j].h;
465       for (k = 0; k < cacheAssoc; ++k) {
466         if (k != j &&
467             (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) {
468           ++cacheTags[i+k].mru;
469         }
470       }
471       cacheTags[i+j].mru = 0x8000;
472       *tempBitmap = gFalse;
473       return cache + (i+j) * glyphSize;
474     }
475   }
476
477   // generate the glyph pixmap
478   if (engine->aa) {
479     glyph = T1_AASetChar(id, c, size, NULL);
480   } else {
481     glyph = T1_SetChar(id, c, size, NULL);
482   }
483   if (!glyph) {
484     return NULL;
485   }
486
487   // copy the glyph into the cache or a temporary bitmap
488   *x = -glyph->metrics.leftSideBearing;
489   *y = glyph->metrics.ascent;
490   *w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing;
491   *h = glyph->metrics.ascent - glyph->metrics.descent;
492   if (engine->aa) {
493     gSize = *w * *h;
494   } else {
495     gSize = ((*w + 7) >> 3) * *h;
496   }
497   if (*w > glyphW || *h > glyphH) {
498     // the glyph doesn't fit in the bounding box -- return a
499     // temporary, uncached bitmap (this shouldn't happen but some
500     // fonts have incorrect bboxes)
501     ret = (Guchar *)gmalloc(gSize);
502     *tempBitmap = gTrue;
503   } else {
504     // store glyph pixmap in cache
505     ret = NULL; // make gcc happy
506     for (j = 0; j < cacheAssoc; ++j) {
507       if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
508         cacheTags[i+j].mru = 0x8000;
509         cacheTags[i+j].code = c;
510         cacheTags[i+j].x = *x;
511         cacheTags[i+j].y = *y;
512         cacheTags[i+j].w = *w;
513         cacheTags[i+j].h = *h;
514         ret = cache + (i+j) * glyphSize;
515       } else {
516         ++cacheTags[i+j].mru;
517       }
518     }
519     *tempBitmap = gFalse;
520   }
521   if (glyph->bits) {
522     memcpy(ret, glyph->bits, gSize);
523   } else {
524     memset(ret, 0, gSize);
525   }
526   return ret;
527 }
528
529 GBool T1Font::getCharPath(CharCode c, Unicode u, GfxState *state) {
530   T1_OUTLINE *outline;
531   T1_PATHSEGMENT *seg;
532   T1_BEZIERSEGMENT *bez;
533   double x, y, x1, y1;
534
535   outline = T1_GetCharOutline(id, c, size, NULL);
536   x = 0;
537   y = 0;
538   for (seg = outline; seg; seg = seg->link) {
539     switch (seg->type) {
540     case T1_PATHTYPE_MOVE:
541       x += seg->dest.x / 65536.0;
542       y += seg->dest.y / 65536.0;
543       state->moveTo(x, y);
544       break;
545     case T1_PATHTYPE_LINE:
546       x += seg->dest.x / 65536.0;
547       y += seg->dest.y / 65536.0;
548       state->lineTo(x, y);
549       break;
550     case T1_PATHTYPE_BEZIER:
551       bez = (T1_BEZIERSEGMENT *)seg;
552       x1 = x + bez->dest.x / 65536.0;
553       y1 = y + bez->dest.y / 65536.0;
554       state->curveTo(x + bez->B.x / 65536.0, y + bez->B.y / 65536.0,
555                      x + bez->C.x / 65536.0, y + bez->C.y / 65536.0,
556                      x1, y1);
557       x = x1;
558       y = y1;
559       break;
560     }
561   }
562   T1_FreeOutline(outline);
563   return gTrue;
564 }
565
566 #endif // HAVE_T1LIB_H