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),
826 MFontDriver mfont__ft_driver =
827 { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
834 if (FT_Init_FreeType (&ft_library) != 0)
835 MERROR (MERROR_FONT_FT, -1);
837 for (i = 0; i < ft_to_prop_size; i++)
838 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
840 Municode_bmp = msymbol ("unicode-bmp");
841 Municode_full = msymbol ("unicode-full");
842 Miso10646_1 = msymbol ("iso10646-1");
843 Miso8859_1 = msymbol ("iso8859-1");
845 #ifdef HAVE_FONTCONFIG
846 fc_generic_family_list = mplist ();
847 mplist_push (fc_generic_family_list, msymbol ("serif"), Mt);
848 mplist_push (fc_generic_family_list, msymbol ("sans-serif"), Mt);
849 mplist_push (fc_generic_family_list, msymbol ("monospace"), Mt);
850 mplist_push (fc_generic_family_list, msymbol ("sans"), Mt);
851 mplist_push (fc_generic_family_list, msymbol ("sans serif"), Mt);
852 mplist_push (fc_generic_family_list, msymbol ("mono"), Mt);
865 MPLIST_DO (plist, ft_font_list)
867 MPLIST_DO (p, MPLIST_VAL (plist))
869 MFTInfo *ft_info = MPLIST_VAL (p);
871 M17N_OBJECT_UNREF (ft_info);
873 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
875 M17N_OBJECT_UNREF (ft_font_list);
878 FT_Done_FreeType (ft_library);
879 all_fonts_scaned = 0;
881 #ifdef HAVE_FONTCONFIG
882 m17n_object_unref (fc_generic_family_list);
888 #ifdef HAVE_FONTCONFIG
893 } FC_vs_M17N_font_prop;
895 static FC_vs_M17N_font_prop fc_weight_table[] =
896 { { FC_WEIGHT_ULTRALIGHT, "extralight" },
897 { FC_WEIGHT_LIGHT, "light" },
898 { FC_WEIGHT_NORMAL, "normal" },
899 { FC_WEIGHT_MEDIUM, "medium" },
900 { FC_WEIGHT_DEMIBOLD, "demibold" },
901 { FC_WEIGHT_EXTRABOLD, "extrabold" },
902 { FC_WEIGHT_BLACK, "black" },
903 { FC_WEIGHT_MEDIUM, NULL } };
905 static FC_vs_M17N_font_prop fc_slant_table[] =
906 { { FC_SLANT_ROMAN, "r" },
907 { FC_SLANT_ITALIC, "i" },
908 { FC_SLANT_OBLIQUE, "o" },
909 { FC_SLANT_ROMAN, NULL } };
911 static FC_vs_M17N_font_prop fc_width_table[] =
912 { { FC_WIDTH_CONDENSED, "condensed" },
913 { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
914 { FC_WIDTH_NORMAL, "normal" },
915 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
916 { FC_WIDTH_EXPANDED, "expanded" },
917 { FC_WIDTH_NORMAL, NULL } };
921 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
925 for (i = 0; table[i].m17n_value; i++)
926 if (val <= table[i].fc_value)
927 msymbol ("table[i].m17n_value");
928 return msymbol ("table[i - 1].m17n_value");
932 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
936 for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
937 return table[i].fc_value;
941 mfont__ft_parse_name (char *name, MFont *font)
943 FcPattern *pat = FcNameParse ((FcChar8 *) name);
950 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
951 mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
952 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
953 mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
954 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
955 mfont__set_property (font, MFONT_WEIGHT,
956 fc_decode_prop (val, fc_weight_table));
957 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
958 mfont__set_property (font, MFONT_STYLE,
959 fc_decode_prop (val, fc_slant_table));
960 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
961 mfont__set_property (font, MFONT_STRETCH,
962 fc_decode_prop (val, fc_width_table));
963 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
964 font->property[MFONT_SIZE] = size * 10;
965 FcPatternDestroy (pat);
970 mfont__ft_unparse_name (MFont *font)
972 FcPattern *pat = FcPatternCreate ();
973 MSymbol sym, weight, style, stretch;
976 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
977 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
978 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
979 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
980 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
981 FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
983 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
984 FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
986 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
987 FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
989 name = (char *) FcNameUnparse (pat);
990 FcPatternDestroy (pat);
993 #endif /* HAVE_FONTCONFIG */
998 #define DEVICE_DELTA(table, size) \
999 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1000 ? (table).DeltaValue[(size) >= (table).StartSize] \
1004 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1005 unsigned code, int size, int *x, int *y)
1007 if (anchor->AnchorFormat == 2)
1009 FT_Outline *outline;
1010 int ap = anchor->f.f1.AnchorPoint;
1012 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1013 outline = &ft_face->glyph->outline;
1014 if (ap < outline->n_points)
1016 *x = outline->points[ap].x;
1017 *y = outline->points[ap].y;
1020 else if (anchor->AnchorFormat == 3)
1022 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1023 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1028 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1029 MSymbol script, MSymbol langsys,
1030 MSymbol gsub_features, MSymbol gpos_features)
1032 int len = to - from;
1033 MGlyph *g = MGLYPH (from);
1035 MRealizedFont *rfont;
1038 OTF_GlyphString otf_gstring;
1040 char *script_name, *language_name;
1041 char *gsub_feature_names, *gpos_feature_names;
1047 rfont = g->rface->rfont;
1048 ft_info = rfont->info;
1049 if (ft_info->otf_flag < 0)
1054 otf = OTF_open (ft_info->filename);
1055 if (otf && OTF_get_table (otf, "head") < 0)
1062 ft_info->otf_flag = -1;
1069 script_name = msymbol_name (script);
1072 if (langsys != Mnil)
1073 language_name = msymbol_name (langsys);
1075 language_name = NULL;
1077 = (gsub_features == Mt ? "*"
1078 : gsub_features == Mnil ? NULL
1079 : msymbol_name (gsub_features));
1080 if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1081 gsub_feature_names = NULL;
1083 = (gpos_features == Mt ? "*"
1084 : gpos_features == Mnil ? NULL
1085 : msymbol_name (gpos_features));
1086 if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1087 gpos_feature_names = NULL;
1089 otf_gstring.size = otf_gstring.used = len;
1090 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1091 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1092 for (i = 0, need_cmap = 0; i < len; i++)
1094 if (gstring->glyphs[from + i].otf_encoded)
1096 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1097 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1101 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1106 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1109 OTF_drive_gdef (otf, &otf_gstring);
1110 gidx = gstring->used;
1112 if (gsub_feature_names)
1114 if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1115 gsub_feature_names) < 0)
1117 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1119 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1122 temp.combining_code = 0;
1125 temp.code = otfg->glyph_id;
1126 temp.otf_encoded = 1;
1131 temp.otf_encoded = 0;
1133 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1134 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1138 for (i = 0; i < len; i++)
1140 MGlyph temp = gstring->glyphs[from + i];
1142 if (otf_gstring.glyphs[i].glyph_id)
1144 temp.code = otf_gstring.glyphs[i].glyph_id;
1145 temp.otf_encoded = 1;
1147 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1150 ft_find_metric (rfont, gstring, gidx, gstring->used);
1152 if (gpos_feature_names)
1156 MGlyph *base = NULL, *mark = NULL;
1158 if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1159 gpos_feature_names) < 0)
1162 u = otf->head->unitsPerEm;
1163 size10 = rfont->font.property[MFONT_SIZE];
1166 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1167 i < otf_gstring.used; i++, otfg++, g++)
1171 if (! otfg->glyph_id)
1173 switch (otfg->positioning_type)
1179 int format = otfg->f.f1.format;
1181 if (format & OTF_XPlacement)
1182 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1183 if (format & OTF_XPlaDevice)
1184 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1185 if (format & OTF_YPlacement)
1186 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1187 if (format & OTF_YPlaDevice)
1188 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1189 if (format & OTF_XAdvance)
1190 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1191 if (format & OTF_XAdvDevice)
1192 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1196 /* Not yet supported. */
1202 goto label_adjust_anchor;
1203 default: /* i.e. case 6 */
1208 label_adjust_anchor:
1210 int base_x, base_y, mark_x, mark_y;
1212 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1213 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1214 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1215 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1217 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1218 adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1219 prev->code, size, &base_x, &base_y);
1220 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1221 adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1222 g->code, size, &mark_x, &mark_y);
1223 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1224 g->yoff = prev->yoff + mark_y - base_y;
1225 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1228 if (otfg->GlyphClass == OTF_GlyphClass0)
1230 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1236 free (otf_gstring.glyphs);
1240 ft_find_metric (rfont, gstring, from, to);
1241 for (i = 0; i < len; i++)
1243 MGlyph temp = gstring->glyphs[from + i];
1244 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1246 free (otf_gstring.glyphs);
1252 mfont__ft_decode_otf (MGlyph *g)
1254 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1255 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1257 return (c ? c : -1);
1260 #endif /* HAVE_OTF */
1262 #endif /* HAVE_FREETYPE */