1 /* font-ft.c -- FreeType interface sub-module.
2 Copyright (C) 2003, 2004
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n library.
8 The m17n library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public License
10 as published by the Free Software Foundation; either version 2.1 of
11 the License, or (at your option) any later version.
13 The m17n library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with the m17n library; if not, write to the Free
20 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 #include <sys/types.h>
35 #include "m17n-misc.h"
38 #include "internal-gui.h"
49 /* Having Xft2 means having fontconfig. */
50 #include <fontconfig/fontconfig.h>
52 int fontconfig_initialized = 0;
54 #endif /* not HAVE_XFT2 */
56 static FT_Library ft_library;
61 MSymbol weight, style, stretch;
64 static int ft_to_prop_size;
65 static MFTtoProp *ft_to_prop;
72 int otf_flag; /* This font 1: is OTF, 0: may be OTF, -1: is not OTF. */
81 #endif /* not HAVE_XFT2 */
84 /* List of FreeType fonts. Keys are family names, values are plists
85 contains fonts of the corresponding family. In the deeper plist,
86 keys are Mt, values are (MFTInfo *). */
87 static MPlist *ft_font_list;
89 /** Return 0 if NAME implies TrueType or OpenType fonts. Othersize
93 check_otf_filename (const char *name)
95 int len = strlen (name);
96 const char *ext = name + (len - 4);
99 || (memcmp (ext, ".ttf", 4)
100 && memcmp (ext, ".TTF", 4)
101 && memcmp (ext, ".otf", 4)
102 && memcmp (ext, ".OTF", 4)))
107 /** Setup members of FT_INFO from FT_FACE. Return the family name. */
110 set_font_info (FT_Face ft_face, MFTInfo *ft_info, MSymbol family)
112 MFont *font = &ft_info->font;
116 MPlist *charmap_list;
117 int unicode_bmp = -1, unicode_full = -1;
124 len = strlen (ft_face->family_name) + 1;
125 buf = (char *) alloca (len);
126 memcpy (buf, ft_face->family_name, len);
127 for (p = buf; *p; p++)
128 if (*p >= 'A' && *p <= 'Z')
130 family = msymbol (buf);
132 mfont__set_property (font, MFONT_FAMILY, family);
134 if (ft_face->style_name)
136 len = strlen (ft_face->style_name) + 1;
137 buf = (char *) alloca (len);
138 memcpy (buf, ft_face->style_name, len);
139 for (p = buf; *p; p++)
140 if (*p >= 'A' && *p <= 'Z')
142 style = msymbol (buf);
143 for (i = 0; i < ft_to_prop_size; i++)
144 if (ft_to_prop[i].ft_style == style)
146 mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight);
147 mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style);
148 mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch);
155 if (i == ft_to_prop_size)
157 mfont__set_property (font, MFONT_WEIGHT, msymbol ("medium"));
158 mfont__set_property (font, MFONT_STYLE, msymbol ("r"));
159 mfont__set_property (font, MFONT_STRETCH, msymbol ("normal"));
162 font->property[MFONT_TYPE] = MFONT_TYPE_FT + 1;
163 mfont__set_property (font, MFONT_ADSTYLE, msymbol (""));
165 charmap_list = mplist ();
166 mplist_add (charmap_list, Mt, (void *) -1);
167 for (i = 0; i < ft_face->num_charmaps; i++)
169 char registry_buf[16];
171 sprintf (registry_buf, "%d-%d",
172 ft_face->charmaps[i]->platform_id,
173 ft_face->charmaps[i]->encoding_id);
174 mplist_add (charmap_list, msymbol (registry_buf), (void *) i);
175 if (ft_face->charmaps[i]->platform_id == 0)
177 if (ft_face->charmaps[i]->encoding_id == 3)
179 else if (ft_face->charmaps[i]->encoding_id == 4)
182 else if (ft_face->charmaps[i]->platform_id == 3)
184 if (ft_face->charmaps[i]->encoding_id == 1)
186 else if (ft_face->charmaps[i]->encoding_id == 10)
189 else if (ft_face->charmaps[i]->platform_id == 1
190 && ft_face->charmaps[i]->encoding_id == 0)
191 mplist_add (charmap_list, msymbol ("apple-roman"), (void *) i);
193 if (unicode_bmp >= 0)
194 mplist_add (charmap_list, msymbol ("unicode-bmp"), (void *) unicode_bmp);
195 if (unicode_full >= 0)
196 mplist_add (charmap_list, msymbol ("unicode-full"), (void *) unicode_full);
198 ft_info->charmap_list = charmap_list;
205 add_font_list (MPlist *font_list)
209 MPLIST_DO (plist, font_list)
211 char *filename = MPLIST_VAL (plist);
214 if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0)
216 if (ft_face->family_name && ((char *) ft_face->family_name)[0])
218 MSymbol family = MPLIST_KEY (plist);
222 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
223 ft_info->filename = filename;
224 ft_info->otf_flag = check_otf_filename (filename);
225 family = set_font_info (ft_face, ft_info, family);
226 p = mplist_get (ft_font_list, family);
230 mplist_add (ft_font_list, family, p);
232 mplist_add (p, family, ft_info);
234 FT_Done_Face (ft_face);
239 M17N_OBJECT_UNREF (font_list);
244 xft_list (MSymbol family)
258 fc_config = FcConfigGetCurrent ();
259 MPLIST_DO (plist, mfont_freetype_path)
260 if (MPLIST_STRING_P (plist)
261 && (pathname = MPLIST_STRING (plist))
262 && stat (pathname, &buf) == 0)
263 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
266 pattern = FcPatternCreate ();
267 FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) (msymbol_name (family)));
268 os = FcObjectSetBuild (FC_FILE, NULL);
269 fs = FcFontList (fc_config, pattern, os);
273 for (i = 0; i < fs->nfont; i++)
277 FcPatternGetString (fs->fonts[i], FC_FILE, 0, &filename);
278 mplist_add (plist, family, strdup ((char *) filename));
280 FcFontSetDestroy (fs);
282 FcObjectSetDestroy (os);
283 FcPatternDestroy (pattern);
287 #else /* not HAVE_XFT2 */
291 MPlist *font_list = mplist (), *plist;
295 MPLIST_DO (plist, mfont_freetype_path)
296 if (MPLIST_STRING_P (plist)
297 && (pathname = MPLIST_STRING (plist))
298 && stat (pathname, &buf) == 0)
300 if (S_ISREG (buf.st_mode))
301 mplist_add (font_list, Mt, strdup (pathname));
302 else if (S_ISDIR (buf.st_mode))
304 int len = strlen (pathname);
306 DIR *dir = opendir (pathname);
311 strcpy (path, pathname);
312 strcpy (path + len, "/");
314 while ((dp = readdir (dir)) != NULL)
316 strcpy (path + len, dp->d_name);
317 mplist_add (font_list, Mt, strdup (path));
328 static MRealizedFont *ft_select (MFrame *, MFont *, MFont *, int);
329 static int ft_open (MRealizedFont *);
330 static void ft_close (MRealizedFont *);
331 static void ft_find_metric (MRealizedFont *, MGlyphString *, int, int);
332 static unsigned ft_encode_char (MRealizedFont *, int, unsigned);
333 static void ft_render (MDrawWindow, int, int, MGlyphString *,
334 MGlyph *, MGlyph *, int, MDrawRegion);
336 MFontDriver ft_driver =
337 { ft_select, ft_open, ft_close,
338 ft_find_metric, ft_encode_char, ft_render };
340 /* The FreeType font driver function LIST. */
342 static MRealizedFont *
343 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
348 MRealizedFont *rfont;
349 MSymbol family, registry;
353 family = FONT_PROPERTY (spec, MFONT_FAMILY);
355 family = FONT_PROPERTY (request, MFONT_FAMILY);
358 registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
359 if (registry == Mnil)
364 ft_font_list = mplist ();
365 plist = mplist_get (ft_font_list, family);
368 add_font_list (xft_list (family));
369 plist = mplist_get (ft_font_list, family);
371 mplist_add (ft_font_list, family, plist = mplist ());
373 #else /* not HAVE_XFT2 */
376 ft_font_list = mplist ();
377 add_font_list (ft_list ());
379 plist = mplist_get (ft_font_list, family);
382 #endif /* not HAVE_XFT2 */
384 MPLIST_DO (plist, plist)
386 MFTInfo *ft_info = MPLIST_VAL (plist);
387 MPlist *p = mplist_find_by_key (ft_info->charmap_list, registry);
392 /* We always ignore FOUNDRY. */
393 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
394 score = mfont__score (&ft_info->font, spec, request, limited_size);
397 || best_score > score))
408 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
409 rfont->frame = frame;
411 rfont->request = *request;
412 rfont->font = best_font->font;
413 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
414 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
415 rfont->score = best_score;
416 rfont->info = best_font;
417 rfont->driver = &ft_driver;
422 close_ft (void *object)
424 MFTInfo *ft_info = (MFTInfo *) object;
426 if (ft_info->ft_face)
427 FT_Done_Face (ft_info->ft_face);
429 if (ft_info->xft_info)
430 mwin__xft_close (ft_info->xft_info);
431 #endif /* HAVE_XFT2 */
434 OTF_close (ft_info->otf);
435 #endif /* HAVE_OTF */
439 /* The FreeType font driver function OPEN. */
442 ft_open (MRealizedFont *rfont)
445 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
446 int mdebug_mask = MDEBUG_FONT;
449 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
450 ft_info->font = ((MFTInfo *) rfont->info)->font;
451 ft_info->otf_flag = ((MFTInfo *) rfont->info)->otf_flag;
452 ft_info->filename = ((MFTInfo *) rfont->info)->filename;
453 ft_info->charmap_list = ((MFTInfo *) rfont->info)->charmap_list;
454 rfont->info = ft_info;
457 ft_info->ft_face = NULL;
458 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
460 if (registry == Mnil)
462 ft_info->charmap_index
463 = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
464 if (ft_info->charmap_index >= 0
465 && FT_Set_Charmap (ft_info->ft_face,
466 ft_info->ft_face->charmaps[ft_info->charmap_index]))
468 size = rfont->font.property[MFONT_SIZE] / 10;
470 ft_info->xft_info = mwin__xft_open (rfont->frame, ft_info->filename, size);
471 if (! ft_info->xft_info)
473 #else /* not HAVE_XFT2 */
474 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
476 #endif /* not HAVE_XFT2 */
478 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
480 rfont->ascent = ft_info->ft_face->ascender >> 6;
481 rfont->descent = ft_info->ft_face->descender >> 6;
485 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
489 /* The FreeType font driver function CLOSE. */
492 ft_close (MRealizedFont *rfont)
494 M17N_OBJECT_UNREF (rfont->info);
497 /* The FreeType font driver function FIND_METRIC. */
500 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
503 MFTInfo *ft_info = (MFTInfo *) rfont->info;
504 FT_Face ft_face = ft_info->ft_face;
505 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
506 FT_Int32 load_flags = FT_LOAD_RENDER;
508 if (! gstring->anti_alias)
510 #ifdef FT_LOAD_TARGET_MONO
511 load_flags |= FT_LOAD_TARGET_MONO;
513 load_flags |= FT_LOAD_MONOCHROME;
517 for (; g != gend; g++)
519 if (g->code == MCHAR_INVALID_CODE)
521 unsigned unitsPerEm = ft_face->units_per_EM;
522 int size = rfont->font.property[MFONT_SIZE] / 10;
525 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
526 g->width = ft_face->max_advance_width * size / unitsPerEm;
527 g->ascent = ft_face->ascender * size / unitsPerEm;
528 g->descent = (- ft_face->descender) * size / unitsPerEm;
533 mwin__xft_get_metric (ft_info->xft_info, ft_info->ft_face, g);
534 #else /* not HAVE_XFT2 */
535 FT_Glyph_Metrics *metrics;
541 code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
543 FT_Load_Glyph (ft_face, code, FT_LOAD_RENDER);
544 metrics = &ft_face->glyph->metrics;
545 g->lbearing = (metrics->horiBearingX >> 6);
546 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
547 g->width = metrics->horiAdvance >> 6;
548 g->ascent = metrics->horiBearingY >> 6;
549 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
550 #endif /* not HAVE_XFT2 */
555 /* The FreeType font driver function ENCODE_CHAR. */
558 ft_encode_char (MRealizedFont *rfont, int c, unsigned ignored)
563 if (rfont->status == 0)
565 if (ft_open (rfont) < 0)
568 ft_info = (MFTInfo *) rfont->info;
569 code = FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) c);
571 return MCHAR_INVALID_CODE;
572 return ((unsigned) c);
576 /* The FreeType font driver function RENDER. */
578 #define NUM_POINTS 0x1000
581 MDrawPoint points[NUM_POINTS];
586 ft_render (MDrawWindow win, int x, int y,
587 MGlyphString *gstring, MGlyph *from, MGlyph *to,
588 int reverse, MDrawRegion region)
592 MRealizedFace *rface = from->rface;
594 MFrame *frame = rface->frame;
595 FT_Int32 load_flags = FT_LOAD_RENDER;
598 MPointTable point_table[8];
599 #endif /* not HAVE_XFT2 */
604 /* It is assured that the all glyphs in the current range use the
605 same realized face. */
606 ft_info = (MFTInfo *) rface->rfont->info;
607 ft_face = ft_info->ft_face;
610 mwin__xft_render (win, x, y, gstring, from, to, reverse, region,
611 ft_info->xft_info, ft_face);
612 #else /* not HAVE_XFT2 */
613 if (! gstring->anti_alias)
615 #ifdef FT_LOAD_TARGET_MONO
616 load_flags |= FT_LOAD_TARGET_MONO;
618 load_flags |= FT_LOAD_MONOCHROME;
622 for (i = 0; i < 8; i++)
623 point_table[i].p = point_table[i].points;
625 for (g = from; g < to; x += g++->width)
637 code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
638 FT_Load_Glyph (ft_face, code, load_flags);
639 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
640 bmp = ft_face->glyph->bitmap.buffer;
641 width = ft_face->glyph->bitmap.width;
642 if (ft_face->glyph->bitmap.pitch < ft_face->glyph->bitmap.width)
643 width = ft_face->glyph->bitmap.pitch;
645 if (gstring->anti_alias)
646 for (i = 0; i < ft_face->glyph->bitmap.rows;
647 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
649 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
650 for (j = 0; j < width; j++, xoff++)
652 intensity = bmp[j] >> 5;
655 ptable = point_table + intensity;
659 if (ptable->p - ptable->points == NUM_POINTS)
661 mwin__draw_points (frame, win, rface,
662 reverse ? 7 - intensity : intensity,
663 ptable->points, NUM_POINTS, region);
664 ptable->p = ptable->points;
670 for (i = 0; i < ft_face->glyph->bitmap.rows;
671 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
673 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
674 for (j = 0; j < width; j++, xoff++)
676 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
679 ptable = point_table;
683 if (ptable->p - ptable->points == NUM_POINTS)
685 mwin__draw_points (frame, win, rface,
687 ptable->points, NUM_POINTS, region);
688 ptable->p = ptable->points;
695 if (gstring->anti_alias)
697 for (i = 1; i < 8; i++)
698 if (point_table[i].p != point_table[i].points)
699 mwin__draw_points (frame, win, rface, reverse ? 7 - i : i,
700 point_table[i].points,
701 point_table[i].p - point_table[i].points, region);
705 if (point_table[0].p != point_table[0].points)
706 mwin__draw_points (frame, win, rface, reverse ? 0 : 7,
707 point_table[0].points,
708 point_table[0].p - point_table[0].points, region);
710 #endif /* not HAVE_XFT2 */
720 char *weight, *style, *stretch;
721 } ft_to_prop_name[] =
722 { { "regular", "medium", "r", "normal" },
723 { "italic", "medium", "i", "normal" },
724 { "bold", "bold", "r", "normal" },
725 { "bold italic", "bold", "i", "normal" },
726 { "narrow", "medium", "r", "condensed" },
727 { "narrow italic", "medium", "i", "condensed" },
728 { "narrow bold", "bold", "r", "condensed" },
729 { "narrow bold italic", "bold", "i", "condensed" },
730 { "black", "black", "r", "normal" },
731 { "black italic", "black", "i", "normal" },
732 { "oblique", "medium", "o", "normal" },
733 { "boldoblique", "bold", "o", "normal" } };
736 if (FT_Init_FreeType (&ft_library) != 0)
737 MERROR (MERROR_FONT_FT, -1);
739 ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
740 MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
741 for (i = 0; i < ft_to_prop_size; i++)
743 ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
744 ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
745 ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
746 ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
749 mfont__driver_list[MFONT_TYPE_FT] = &ft_driver;
761 MPLIST_DO (plist, ft_font_list)
763 MPLIST_DO (p, MPLIST_VAL (plist))
765 MFTInfo *ft_info = (MFTInfo *) MPLIST_VAL (p);
766 free (ft_info->filename);
767 M17N_OBJECT_UNREF (ft_info->charmap_list);
770 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
772 M17N_OBJECT_UNREF (ft_font_list);
776 FT_Done_FreeType (ft_library);
781 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
782 MRealizedFont *rfont,
783 MSymbol script, MSymbol langsys,
784 MSymbol gsub_features, MSymbol gpos_features)
792 OTF_GlyphString otf_gstring;
794 char *script_name, *language_name;
795 char *gsub_feature_names, *gpos_feature_names;
796 int from_pos, to_pos;
802 ft_info = (MFTInfo *) rfont->info;
803 if (ft_info->otf_flag < 0)
806 if (! otf && (otf = OTF_open (ft_info->filename)))
808 if (OTF_get_table (otf, "head") < 0
809 || (OTF_check_table (otf, "GSUB") < 0
810 && OTF_check_table (otf, "GPOS") < 0))
813 ft_info->otf_flag = -1;
820 script_name = msymbol_name (script);
821 language_name = langsys != Mnil ? msymbol_name (langsys) : NULL;
823 = (gsub_features == Mt ? "*"
824 : gsub_features == Mnil ? NULL
825 : msymbol_name (gsub_features));
827 = (gpos_features == Mt ? "*"
828 : gpos_features == Mnil ? NULL
829 : msymbol_name (gpos_features));
831 g = gstring->glyphs[from];
834 for (i = from + 1; i < to; i++)
836 if (from_pos > gstring->glyphs[i].pos)
837 from_pos = gstring->glyphs[i].pos;
838 if (to_pos < gstring->glyphs[i].to)
839 to_pos = gstring->glyphs[i].to;
842 unitsPerEm = otf->head->unitsPerEm;
843 otf_gstring.size = otf_gstring.used = len;
844 otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
845 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
846 for (i = 0; i < len; i++)
848 if (gstring->glyphs[from + i].otf_encoded)
850 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
851 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
855 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
859 if (OTF_drive_tables (otf, &otf_gstring, script_name, language_name,
860 gsub_feature_names, gpos_feature_names) < 0)
864 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
866 g.combining_code = 0;
870 g.code = otfg->glyph_id;
871 switch (otfg->positioning_type)
875 int off_x = 128, off_y = 128;
877 if (otfg->f.f1.format & OTF_XPlacement)
878 off_x = ((double) (otfg->f.f1.value->XPlacement)
879 * 100 / unitsPerEm + 128);
880 if (otfg->f.f1.format & OTF_YPlacement)
881 off_y = ((double) (otfg->f.f1.value->YPlacement)
882 * 100 / unitsPerEm + 128);
884 = MAKE_COMBINING_CODE (3, 2, 3, 0, off_y, off_x);
885 if ((otfg->f.f1.format & OTF_XAdvance)
886 || (otfg->f.f1.format & OTF_YAdvance))
891 /* Not yet supported. */
897 off_x = ((double) (otfg->f.f4.base_anchor->XCoordinate
898 - otfg->f.f4.mark_anchor->XCoordinate)
899 * 100 / unitsPerEm + 128);
900 off_y = ((double) (otfg->f.f4.base_anchor->YCoordinate
901 - otfg->f.f4.mark_anchor->YCoordinate)
902 * 100 / unitsPerEm + 128);
904 = MAKE_COMBINING_CODE (3, 0, 3, 0, off_y, off_x);
908 /* Not yet supported. */
910 default: /* i.e case 6 */
911 /* Not yet supported. */
921 MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
926 #endif /* HAVE_OTF */
927 for (i = 0; i < len; i++)
929 g = gstring->glyphs[from + i];
930 MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
936 mfont__ft_decode_otf (MGlyph *g)
939 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
940 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
943 #else /* not HAVE_OTF */
945 #endif /* not HAVE_OTF */
948 #else /* not HAVE_FREETYPE */
961 #endif /* HAVE_FREETYPE */