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