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