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