]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/FTFont.cc
Reused eog HIG dialog in GPdf.
[evince.git] / pdf / xpdf / FTFont.cc
1 //========================================================================
2 //
3 // FTFont.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 <math.h>
18 #include <string.h>
19 #include "gmem.h"
20 #include "freetype/ftoutln.h"
21 #include "freetype/internal/ftobjs.h"
22 #if 1 //~ cff cid->gid map
23 #include "freetype/internal/cfftypes.h"
24 #include "freetype/internal/tttypes.h"
25 #endif
26 #include "GlobalParams.h"
27 #include "GfxState.h"
28 #include "FTFont.h"
29
30 //------------------------------------------------------------------------
31
32 FTFontEngine::FTFontEngine(Display *displayA, Visual *visualA, int depthA,
33                            Colormap colormapA, GBool aaA):
34   SFontEngine(displayA, visualA, depthA, colormapA) {
35
36   ok = gFalse;
37   if (FT_Init_FreeType(&lib)) {
38     return;
39   }
40   aa = aaA;
41   ok = gTrue;
42 }
43
44 FTFontEngine::~FTFontEngine() {
45   FT_Done_FreeType(lib);
46 }
47
48 //------------------------------------------------------------------------
49
50 FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
51                        char **fontEnc, GBool pdfFontHasEncoding,
52                        GBool pdfFontIsSymbolic) {
53   char *name;
54   int unicodeCmap, macRomanCmap, msSymbolCmap;
55   int i, j;
56
57   ok = gFalse;
58   engine = engineA;
59   codeMap = NULL;
60   cidToGID = NULL;
61   cidToGIDLen = 0;
62
63   if (FT_New_Face(engine->lib, fontFileName, 0, &face)) {
64     return;
65   }
66
67   if (!strcmp(face->driver->root.clazz->module_name, "type1") ||
68       !strcmp(face->driver->root.clazz->module_name, "cff")) {
69
70     mode = ftFontModeCodeMapDirect;
71     codeMap = (Guint *)gmalloc(256 * sizeof(Guint));
72     for (i = 0; i < 256; ++i) {
73       codeMap[i] = 0;
74       if ((name = fontEnc[i])) {
75         codeMap[i] = FT_Get_Name_Index(face, name);
76       }
77     }
78
79   } else {
80
81     // To match up with the Adobe-defined behaviour, we choose a cmap
82     // like this:
83     // 1. If the PDF font has an encoding:
84     //    1a. If the TrueType font has a Microsoft Unicode cmap, use it,
85     //        and use the Unicode indexes, not the char codes.
86     //    1b. If the PDF font is symbolic and the TrueType font has a
87     //        Microsoft Symbol cmap, use it, and use (0xf000 + char code).
88     //    1c. If the TrueType font has a Macintosh Roman cmap, use it,
89     //        and reverse map the char names through MacRomanEncoding to
90     //        get char codes.
91     // 2. If the PDF font does not have an encoding:
92     //    2a. If the TrueType font has a Macintosh Roman cmap, use it,
93     //        and use char codes directly.
94     //    2b. If the TrueType font has a Microsoft Symbol cmap, use it,
95     //        and use (0xf000 + char code).
96     // 3. If none of these rules apply, use the first cmap and hope for
97     //    the best (this shouldn't happen).
98     unicodeCmap = macRomanCmap = msSymbolCmap = 0xffff;
99     for (i = 0; i < face->num_charmaps; ++i) {
100       if ((face->charmaps[i]->platform_id == 3 &&
101            face->charmaps[i]->encoding_id == 1) ||
102           face->charmaps[i]->platform_id == 0) {
103         unicodeCmap = i;
104       } else if (face->charmaps[i]->platform_id == 1 &&
105                  face->charmaps[i]->encoding_id == 0) {
106         macRomanCmap = i;
107       } else if (face->charmaps[i]->platform_id == 3 &&
108                  face->charmaps[i]->encoding_id == 0) {
109         msSymbolCmap = i;
110       }
111     }
112     i = 0;
113     mode = ftFontModeCharCode;
114     charMapOffset = 0;
115     if (pdfFontHasEncoding) {
116       if (unicodeCmap != 0xffff) {
117         i = unicodeCmap;
118         mode = ftFontModeUnicode;
119       } else if (pdfFontIsSymbolic && msSymbolCmap != 0xffff) {
120         i = msSymbolCmap;
121         mode = ftFontModeCharCodeOffset;
122         charMapOffset = 0xf000;
123       } else if (macRomanCmap != 0xffff) {
124         i = macRomanCmap;
125         mode = ftFontModeCodeMap;
126         codeMap = (Guint *)gmalloc(256 * sizeof(Guint));
127         for (j = 0; j < 256; ++j) {
128           if (fontEnc[j]) {
129             codeMap[j] = globalParams->getMacRomanCharCode(fontEnc[j]);
130           } else {
131             codeMap[j] = 0;
132           }
133         }
134       }
135     } else {
136       if (macRomanCmap != 0xffff) {
137         i = macRomanCmap;
138         mode = ftFontModeCharCode;
139       } else if (msSymbolCmap != 0xffff) {
140         i = msSymbolCmap;
141         mode = ftFontModeCharCodeOffset;
142         charMapOffset = 0xf000;
143       }
144     }
145     if (FT_Set_Charmap(face, face->charmaps[i])) {
146       return;
147     }
148   }
149
150   ok = gTrue;
151 }
152
153 FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
154                        Gushort *cidToGIDA, int cidToGIDLenA, GBool embedded) {
155   int i;
156
157   ok = gFalse;
158   engine = engineA;
159   codeMap = NULL;
160   cidToGID = NULL;
161   cidToGIDLen = 0;
162
163   if (FT_New_Face(engine->lib, fontFileName, 0, &face)) {
164     return;
165   }
166   cidToGIDLen = cidToGIDLenA;
167   cidToGID = (Gushort *)gmalloc(cidToGIDLen * sizeof(Gushort));
168   memcpy(cidToGID, cidToGIDA, cidToGIDLen * sizeof(Gushort));
169   if (!strcmp(face->driver->root.clazz->module_name, "t1cid")) {
170     mode = ftFontModeCID;
171   } else if (!strcmp(face->driver->root.clazz->module_name, "cff")) {
172     mode = ftFontModeCFFCharset;
173   } else if (embedded) {
174     mode = ftFontModeCIDToGIDMap;
175   } else {
176     mode = ftFontModeUnicode;
177     for (i = 0; i < face->num_charmaps; ++i) {
178       if ((face->charmaps[i]->platform_id == 3 &&
179            face->charmaps[i]->encoding_id == 1) ||
180           face->charmaps[i]->platform_id == 0) {
181         break;
182       }
183     }
184     if (i == face->num_charmaps) {
185       i = 0;
186     }
187     FT_Set_Charmap(face, face->charmaps[i]);
188   }
189   ok = gTrue;
190 }
191
192 FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
193                        GBool embedded) {
194   int i;
195
196   ok = gFalse;
197   engine = engineA;
198   codeMap = NULL;
199   cidToGID = NULL;
200   cidToGIDLen = 0;
201
202   if (FT_New_Face(engine->lib, fontFileName, 0, &face)) {
203     return;
204   }
205   if (!strcmp(face->driver->root.clazz->module_name, "t1cid")) {
206     mode = ftFontModeCID;
207   } else if (embedded) {
208     mode = ftFontModeCFFCharset;
209   } else {
210     mode = ftFontModeUnicode;
211     for (i = 0; i < face->num_charmaps; ++i) {
212       if ((face->charmaps[i]->platform_id == 3 &&
213            face->charmaps[i]->encoding_id == 1) ||
214           face->charmaps[i]->platform_id == 0) {
215         break;
216       }
217     }
218     if (i == face->num_charmaps) {
219       i = 0;
220     }
221     FT_Set_Charmap(face, face->charmaps[i]);
222   }
223   ok = gTrue;
224 }
225
226 FTFontFile::~FTFontFile() {
227   if (face) {
228     FT_Done_Face(face);
229   }
230   if (codeMap) {
231     gfree(codeMap);
232   }
233   if (cidToGID) {
234     gfree(cidToGID);
235   }
236 }
237
238 //------------------------------------------------------------------------
239
240 FTFont::FTFont(FTFontFile *fontFileA, double *m) {
241   FTFontEngine *engine;
242   FT_Face face;
243   double size, div;
244   int x, xMin, xMax;
245   int y, yMin, yMax;
246   int i;
247
248   ok = gFalse;
249   fontFile = fontFileA;
250   engine = fontFile->engine;
251   face = fontFile->face;
252   if (FT_New_Size(face, &sizeObj)) {
253     return;
254   }
255   face->size = sizeObj;
256   size = sqrt(m[2]*m[2] + m[3]*m[3]);
257   if (FT_Set_Pixel_Sizes(face, 0, (int)size)) {
258     return;
259   }
260
261   div = face->bbox.xMax > 20000 ? 65536 : 1;
262
263   // transform the four corners of the font bounding box -- the min
264   // and max values form the bounding box of the transformed font
265   x = (int)((m[0] * face->bbox.xMin + m[2] * face->bbox.yMin) /
266             (div * face->units_per_EM));
267   xMin = xMax = x;
268   y = (int)((m[1] * face->bbox.xMin + m[3] * face->bbox.yMin) /
269             (div * face->units_per_EM));
270   yMin = yMax = y;
271   x = (int)((m[0] * face->bbox.xMin + m[2] * face->bbox.yMax) /
272             (div * face->units_per_EM));
273   if (x < xMin) {
274     xMin = x;
275   } else if (x > xMax) {
276     xMax = x;
277   }
278   y = (int)((m[1] * face->bbox.xMin + m[3] * face->bbox.yMax) /
279             (div * face->units_per_EM));
280   if (y < yMin) {
281     yMin = y;
282   } else if (y > yMax) {
283     yMax = y;
284   }
285   x = (int)((m[0] * face->bbox.xMax + m[2] * face->bbox.yMin) /
286             (div * face->units_per_EM));
287   if (x < xMin) {
288     xMin = x;
289   } else if (x > xMax) {
290     xMax = x;
291   }
292   y = (int)((m[1] * face->bbox.xMax + m[3] * face->bbox.yMin) /
293             (div * face->units_per_EM));
294   if (y < yMin) {
295     yMin = y;
296   } else if (y > yMax) {
297     yMax = y;
298   }
299   x = (int)((m[0] * face->bbox.xMax + m[2] * face->bbox.yMax) /
300             (div * face->units_per_EM));
301   if (x < xMin) {
302     xMin = x;
303   } else if (x > xMax) {
304     xMax = x;
305   }
306   y = (int)((m[1] * face->bbox.xMax + m[3] * face->bbox.yMax) /
307             (div * face->units_per_EM));
308   if (y < yMin) {
309     yMin = y;
310   } else if (y > yMax) {
311     yMax = y;
312   }
313   // This is a kludge: some buggy PDF generators embed fonts with
314   // zero bounding boxes.
315   if (xMax == xMin) {
316     xMin = 0;
317     xMax = (int)size;
318   }
319   if (yMax == yMin) {
320     yMin = 0;
321     yMax = (int)(1.2 * size);
322   }
323   // this should be (max - min + 1), but we add some padding to
324   // deal with rounding errors, bogus bboxes, etc.
325   glyphW = xMax - xMin + 3;
326   glyphW += glyphW >> 1;
327   glyphH = yMax - yMin + 3;
328   glyphH += glyphH >> 1;
329   if (engine->aa) {
330     glyphSize = glyphW * glyphH;
331   } else {
332     glyphSize = ((glyphW + 7) >> 3) * glyphH;
333   }
334
335   // set up the glyph pixmap cache
336   cacheAssoc = 8;
337   if (glyphSize <= 256) {
338     cacheSets = 8;
339   } else if (glyphSize <= 512) {
340     cacheSets = 4;
341   } else if (glyphSize <= 1024) {
342     cacheSets = 2;
343   } else {
344     cacheSets = 1;
345   }
346   cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
347   cacheTags = (FTFontCacheTag *)gmalloc(cacheSets * cacheAssoc *
348                                         sizeof(FTFontCacheTag));
349   for (i = 0; i < cacheSets * cacheAssoc; ++i) {
350     cacheTags[i].mru = i & (cacheAssoc - 1);
351   }
352
353   // create the XImage
354   if (!(image = XCreateImage(engine->display, engine->visual, engine->depth,
355                              ZPixmap, 0, NULL, glyphW, glyphH, 8, 0))) {
356     return;
357   }
358   image->data = (char *)gmalloc(glyphH * image->bytes_per_line);
359
360   // compute the transform matrix
361   matrix.xx = (FT_Fixed)((m[0] / size) * 65536);
362   matrix.yx = (FT_Fixed)((m[1] / size) * 65536);
363   matrix.xy = (FT_Fixed)((m[2] / size) * 65536);
364   matrix.yy = (FT_Fixed)((m[3] / size) * 65536);
365
366   ok = gTrue;
367 }
368
369 FTFont::~FTFont() {
370   gfree(cacheTags);
371   gfree(cache);
372   gfree(image->data);
373   image->data = NULL;
374   XDestroyImage(image);
375 }
376
377 GBool FTFont::drawChar(Drawable d, int w, int h, GC gc,
378                        int x, int y, int r, int g, int b,
379                        CharCode c, Unicode u) {
380   FTFontEngine *engine;
381   XColor xcolor;
382   int bgR, bgG, bgB;
383   Gulong colors[5];
384   Guchar *bitmap, *p;
385   GBool tempBitmap;
386   XImage *img;
387   int pix;
388   int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0;
389   int xx, yy, xx1;
390
391   engine = fontFile->engine;
392
393   // no Unicode index for this char - don't draw anything
394   if (fontFile->mode == ftFontModeUnicode && u == 0) {
395     return gFalse;
396   }
397
398   // generate the glyph pixmap
399   if (!(bitmap = getGlyphPixmap(c, u, &xOffset, &yOffset, &gw, &gh,
400                                 &tempBitmap))) {
401     return gFalse;
402   }
403
404   // compute: (x0,y0) = position in destination drawable
405   //          (x1,y1) = position in glyph image
406   //          (w0,h0) = size of image transfer
407   x0 = x - xOffset;
408   y0 = y - yOffset;
409   x1 = 0;
410   y1 = 0;
411   w0 = gw;
412   h0 = gh;
413   if (x0 < 0) {
414     x1 = -x0;
415     w0 += x0;
416     x0 = 0;
417   }
418   if (x0 + w0 > w) {
419     w0 = w - x0;
420   }
421   if (w0 < 0) {
422     goto done;
423   }
424   if (y0 < 0) {
425     y1 = -y0;
426     h0 += y0;
427     y0 = 0;
428   }
429   if (y0 + h0 > h) {
430     h0 = h - y0;
431   }
432   if (h0 < 0) {
433     goto done;
434   }
435
436   // getGlyphPixmap may have returned a larger-than-cache-entry
437   // bitmap, in which case we need to allocate a temporary XImage here
438   if (tempBitmap) {
439     if (!(img = XCreateImage(engine->display, engine->visual, engine->depth,
440                              ZPixmap, 0, NULL, gw, gh, 8, 0))) {
441       goto done;
442     }
443     img->data = (char *)gmalloc(gh * img->bytes_per_line);
444   } else {
445     img = image;
446   }
447
448   // read the X image
449   XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
450                ZPixmap, img, x1, y1);
451
452   if (engine->aa) {
453
454     // compute the colors
455     xcolor.pixel = XGetPixel(img, x1 + w0/2, y1 + h0/2);
456     XQueryColor(engine->display, engine->colormap, &xcolor);
457     bgR = xcolor.red;
458     bgG = xcolor.green;
459     bgB = xcolor.blue;
460     colors[1] = engine->findColor((r + 3*bgR) / 4,
461                                   (g + 3*bgG) / 4,
462                                   (b + 3*bgB) / 4);
463     colors[2] = engine->findColor((r + bgR) / 2,
464                                   (g + bgG) / 2,
465                                   (b + bgB) / 2);
466     colors[3] = engine->findColor((3*r + bgR) / 4,
467                                   (3*g + bgG) / 4,
468                                   (3*b + bgB) / 4);
469     colors[4] = engine->findColor(r, g, b);
470
471     // stuff the glyph pixmap into the X image
472     p = bitmap;
473     for (yy = 0; yy < gh; ++yy) {
474       for (xx = 0; xx < gw; ++xx) {
475         pix = *p++ & 0xff;
476         // this is a heuristic which seems to produce decent
477         // results -- the linear mapping would be:
478         // pix = (pix * 5) / 256;
479         pix = ((pix + 10) * 5) / 256;
480         if (pix > 4) {
481           pix = 4;
482         }
483         if (pix > 0) {
484           XPutPixel(img, xx, yy, colors[pix]);
485         }
486       }
487     }
488
489   } else {
490
491     // one color
492     colors[1] = engine->findColor(r, g, b);
493
494     // stuff the glyph bitmap into the X image
495     p = bitmap;
496     for (yy = 0; yy < gh; ++yy) {
497       for (xx = 0; xx < gw; xx += 8) {
498         pix = *p++;
499         for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
500           if (pix & 0x80) {
501             XPutPixel(img, xx1, yy, colors[1]);
502           }
503           pix <<= 1;
504         }
505       }
506     }
507
508   }
509
510   // draw the X image
511   XPutImage(engine->display, d, gc, img, x1, y1, x0, y0, w0, h0);
512
513   if (tempBitmap) {
514     gfree(img->data);
515     img->data = NULL;
516     XDestroyImage(img);
517   }
518  done:
519   if (tempBitmap) {
520     gfree(bitmap);
521   }
522   return gTrue;
523 }
524
525 Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u,
526                                int *x, int *y, int *w, int *h,
527                                GBool *tempBitmap) {
528   FT_GlyphSlot slot;
529   FT_UInt idx;
530   int rowSize;
531   int i, j, k;
532   Guchar *ret, *p, *q;
533
534   // check the cache
535   i = (c & (cacheSets - 1)) * cacheAssoc;
536   for (j = 0; j < cacheAssoc; ++j) {
537     if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) {
538       *x = cacheTags[i+j].x;
539       *y = cacheTags[i+j].y;
540       *w = cacheTags[i+j].w;
541       *h = cacheTags[i+j].h;
542       for (k = 0; k < cacheAssoc; ++k) {
543         if (k != j &&
544             (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) {
545           ++cacheTags[i+k].mru;
546         }
547       }
548       cacheTags[i+j].mru = 0x8000;
549       *tempBitmap = gFalse;
550       return cache + (i+j) * glyphSize;
551     }
552   }
553
554   // generate the glyph pixmap or bitmap
555   fontFile->face->size = sizeObj;
556   FT_Set_Transform(fontFile->face, &matrix, NULL);
557   slot = fontFile->face->glyph;
558   idx = getGlyphIndex(c, u);
559   // if we have the FT2 bytecode interpreter, autohinting won't be used
560 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
561   if (FT_Load_Glyph(fontFile->face, idx, FT_LOAD_DEFAULT)) {
562     return gFalse;
563   }
564 #else
565   // FT2's autohinting doesn't always work very well (especially with
566   // font subsets), so turn it off if anti-aliasing is enabled; if
567   // anti-aliasing is disabled, this seems to be a tossup - some fonts
568   // look better with hinting, some without, so leave hinting on
569   if (FT_Load_Glyph(fontFile->face, idx,
570                     fontFile->engine->aa ? FT_LOAD_NO_HINTING
571                                          : FT_LOAD_DEFAULT)) {
572     return gFalse;
573   }
574 #endif
575   if (FT_Render_Glyph(slot,
576                       fontFile->engine->aa ? ft_render_mode_normal :
577                                              ft_render_mode_mono)) {
578     return gFalse;
579   }
580
581   // copy the glyph into the cache or a temporary bitmap
582   *x = -slot->bitmap_left;
583   *y = slot->bitmap_top;
584   *w = slot->bitmap.width;
585   *h = slot->bitmap.rows;
586   if (fontFile->engine->aa) {
587     rowSize = *w;
588   } else {
589     rowSize = (*w + 7) >> 3;
590   }
591   if (*w > glyphW || *h > glyphH) {
592     // the glyph doesn't fit in the bounding box -- return a
593     // temporary, uncached bitmap (this shouldn't happen but some
594     // fonts have incorrect bboxes)
595     ret = (Guchar *)gmalloc(*h * rowSize);
596     *tempBitmap = gTrue;
597   } else {
598     // store glyph pixmap in cache
599     ret = NULL; // make gcc happy
600     for (j = 0; j < cacheAssoc; ++j) {
601       if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
602         cacheTags[i+j].mru = 0x8000;
603         cacheTags[i+j].code = c;
604         cacheTags[i+j].x = *x;
605         cacheTags[i+j].y = *y;
606         cacheTags[i+j].w = *w;
607         cacheTags[i+j].h = *h;
608         ret = cache + (i+j) * glyphSize;
609       } else {
610         ++cacheTags[i+j].mru;
611       }
612     }
613     *tempBitmap = gFalse;
614   }
615   for (k = 0, p = ret, q = slot->bitmap.buffer;
616        k < slot->bitmap.rows;
617        ++k, p += rowSize, q += slot->bitmap.pitch) {
618     memcpy(p, q, rowSize);
619   }
620   return ret;
621 }
622
623 GBool FTFont::getCharPath(CharCode c, Unicode u, GfxState *state) {
624   static FT_Outline_Funcs outlineFuncs = {
625     &charPathMoveTo,
626     &charPathLineTo,
627     &charPathConicTo,
628     &charPathCubicTo,
629     0, 0
630   };
631   FT_GlyphSlot slot;
632   FT_UInt idx;
633   FT_Glyph glyph;
634
635   fontFile->face->size = sizeObj;
636   FT_Set_Transform(fontFile->face, &matrix, NULL);
637   slot = fontFile->face->glyph;
638   idx = getGlyphIndex(c, u);
639 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
640   if (FT_Load_Glyph(fontFile->face, idx, FT_LOAD_DEFAULT)) {
641     return gFalse;
642   }
643 #else
644   // FT2's autohinting doesn't always work very well (especially with
645   // font subsets), so turn it off if anti-aliasing is enabled; if
646   // anti-aliasing is disabled, this seems to be a tossup - some fonts
647   // look better with hinting, some without, so leave hinting on
648   if (FT_Load_Glyph(fontFile->face, idx,
649                     fontFile->engine->aa ? FT_LOAD_NO_HINTING
650                                          : FT_LOAD_DEFAULT)) {
651     return gFalse;
652   }
653 #endif
654   if (FT_Get_Glyph(slot, &glyph)) {
655     return gFalse;
656   }
657   FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
658                        &outlineFuncs, state);
659   return gTrue;
660 }
661
662 int FTFont::charPathMoveTo(FT_Vector *pt, void *state) {
663   ((GfxState *)state)->moveTo(pt->x / 64.0, -pt->y / 64.0);
664   return 0;
665 }
666
667 int FTFont::charPathLineTo(FT_Vector *pt, void *state) {
668   ((GfxState *)state)->lineTo(pt->x / 64.0, -pt->y / 64.0);
669   return 0;
670 }
671
672 int FTFont::charPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *state) {
673   double x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
674
675   x0 = ((GfxState *)state)->getCurX();
676   y0 = ((GfxState *)state)->getCurY();
677   xc = ctrl->x / 64.0;
678   yc = -ctrl->y / 64.0;
679   x3 = pt->x / 64.0;
680   y3 = -pt->y / 64.0;
681
682   // A second-order Bezier curve is defined by two endpoints, p0 and
683   // p3, and one control point, pc:
684   //
685   //     p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
686   //
687   // A third-order Bezier curve is defined by the same two endpoints,
688   // p0 and p3, and two control points, p1 and p2:
689   //
690   //     p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
691   //
692   // Applying some algebra, we can convert a second-order curve to a
693   // third-order curve:
694   //
695   //     p1 = (1/3) * (p0 + 2pc)
696   //     p2 = (1/3) * (2pc + p3)
697
698   x1 = (1.0 / 3.0) * (x0 + 2 * xc);
699   y1 = (1.0 / 3.0) * (y0 + 2 * yc);
700   x2 = (1.0 / 3.0) * (2 * xc + x3);
701   y2 = (1.0 / 3.0) * (2 * yc + y3);
702
703   ((GfxState *)state)->curveTo(x1, y1, x2, y2, x3, y3);
704   return 0;
705 }
706
707 int FTFont::charPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2,
708                             FT_Vector *pt, void *state) {
709   ((GfxState *)state)->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0,
710                                ctrl2->x / 64.0, -ctrl2->y / 64.0,
711                                pt->x / 64.0, -pt->y / 64.0);
712   return 0;
713 }
714
715 FT_UInt FTFont::getGlyphIndex(CharCode c, Unicode u) {
716   FT_UInt idx;
717   int j;
718
719   idx = 0; // make gcc happy
720   switch (fontFile->mode) {
721   case ftFontModeUnicode:
722     idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)u);
723     break;
724   case ftFontModeCharCode:
725     idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)c);
726     break;
727   case ftFontModeCharCodeOffset:
728     if ((idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)c)) == 0) {
729       idx = FT_Get_Char_Index(fontFile->face,
730                               (FT_ULong)(c + fontFile->charMapOffset));
731     }
732     break;
733   case ftFontModeCodeMap:
734     if (c <= 0xff) {
735       idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)fontFile->codeMap[c]);
736     } else {
737       idx = 0;
738     }
739     break;
740   case ftFontModeCodeMapDirect:
741     if (c <= 0xff) {
742       idx = (FT_UInt)fontFile->codeMap[c];
743     } else {
744       idx = 0;
745     }
746     break;
747   case ftFontModeCIDToGIDMap:
748     if (fontFile->cidToGIDLen) {
749       if ((int)c < fontFile->cidToGIDLen) {
750         idx = (FT_UInt)fontFile->cidToGID[c];
751       } else {
752         idx = (FT_UInt)0;
753       }
754     } else {
755       idx = (FT_UInt)c;
756     }
757     break;
758   case ftFontModeCFFCharset:
759 #if 1 //~ cff cid->gid map
760     {
761 #if FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 0
762       CFF_Font *cff = (CFF_Font *)((TT_Face)fontFile->face)->extra.data;
763 #else
764       CFF_Font cff = (CFF_Font)((TT_Face)fontFile->face)->extra.data;
765 #endif
766       idx = 0;
767       for (j = 0; j < (int)cff->num_glyphs; ++j) {
768         if (cff->charset.sids[j] == c) {
769           idx = j;
770           break;
771         }
772       }
773     }
774 #endif
775     break;
776   case ftFontModeCID:
777     idx = c;
778     break;
779   }
780   return idx;
781 }
782
783 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)