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"
39 #include "internal-gui.h"
45 #include <freetype/ftbdf.h>
47 #ifdef HAVE_FONTCONFIG
48 #include <fontconfig/fontconfig.h>
50 int fontconfig_initialized = 0;
52 #endif /* not HAVE_FONTCONFIG */
54 static MSymbol Municode_bmp, Municode_full, Miso10646_1, Miso8859_1;
56 static FT_Library ft_library;
62 enum MFontProperty prop;
66 static MFTtoProp ft_to_prop[] =
67 { { "italic", 0, MFONT_STYLE, "i" },
68 { "roman", 0, MFONT_STYLE, "r" },
69 { "oblique", 0, MFONT_STYLE, "p" },
70 { "regular", 0, MFONT_WEIGHT, "medium" },
71 { "normal", 0, MFONT_WEIGHT, "medium" },
72 /* We need this entry even if "bold" is in commone_weight[] to
73 handle such style names as "bolditalic" and "boldoblique". */
74 { "bold", 0, MFONT_WEIGHT, "bold" },
75 { "demi bold", 0, MFONT_WEIGHT, "demibold" },
76 { "demi", 0, MFONT_WEIGHT, "demibold" } };
77 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
79 /** List of FreeType fonts. Keys are family names, values are plists
80 contains fonts of the corresponding family. In the deeper plist,
81 keys are Mt, values are (MFTInfo *). */
82 static MPlist *ft_font_list;
84 static int all_fonts_scaned;
86 /** Return 0 if NAME implies TrueType or OpenType fonts. Othersize
90 check_otf_filename (const char *name)
92 int len = strlen (name);
93 const char *ext = name + (len - 4);
96 || (memcmp (ext, ".ttf", 4)
97 && memcmp (ext, ".TTF", 4)
98 && memcmp (ext, ".otf", 4)
99 && memcmp (ext, ".OTF", 4)))
104 /** Setup members of FT_INFO from FT_FACE. Return the family name. */
107 set_font_info (FT_Face ft_face, MFTInfo *ft_info, MSymbol family)
109 MFont *font = &ft_info->font;
112 MPlist *charmap_list;
113 int unicode_bmp = -1, unicode_full = -1, unicode = -1;
120 len = strlen (ft_face->family_name) + 1;
121 buf = (char *) alloca (len);
122 memcpy (buf, ft_face->family_name, len);
123 for (p = buf; *p; p++)
124 if (*p >= 'A' && *p <= 'Z')
126 family = msymbol (buf);
128 mfont__set_property (font, MFONT_FAMILY, family);
129 mfont__set_property (font, MFONT_WEIGHT, msymbol ("medium"));
130 mfont__set_property (font, MFONT_STYLE, msymbol ("r"));
131 mfont__set_property (font, MFONT_STRETCH, msymbol ("normal"));
132 mfont__set_property (font, MFONT_ADSTYLE, msymbol (""));
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')
143 while (*p && (*p < 'a' || *p > 'z')) p++;
146 for (i = 0; i < ft_to_prop_size; i++)
147 if (! strncmp (ft_to_prop[i].ft_style, p, ft_to_prop[i].len))
149 mfont__set_property (font, ft_to_prop[i].prop,
150 msymbol (ft_to_prop[i].val));
151 p += ft_to_prop[i].len;
154 if (i == ft_to_prop_size)
159 while (*p1 >= 'a' && *p1 <= 'z') p1++;
160 sym = msymbol__with_len (p, p1 - p);
161 for (i = MFONT_WEIGHT; i <= MFONT_STYLE; i++)
162 if (msymbol_get (sym, mfont__property_table[i].property))
164 mfont__set_property (font, i, sym);
169 while (*p && (*p < 'a' || *p > 'z')) p++;
173 charmap_list = mplist ();
174 mplist_add (charmap_list, Mt, (void *) -1);
175 for (i = 0; i < ft_face->num_charmaps; i++)
177 char registry_buf[16];
180 sprintf (registry_buf, "%d-%d",
181 ft_face->charmaps[i]->platform_id,
182 ft_face->charmaps[i]->encoding_id);
183 registry = msymbol (registry_buf);
184 mplist_add (charmap_list, registry, (void *) i);
186 if (ft_face->charmaps[i]->platform_id == 0)
188 if (ft_face->charmaps[i]->encoding_id == 3)
190 else if (ft_face->charmaps[i]->encoding_id == 4)
193 else if (ft_face->charmaps[i]->platform_id == 3)
195 if (ft_face->charmaps[i]->encoding_id == 1)
197 else if (ft_face->charmaps[i]->encoding_id == 10)
200 else if (ft_face->charmaps[i]->platform_id == 1
201 && ft_face->charmaps[i]->encoding_id == 0)
202 mplist_add (charmap_list, msymbol ("apple-roman"), (void *) i);
204 if (unicode_full >= 0)
206 mplist_add (charmap_list, Municode_full, (void *) unicode_full);
207 mplist_add (charmap_list, Municode_bmp, (void *) unicode_full);
208 mplist_add (charmap_list, Miso10646_1, (void *) unicode_full);
209 unicode = unicode_full;
211 else if (unicode_bmp >= 0)
213 mplist_add (charmap_list, Municode_bmp, (void *) unicode_bmp);
214 mplist_add (charmap_list, Miso10646_1, (void *) unicode_bmp);
215 unicode = unicode_bmp;
219 FT_Set_Charmap (ft_face, ft_face->charmaps[unicode]);
220 for (i = 255; i >= 32; i--)
224 if (FT_Get_Char_Index (ft_face, (FT_ULong) i) == 0)
228 mplist_add (charmap_list, Miso8859_1, (void *) unicode);
231 ft_info->charmap_list = charmap_list;
233 if (! FT_IS_SCALABLE (ft_face))
235 BDF_PropertyRec prop;
237 FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop);
238 font->property[MFONT_SIZE] = prop.u.integer * 10;
239 FT_Get_BDF_Property (ft_face, "RESOLUTION_Y", &prop);
240 font->property[MFONT_RESY] = prop.u.integer;
248 close_ft (void *object)
250 MFTInfo *ft_info = object;
252 if (ft_info->ft_face)
254 if (ft_info->extra_info)
255 M17N_OBJECT_UNREF (ft_info->extra_info);
256 FT_Done_Face (ft_info->ft_face);
259 OTF_close (ft_info->otf);
260 #endif /* HAVE_OTF */
262 free (ft_info->filename);
263 if (ft_info->languages)
264 free (ft_info->languages);
265 M17N_OBJECT_UNREF (ft_info->charmap_list);
270 add_font_info (char *filename, MSymbol family, char *languages)
273 BDF_PropertyRec prop;
274 MFTInfo *ft_info = NULL;
276 if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0)
278 if (FT_IS_SCALABLE (ft_face)
279 || FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0)
284 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
285 ft_info->filename = strdup (filename);
287 ft_info->languages = strdup (languages);
288 ft_info->otf_flag = check_otf_filename (filename);
289 fam = set_font_info (ft_face, ft_info, family);
290 plist = mplist_get (ft_font_list, fam);
294 mplist_add (ft_font_list, fam, plist);
296 mplist_add (plist, fam, ft_info);
298 FT_Done_Face (ft_face);
302 #ifdef HAVE_FONTCONFIG
304 static MPlist *fc_generic_family_list;
307 fc_list (MSymbol family)
321 fc_config = FcConfigGetCurrent ();
322 MPLIST_DO (plist, mfont_freetype_path)
323 if (MPLIST_STRING_P (plist)
324 && (pathname = MPLIST_STRING (plist))
325 && stat (pathname, &buf) == 0)
326 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
327 /* TODO: avoid duplicate addition by checking the current font
328 directory list given by FcConfigGetFontDirs (). */
331 pattern = FcPatternCreate ();
333 FcPatternAddString (pattern, FC_FAMILY,
334 (FcChar8 *) (msymbol_name (family)));
335 os = FcObjectSetBuild (FC_FILE, FC_FAMILY, FC_LANG, NULL);
336 fs = FcFontList (fc_config, pattern, os);
339 && mplist_get (fc_generic_family_list, family)
340 && FcConfigSubstitute (fc_config, pattern, FcMatchPattern) == FcTrue)
342 FcFontSetDestroy (fs);
343 fs = FcFontList (fc_config, pattern, os);
345 for (i = 0; i < fs->nfont; i++)
347 char *filename, *languages;
349 FcPatternGetString (fs->fonts[i], FC_FILE, 0, (FcChar8 **) &filename);
350 FcPatternGetString (fs->fonts[i], FC_LANG, 0, (FcChar8 **) &languages);
356 FcPatternGetString (fs->fonts[i], FC_FAMILY, 0, (FcChar8 **) &fname);
357 fam = msymbol (fname);
358 if (! mplist_get (ft_font_list, fam))
359 add_font_info (filename, fam, languages);
362 add_font_info (filename, family, languages);
364 FcFontSetDestroy (fs);
365 FcObjectSetDestroy (os);
366 FcPatternDestroy (pattern);
369 #else /* not HAVE_FONTCONFIG */
378 MPLIST_DO (plist, mfont_freetype_path)
379 if (MPLIST_STRING_P (plist)
380 && (pathname = MPLIST_STRING (plist))
381 && stat (pathname, &buf) == 0)
383 if (S_ISREG (buf.st_mode))
384 add_font_info (pathname, Mnil, NULL);
385 else if (S_ISDIR (buf.st_mode))
387 int len = strlen (pathname);
389 DIR *dir = opendir (pathname);
394 strcpy (path, pathname);
395 strcpy (path + len, "/");
397 while ((dp = readdir (dir)) != NULL)
399 strcpy (path + len, dp->d_name);
400 add_font_info (path, Mnil, NULL);
408 #endif /* not HAVE_FONTCONFIG */
410 /* The FreeType font driver function SELECT. */
412 static MRealizedFont *
413 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
418 MRealizedFont *rfont;
419 MSymbol family, registry;
423 family = FONT_PROPERTY (spec, MFONT_FAMILY);
425 family = FONT_PROPERTY (request, MFONT_FAMILY);
426 registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
427 if (registry == Mnil)
431 ft_font_list = mplist ();
432 #ifdef HAVE_FONTCONFIG
435 plist = mplist_get (ft_font_list, family);
439 plist = mplist_get (ft_font_list, family);
442 mplist_add (ft_font_list, family, plist = mplist ());
449 if (! all_fonts_scaned)
452 all_fonts_scaned = 1;
455 #else /* not HAVE_FONTCONFIG */
456 if (! all_fonts_scaned)
459 all_fonts_scaned = 1;
463 plist = mplist_get (ft_font_list, family);
467 #endif /* not HAVE_FONTCONFIG */
470 plist = MPLIST_VAL (ft_font_list);
473 MPLIST_DO (pl, plist)
475 MFTInfo *ft_info = MPLIST_VAL (pl);
478 if (! mplist_find_by_key (ft_info->charmap_list, registry))
480 /* We always ignore FOUNDRY. */
481 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
482 score = mfont__score (&ft_info->font, spec, request, limited_size);
485 || best_score > score))
495 plist = MPLIST_NEXT (plist);
496 if (! MPLIST_TAIL_P (plist))
502 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
503 rfont->frame = frame;
505 rfont->request = *request;
506 rfont->font = best_font->font;
507 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
508 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
509 rfont->score = best_score;
510 rfont->info = best_font;
511 M17N_OBJECT_REF (best_font);
516 /* The FreeType font driver function OPEN. */
519 ft_open (MRealizedFont *rfont)
521 MFTInfo *base = rfont->info, *ft_info;
522 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
523 int mdebug_mask = MDEBUG_FONT;
526 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
527 ft_info->font = base->font;
528 ft_info->filename = strdup (base->filename);
529 ft_info->otf_flag = base->otf_flag;
530 ft_info->charmap_list = base->charmap_list;
531 M17N_OBJECT_REF (ft_info->charmap_list);
532 M17N_OBJECT_UNREF (base);
533 rfont->info = ft_info;
536 ft_info->ft_face = NULL;
537 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
539 if (registry == Mnil)
541 ft_info->charmap_index
542 = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
543 if (ft_info->charmap_index >= 0
544 && FT_Set_Charmap (ft_info->ft_face,
545 ft_info->ft_face->charmaps[ft_info->charmap_index]))
547 size = rfont->font.property[MFONT_SIZE] / 10;
548 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
551 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
553 rfont->ascent = ft_info->ft_face->ascender >> 6;
554 rfont->descent = - (ft_info->ft_face->descender >> 6);
555 rfont->type = Mfreetype;
556 rfont->fontp = ft_info->ft_face;
560 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
561 if (ft_info->ft_face)
562 FT_Done_Face (ft_info->ft_face);
563 M17N_OBJECT_UNREF (ft_info->charmap_list);
564 free (ft_info->filename);
570 /* The FreeType font driver function FIND_METRIC. */
573 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
576 MFTInfo *ft_info = (MFTInfo *) rfont->info;
577 FT_Face ft_face = ft_info->ft_face;
578 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
580 for (; g != gend; g++)
582 if (g->code == MCHAR_INVALID_CODE)
584 if (FT_IS_SCALABLE (ft_face))
586 unsigned unitsPerEm = ft_face->units_per_EM;
587 int size = rfont->font.property[MFONT_SIZE] / 10;
590 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
591 g->width = ft_face->max_advance_width * size / unitsPerEm;
592 g->ascent = ft_face->ascender * size / unitsPerEm;
593 g->descent = (- ft_face->descender) * size / unitsPerEm;
597 BDF_PropertyRec prop;
600 g->rbearing = g->width = ft_face->available_sizes->width;
601 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
603 g->ascent = prop.u.integer;
604 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
605 g->descent = prop.u.integer;
609 g->ascent = ft_face->available_sizes->height;
616 FT_Glyph_Metrics *metrics;
618 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
619 metrics = &ft_face->glyph->metrics;
620 g->lbearing = (metrics->horiBearingX >> 6);
621 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
622 g->width = metrics->horiAdvance >> 6;
623 g->ascent = metrics->horiBearingY >> 6;
624 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
629 /* The FreeType font driver function ENCODE_CHAR. */
632 ft_encode_char (MRealizedFont *rfont, unsigned code)
636 if (rfont->status == 0)
638 if ((rfont->driver->open) (rfont) < 0)
641 ft_info = (MFTInfo *) rfont->info;
642 code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
644 return MCHAR_INVALID_CODE;
649 /* The FreeType font driver function RENDER. */
651 #define NUM_POINTS 0x1000
654 MDrawPoint points[NUM_POINTS];
659 ft_render (MDrawWindow win, int x, int y,
660 MGlyphString *gstring, MGlyph *from, MGlyph *to,
661 int reverse, MDrawRegion region)
665 MRealizedFace *rface = from->rface;
666 MFrame *frame = rface->frame;
667 FT_Int32 load_flags = FT_LOAD_RENDER;
670 MPointTable point_table[8];
675 /* It is assured that the all glyphs in the current range use the
676 same realized face. */
677 ft_info = (MFTInfo *) rface->rfont->info;
678 ft_face = ft_info->ft_face;
680 if (! gstring->anti_alias)
682 #ifdef FT_LOAD_TARGET_MONO
683 load_flags |= FT_LOAD_TARGET_MONO;
685 load_flags |= FT_LOAD_MONOCHROME;
689 for (i = 0; i < 8; i++)
690 point_table[i].p = point_table[i].points;
692 for (g = from; g < to; x += g++->width)
700 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
701 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
702 bmp = ft_face->glyph->bitmap.buffer;
703 width = ft_face->glyph->bitmap.width;
704 pitch = ft_face->glyph->bitmap.pitch;
705 if (! gstring->anti_alias)
710 if (gstring->anti_alias)
711 for (i = 0; i < ft_face->glyph->bitmap.rows;
712 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
714 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
715 for (j = 0; j < width; j++, xoff++)
717 intensity = bmp[j] >> 5;
720 ptable = point_table + intensity;
724 if (ptable->p - ptable->points == NUM_POINTS)
726 (*frame->driver->draw_points)
728 reverse ? 7 - intensity : intensity,
729 ptable->points, NUM_POINTS, region);
730 ptable->p = ptable->points;
736 for (i = 0; i < ft_face->glyph->bitmap.rows;
737 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
739 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
740 for (j = 0; j < width; j++, xoff++)
742 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
745 ptable = point_table;
749 if (ptable->p - ptable->points == NUM_POINTS)
751 (*frame->driver->draw_points) (frame, win, rface,
753 ptable->points, NUM_POINTS, region);
754 ptable->p = ptable->points;
761 if (gstring->anti_alias)
763 for (i = 1; i < 8; i++)
764 if (point_table[i].p != point_table[i].points)
765 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
766 point_table[i].points,
767 point_table[i].p - point_table[i].points, region);
771 if (point_table[0].p != point_table[0].points)
772 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
773 point_table[0].points,
774 point_table[0].p - point_table[0].points, region);
779 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language)
782 MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
783 char *lang = language != Mnil ? MSYMBOL_NAME (language) : NULL;
785 if (! all_fonts_scaned)
787 #ifdef HAVE_FONTCONFIG
792 all_fonts_scaned = 1;
799 pl = mplist_find_by_key (ft_font_list, family);
806 MPLIST_DO (p, MPLIST_VAL (pl))
808 MFTInfo *ft_info = MPLIST_VAL (p);
810 if (lang && ft_info->languages && strstr (ft_info->languages, lang))
812 if (font && ! mfont__match_p (&ft_info->font, font, MFONT_REGISTRY))
814 mplist_push (plist, FONT_PROPERTY (&ft_info->font, MFONT_FAMILY),
825 MFontDriver mfont__ft_driver =
826 { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
833 if (FT_Init_FreeType (&ft_library) != 0)
834 MERROR (MERROR_FONT_FT, -1);
836 for (i = 0; i < ft_to_prop_size; i++)
837 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
839 Municode_bmp = msymbol ("unicode-bmp");
840 Municode_full = msymbol ("unicode-full");
841 Miso10646_1 = msymbol ("iso10646-1");
842 Miso8859_1 = msymbol ("iso8859-1");
844 #ifdef HAVE_FONTCONFIG
845 fc_generic_family_list = mplist ();
846 mplist_push (fc_generic_family_list, msymbol ("serif"), Mt);
847 mplist_push (fc_generic_family_list, msymbol ("sans-serif"), Mt);
848 mplist_push (fc_generic_family_list, msymbol ("monospace"), Mt);
849 mplist_push (fc_generic_family_list, msymbol ("sans"), Mt);
850 mplist_push (fc_generic_family_list, msymbol ("sans serif"), Mt);
851 mplist_push (fc_generic_family_list, msymbol ("mono"), Mt);
864 MPLIST_DO (plist, ft_font_list)
866 MPLIST_DO (p, MPLIST_VAL (plist))
868 MFTInfo *ft_info = MPLIST_VAL (p);
870 M17N_OBJECT_UNREF (ft_info);
872 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
874 M17N_OBJECT_UNREF (ft_font_list);
877 FT_Done_FreeType (ft_library);
878 all_fonts_scaned = 0;
880 #ifdef HAVE_FONTCONFIG
881 m17n_object_unref (fc_generic_family_list);
887 #ifdef HAVE_FONTCONFIG
892 } FC_vs_M17N_font_prop;
894 static FC_vs_M17N_font_prop fc_weight_table[] =
895 { { FC_WEIGHT_ULTRALIGHT, "extralight" },
896 { FC_WEIGHT_LIGHT, "light" },
897 { FC_WEIGHT_NORMAL, "normal" },
898 { FC_WEIGHT_MEDIUM, "medium" },
899 { FC_WEIGHT_DEMIBOLD, "demibold" },
900 { FC_WEIGHT_EXTRABOLD, "extrabold" },
901 { FC_WEIGHT_BLACK, "black" },
902 { FC_WEIGHT_MEDIUM, NULL } };
904 static FC_vs_M17N_font_prop fc_slant_table[] =
905 { { FC_SLANT_ROMAN, "r" },
906 { FC_SLANT_ITALIC, "i" },
907 { FC_SLANT_OBLIQUE, "o" },
908 { FC_SLANT_ROMAN, NULL } };
910 static FC_vs_M17N_font_prop fc_width_table[] =
911 { { FC_WIDTH_CONDENSED, "condensed" },
912 { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
913 { FC_WIDTH_NORMAL, "normal" },
914 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
915 { FC_WIDTH_EXPANDED, "expanded" },
916 { FC_WIDTH_NORMAL, NULL } };
920 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
924 for (i = 0; table[i].m17n_value; i++)
925 if (val <= table[i].fc_value)
926 msymbol ("table[i].m17n_value");
927 return msymbol ("table[i - 1].m17n_value");
931 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
935 for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
936 return table[i].fc_value;
940 mfont__ft_parse_name (char *name, MFont *font)
942 FcPattern *pat = FcNameParse ((FcChar8 *) name);
949 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
950 mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
951 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
952 mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
953 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
954 mfont__set_property (font, MFONT_WEIGHT,
955 fc_decode_prop (val, fc_weight_table));
956 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
957 mfont__set_property (font, MFONT_STYLE,
958 fc_decode_prop (val, fc_slant_table));
959 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
960 mfont__set_property (font, MFONT_STRETCH,
961 fc_decode_prop (val, fc_width_table));
962 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
963 font->property[MFONT_SIZE] = size * 10;
964 FcPatternDestroy (pat);
969 mfont__ft_unparse_name (MFont *font)
971 FcPattern *pat = FcPatternCreate ();
972 MSymbol sym, weight, style, stretch;
975 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
976 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
977 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
978 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
979 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
980 FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
982 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
983 FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
985 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
986 FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
988 name = (char *) FcNameUnparse (pat);
989 FcPatternDestroy (pat);
992 #endif /* HAVE_FONTCONFIG */
997 #define DEVICE_DELTA(table, size) \
998 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
999 ? (table).DeltaValue[(size) >= (table).StartSize] \
1003 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1004 unsigned code, int size, int *x, int *y)
1006 if (anchor->AnchorFormat == 2)
1008 FT_Outline *outline;
1009 int ap = anchor->f.f1.AnchorPoint;
1011 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1012 outline = &ft_face->glyph->outline;
1013 if (ap < outline->n_points)
1015 *x = outline->points[ap].x;
1016 *y = outline->points[ap].y;
1019 else if (anchor->AnchorFormat == 3)
1021 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1022 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1027 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1028 MSymbol script, MSymbol langsys,
1029 MSymbol gsub_features, MSymbol gpos_features)
1031 int len = to - from;
1032 MGlyph *g = MGLYPH (from);
1034 MRealizedFont *rfont;
1037 OTF_GlyphString otf_gstring;
1039 char *script_name, *language_name;
1040 char *gsub_feature_names, *gpos_feature_names;
1046 rfont = g->rface->rfont;
1047 ft_info = rfont->info;
1048 if (ft_info->otf_flag < 0)
1053 otf = OTF_open (ft_info->filename);
1054 if (otf && OTF_get_table (otf, "head") < 0)
1061 ft_info->otf_flag = -1;
1068 script_name = msymbol_name (script);
1071 if (langsys != Mnil)
1072 language_name = msymbol_name (langsys);
1074 language_name = NULL;
1076 = (gsub_features == Mt ? "*"
1077 : gsub_features == Mnil ? NULL
1078 : msymbol_name (gsub_features));
1079 if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1080 gsub_feature_names = NULL;
1082 = (gpos_features == Mt ? "*"
1083 : gpos_features == Mnil ? NULL
1084 : msymbol_name (gpos_features));
1085 if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1086 gpos_feature_names = NULL;
1088 otf_gstring.size = otf_gstring.used = len;
1089 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1090 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1091 for (i = 0, need_cmap = 0; i < len; i++)
1093 if (gstring->glyphs[from + i].otf_encoded)
1095 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1096 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1100 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1105 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1108 OTF_drive_gdef (otf, &otf_gstring);
1109 gidx = gstring->used;
1111 if (gsub_feature_names)
1113 if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1114 gsub_feature_names) < 0)
1116 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1118 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1121 temp.combining_code = 0;
1124 temp.code = otfg->glyph_id;
1125 temp.otf_encoded = 1;
1130 temp.otf_encoded = 0;
1132 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1133 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1137 for (i = 0; i < len; i++)
1139 MGlyph temp = gstring->glyphs[from + i];
1141 if (otf_gstring.glyphs[i].glyph_id)
1143 temp.code = otf_gstring.glyphs[i].glyph_id;
1144 temp.otf_encoded = 1;
1146 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1149 ft_find_metric (rfont, gstring, gidx, gstring->used);
1151 if (gpos_feature_names)
1155 MGlyph *base = NULL, *mark = NULL;
1157 if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1158 gpos_feature_names) < 0)
1161 u = otf->head->unitsPerEm;
1162 size10 = rfont->font.property[MFONT_SIZE];
1165 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1166 i < otf_gstring.used; i++, otfg++, g++)
1170 if (! otfg->glyph_id)
1172 switch (otfg->positioning_type)
1178 int format = otfg->f.f1.format;
1180 if (format & OTF_XPlacement)
1181 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1182 if (format & OTF_XPlaDevice)
1183 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1184 if (format & OTF_YPlacement)
1185 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1186 if (format & OTF_YPlaDevice)
1187 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1188 if (format & OTF_XAdvance)
1189 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1190 if (format & OTF_XAdvDevice)
1191 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1195 /* Not yet supported. */
1201 goto label_adjust_anchor;
1202 default: /* i.e. case 6 */
1207 label_adjust_anchor:
1209 int base_x, base_y, mark_x, mark_y;
1211 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1212 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1213 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1214 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1216 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1217 adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1218 prev->code, size, &base_x, &base_y);
1219 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1220 adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1221 g->code, size, &mark_x, &mark_y);
1222 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1223 g->yoff = prev->yoff + mark_y - base_y;
1224 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1227 if (otfg->GlyphClass == OTF_GlyphClass0)
1229 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1235 free (otf_gstring.glyphs);
1239 ft_find_metric (rfont, gstring, from, to);
1240 for (i = 0; i < len; i++)
1242 MGlyph temp = gstring->glyphs[from + i];
1243 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1245 free (otf_gstring.glyphs);
1251 mfont__ft_decode_otf (MGlyph *g)
1253 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1254 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1256 return (c ? c : -1);
1259 #endif /* HAVE_OTF */
1261 #endif /* HAVE_FREETYPE */