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