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 containing fonts of the corresponding family. In the deeper
81 plist, 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 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0, (FcChar8 **) &filename)
352 if (FcPatternGetString (fs->fonts[i], FC_LANG, 0, (FcChar8 **) &languages)
360 FcPatternGetString (fs->fonts[i], FC_FAMILY, 0, (FcChar8 **) &fname);
361 fam = msymbol (fname);
362 if (! mplist_get (ft_font_list, fam))
363 add_font_info (filename, fam, languages);
366 add_font_info (filename, family, languages);
368 FcFontSetDestroy (fs);
369 FcObjectSetDestroy (os);
370 FcPatternDestroy (pattern);
373 #else /* not HAVE_FONTCONFIG */
382 MPLIST_DO (plist, mfont_freetype_path)
383 if (MPLIST_STRING_P (plist)
384 && (pathname = MPLIST_STRING (plist))
385 && stat (pathname, &buf) == 0)
387 if (S_ISREG (buf.st_mode))
388 add_font_info (pathname, Mnil, NULL);
389 else if (S_ISDIR (buf.st_mode))
391 int len = strlen (pathname);
393 DIR *dir = opendir (pathname);
398 strcpy (path, pathname);
399 strcpy (path + len, "/");
401 while ((dp = readdir (dir)) != NULL)
403 strcpy (path + len, dp->d_name);
404 add_font_info (path, Mnil, NULL);
412 #endif /* not HAVE_FONTCONFIG */
414 /* The FreeType font driver function SELECT. */
416 static MRealizedFont *
417 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
422 MRealizedFont *rfont;
423 MSymbol family, registry;
427 family = FONT_PROPERTY (spec, MFONT_FAMILY);
429 family = FONT_PROPERTY (request, MFONT_FAMILY);
430 registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
431 if (registry == Mnil)
435 ft_font_list = mplist ();
436 #ifdef HAVE_FONTCONFIG
439 plist = mplist_get (ft_font_list, family);
443 plist = mplist_get (ft_font_list, family);
446 mplist_add (ft_font_list, family, plist = mplist ());
453 if (! all_fonts_scaned)
456 all_fonts_scaned = 1;
459 #else /* not HAVE_FONTCONFIG */
460 if (! all_fonts_scaned)
463 all_fonts_scaned = 1;
467 plist = mplist_get (ft_font_list, family);
471 #endif /* not HAVE_FONTCONFIG */
474 plist = MPLIST_VAL (ft_font_list);
477 MPLIST_DO (pl, plist)
479 MFTInfo *ft_info = MPLIST_VAL (pl);
482 if (! mplist_find_by_key (ft_info->charmap_list, registry))
484 /* We always ignore FOUNDRY. */
485 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
486 score = mfont__score (&ft_info->font, spec, request, limited_size);
489 || best_score > score))
499 plist = MPLIST_NEXT (plist);
500 if (! MPLIST_TAIL_P (plist))
506 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
507 rfont->frame = frame;
509 rfont->request = *request;
510 rfont->font = best_font->font;
511 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
512 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
513 rfont->score = best_score;
514 rfont->info = best_font;
515 M17N_OBJECT_REF (best_font);
520 /* The FreeType font driver function OPEN. */
523 ft_open (MRealizedFont *rfont)
525 MFTInfo *base = rfont->info, *ft_info;
526 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
527 int mdebug_mask = MDEBUG_FONT;
530 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
531 ft_info->font = base->font;
532 ft_info->filename = strdup (base->filename);
533 ft_info->otf_flag = base->otf_flag;
534 ft_info->charmap_list = base->charmap_list;
535 M17N_OBJECT_REF (ft_info->charmap_list);
536 M17N_OBJECT_UNREF (base);
537 rfont->info = ft_info;
540 ft_info->ft_face = NULL;
541 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
543 if (registry == Mnil)
545 ft_info->charmap_index
546 = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
547 if (ft_info->charmap_index >= 0
548 && FT_Set_Charmap (ft_info->ft_face,
549 ft_info->ft_face->charmaps[ft_info->charmap_index]))
551 size = rfont->font.property[MFONT_SIZE] / 10;
552 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
555 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
557 rfont->ascent = ft_info->ft_face->ascender >> 6;
558 rfont->descent = - (ft_info->ft_face->descender >> 6);
559 rfont->type = Mfreetype;
560 rfont->fontp = ft_info->ft_face;
564 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
565 if (ft_info->ft_face)
566 FT_Done_Face (ft_info->ft_face);
567 M17N_OBJECT_UNREF (ft_info->charmap_list);
568 free (ft_info->filename);
574 /* The FreeType font driver function FIND_METRIC. */
577 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
580 MFTInfo *ft_info = (MFTInfo *) rfont->info;
581 FT_Face ft_face = ft_info->ft_face;
582 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
584 for (; g != gend; g++)
586 if (g->code == MCHAR_INVALID_CODE)
588 if (FT_IS_SCALABLE (ft_face))
590 unsigned unitsPerEm = ft_face->units_per_EM;
591 int size = rfont->font.property[MFONT_SIZE] / 10;
594 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
595 g->width = ft_face->max_advance_width * size / unitsPerEm;
596 g->ascent = ft_face->ascender * size / unitsPerEm;
597 g->descent = (- ft_face->descender) * size / unitsPerEm;
601 BDF_PropertyRec prop;
604 g->rbearing = g->width = ft_face->available_sizes->width;
605 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
607 g->ascent = prop.u.integer;
608 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
609 g->descent = prop.u.integer;
613 g->ascent = ft_face->available_sizes->height;
620 FT_Glyph_Metrics *metrics;
622 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
623 metrics = &ft_face->glyph->metrics;
624 g->lbearing = (metrics->horiBearingX >> 6);
625 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
626 g->width = metrics->horiAdvance >> 6;
627 g->ascent = metrics->horiBearingY >> 6;
628 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
633 /* The FreeType font driver function ENCODE_CHAR. */
636 ft_encode_char (MRealizedFont *rfont, unsigned code)
640 if (rfont->status == 0)
642 if ((rfont->driver->open) (rfont) < 0)
645 ft_info = (MFTInfo *) rfont->info;
646 code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
648 return MCHAR_INVALID_CODE;
653 /* The FreeType font driver function RENDER. */
655 #define NUM_POINTS 0x1000
658 MDrawPoint points[NUM_POINTS];
663 ft_render (MDrawWindow win, int x, int y,
664 MGlyphString *gstring, MGlyph *from, MGlyph *to,
665 int reverse, MDrawRegion region)
669 MRealizedFace *rface = from->rface;
670 MFrame *frame = rface->frame;
671 FT_Int32 load_flags = FT_LOAD_RENDER;
674 MPointTable point_table[8];
679 /* It is assured that the all glyphs in the current range use the
680 same realized face. */
681 ft_info = (MFTInfo *) rface->rfont->info;
682 ft_face = ft_info->ft_face;
684 if (! gstring->anti_alias)
686 #ifdef FT_LOAD_TARGET_MONO
687 load_flags |= FT_LOAD_TARGET_MONO;
689 load_flags |= FT_LOAD_MONOCHROME;
693 for (i = 0; i < 8; i++)
694 point_table[i].p = point_table[i].points;
696 for (g = from; g < to; x += g++->width)
704 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
705 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
706 bmp = ft_face->glyph->bitmap.buffer;
707 width = ft_face->glyph->bitmap.width;
708 pitch = ft_face->glyph->bitmap.pitch;
709 if (! gstring->anti_alias)
714 if (gstring->anti_alias)
715 for (i = 0; i < ft_face->glyph->bitmap.rows;
716 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
718 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
719 for (j = 0; j < width; j++, xoff++)
721 intensity = bmp[j] >> 5;
724 ptable = point_table + intensity;
728 if (ptable->p - ptable->points == NUM_POINTS)
730 (*frame->driver->draw_points)
732 reverse ? 7 - intensity : intensity,
733 ptable->points, NUM_POINTS, region);
734 ptable->p = ptable->points;
740 for (i = 0; i < ft_face->glyph->bitmap.rows;
741 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
743 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
744 for (j = 0; j < width; j++, xoff++)
746 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
749 ptable = point_table;
753 if (ptable->p - ptable->points == NUM_POINTS)
755 (*frame->driver->draw_points) (frame, win, rface,
757 ptable->points, NUM_POINTS, region);
758 ptable->p = ptable->points;
765 if (gstring->anti_alias)
767 for (i = 1; i < 8; i++)
768 if (point_table[i].p != point_table[i].points)
769 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
770 point_table[i].points,
771 point_table[i].p - point_table[i].points, region);
775 if (point_table[0].p != point_table[0].points)
776 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
777 point_table[0].points,
778 point_table[0].p - point_table[0].points, region);
783 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language)
786 MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
787 char *lang = language != Mnil ? MSYMBOL_NAME (language) : NULL;
789 if (! all_fonts_scaned)
791 #ifdef HAVE_FONTCONFIG
796 all_fonts_scaned = 1;
803 pl = mplist_find_by_key (ft_font_list, family);
810 MPLIST_DO (p, MPLIST_VAL (pl))
812 MFTInfo *ft_info = MPLIST_VAL (p);
814 if (lang && ft_info->languages && strstr (ft_info->languages, lang))
816 if (font && ! mfont__match_p (&ft_info->font, font, MFONT_REGISTRY))
818 mplist_push (plist, FONT_PROPERTY (&ft_info->font, MFONT_FAMILY),
829 MFontDriver mfont__ft_driver =
830 { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
837 if (FT_Init_FreeType (&ft_library) != 0)
838 MERROR (MERROR_FONT_FT, -1);
840 for (i = 0; i < ft_to_prop_size; i++)
841 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
843 Municode_bmp = msymbol ("unicode-bmp");
844 Municode_full = msymbol ("unicode-full");
845 Miso10646_1 = msymbol ("iso10646-1");
846 Miso8859_1 = msymbol ("iso8859-1");
848 #ifdef HAVE_FONTCONFIG
849 fc_generic_family_list = mplist ();
850 mplist_push (fc_generic_family_list, msymbol ("serif"), Mt);
851 mplist_push (fc_generic_family_list, msymbol ("sans-serif"), Mt);
852 mplist_push (fc_generic_family_list, msymbol ("monospace"), Mt);
853 mplist_push (fc_generic_family_list, msymbol ("sans"), Mt);
854 mplist_push (fc_generic_family_list, msymbol ("sans serif"), Mt);
855 mplist_push (fc_generic_family_list, msymbol ("mono"), Mt);
868 MPLIST_DO (plist, ft_font_list)
870 MPLIST_DO (p, MPLIST_VAL (plist))
872 MFTInfo *ft_info = MPLIST_VAL (p);
874 M17N_OBJECT_UNREF (ft_info);
876 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
878 M17N_OBJECT_UNREF (ft_font_list);
881 FT_Done_FreeType (ft_library);
882 all_fonts_scaned = 0;
884 #ifdef HAVE_FONTCONFIG
885 m17n_object_unref (fc_generic_family_list);
891 #ifdef HAVE_FONTCONFIG
896 } FC_vs_M17N_font_prop;
898 static FC_vs_M17N_font_prop fc_weight_table[] =
899 { { FC_WEIGHT_ULTRALIGHT, "extralight" },
900 { FC_WEIGHT_LIGHT, "light" },
901 { FC_WEIGHT_NORMAL, "normal" },
902 { FC_WEIGHT_MEDIUM, "medium" },
903 { FC_WEIGHT_DEMIBOLD, "demibold" },
904 { FC_WEIGHT_EXTRABOLD, "extrabold" },
905 { FC_WEIGHT_BLACK, "black" },
906 { FC_WEIGHT_MEDIUM, NULL } };
908 static FC_vs_M17N_font_prop fc_slant_table[] =
909 { { FC_SLANT_ROMAN, "r" },
910 { FC_SLANT_ITALIC, "i" },
911 { FC_SLANT_OBLIQUE, "o" },
912 { FC_SLANT_ROMAN, NULL } };
914 static FC_vs_M17N_font_prop fc_width_table[] =
915 { { FC_WIDTH_CONDENSED, "condensed" },
916 { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
917 { FC_WIDTH_NORMAL, "normal" },
918 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
919 { FC_WIDTH_EXPANDED, "expanded" },
920 { FC_WIDTH_NORMAL, NULL } };
924 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
928 for (i = 0; table[i].m17n_value; i++)
929 if (val <= table[i].fc_value)
930 msymbol ("table[i].m17n_value");
931 return msymbol ("table[i - 1].m17n_value");
935 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
939 for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
940 return table[i].fc_value;
944 mfont__ft_parse_name (char *name, MFont *font)
946 FcPattern *pat = FcNameParse ((FcChar8 *) name);
953 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
954 mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
955 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
956 mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
957 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
958 mfont__set_property (font, MFONT_WEIGHT,
959 fc_decode_prop (val, fc_weight_table));
960 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
961 mfont__set_property (font, MFONT_STYLE,
962 fc_decode_prop (val, fc_slant_table));
963 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
964 mfont__set_property (font, MFONT_STRETCH,
965 fc_decode_prop (val, fc_width_table));
966 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
967 font->property[MFONT_SIZE] = size * 10;
968 FcPatternDestroy (pat);
973 mfont__ft_unparse_name (MFont *font)
975 FcPattern *pat = FcPatternCreate ();
976 MSymbol sym, weight, style, stretch;
979 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
980 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
981 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
982 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
983 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
984 FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
986 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
987 FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
989 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
990 FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
992 name = (char *) FcNameUnparse (pat);
993 FcPatternDestroy (pat);
996 #endif /* HAVE_FONTCONFIG */
1001 #define DEVICE_DELTA(table, size) \
1002 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1003 ? (table).DeltaValue[(size) >= (table).StartSize] \
1007 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1008 unsigned code, int size, int *x, int *y)
1010 if (anchor->AnchorFormat == 2)
1012 FT_Outline *outline;
1013 int ap = anchor->f.f1.AnchorPoint;
1015 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1016 outline = &ft_face->glyph->outline;
1017 if (ap < outline->n_points)
1019 *x = outline->points[ap].x;
1020 *y = outline->points[ap].y;
1023 else if (anchor->AnchorFormat == 3)
1025 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1026 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1031 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1032 MSymbol script, MSymbol langsys,
1033 MSymbol gsub_features, MSymbol gpos_features)
1035 int len = to - from;
1036 MGlyph *g = MGLYPH (from);
1038 MRealizedFont *rfont;
1041 OTF_GlyphString otf_gstring;
1043 char *script_name, *language_name;
1044 char *gsub_feature_names, *gpos_feature_names;
1050 rfont = g->rface->rfont;
1051 ft_info = rfont->info;
1052 if (ft_info->otf_flag < 0)
1057 otf = OTF_open (ft_info->filename);
1058 if (otf && OTF_get_table (otf, "head") < 0)
1065 ft_info->otf_flag = -1;
1072 script_name = msymbol_name (script);
1075 if (langsys != Mnil)
1076 language_name = msymbol_name (langsys);
1078 language_name = NULL;
1080 = (gsub_features == Mt ? "*"
1081 : gsub_features == Mnil ? NULL
1082 : msymbol_name (gsub_features));
1083 if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1084 gsub_feature_names = NULL;
1086 = (gpos_features == Mt ? "*"
1087 : gpos_features == Mnil ? NULL
1088 : msymbol_name (gpos_features));
1089 if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1090 gpos_feature_names = NULL;
1092 otf_gstring.size = otf_gstring.used = len;
1093 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1094 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1095 for (i = 0, need_cmap = 0; i < len; i++)
1097 if (gstring->glyphs[from + i].otf_encoded)
1099 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1100 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1104 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1109 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1112 OTF_drive_gdef (otf, &otf_gstring);
1113 gidx = gstring->used;
1115 if (gsub_feature_names)
1117 if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1118 gsub_feature_names) < 0)
1120 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1122 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1125 temp.combining_code = 0;
1128 temp.code = otfg->glyph_id;
1129 temp.otf_encoded = 1;
1134 temp.otf_encoded = 0;
1136 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1137 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1141 for (i = 0; i < len; i++)
1143 MGlyph temp = gstring->glyphs[from + i];
1145 if (otf_gstring.glyphs[i].glyph_id)
1147 temp.code = otf_gstring.glyphs[i].glyph_id;
1148 temp.otf_encoded = 1;
1150 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1153 ft_find_metric (rfont, gstring, gidx, gstring->used);
1155 if (gpos_feature_names)
1159 MGlyph *base = NULL, *mark = NULL;
1161 if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1162 gpos_feature_names) < 0)
1165 u = otf->head->unitsPerEm;
1166 size10 = rfont->font.property[MFONT_SIZE];
1169 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1170 i < otf_gstring.used; i++, otfg++, g++)
1174 if (! otfg->glyph_id)
1176 switch (otfg->positioning_type)
1182 int format = otfg->f.f1.format;
1184 if (format & OTF_XPlacement)
1185 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1186 if (format & OTF_XPlaDevice)
1187 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1188 if (format & OTF_YPlacement)
1189 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1190 if (format & OTF_YPlaDevice)
1191 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1192 if (format & OTF_XAdvance)
1193 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1194 if (format & OTF_XAdvDevice)
1195 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1199 /* Not yet supported. */
1205 goto label_adjust_anchor;
1206 default: /* i.e. case 6 */
1211 label_adjust_anchor:
1213 int base_x, base_y, mark_x, mark_y;
1215 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1216 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1217 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1218 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1220 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1221 adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1222 prev->code, size, &base_x, &base_y);
1223 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1224 adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1225 g->code, size, &mark_x, &mark_y);
1226 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1227 g->yoff = prev->yoff + mark_y - base_y;
1228 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1231 if (otfg->GlyphClass == OTF_GlyphClass0)
1233 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1239 free (otf_gstring.glyphs);
1243 ft_find_metric (rfont, gstring, from, to);
1244 for (i = 0; i < len; i++)
1246 MGlyph temp = gstring->glyphs[from + i];
1247 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1249 free (otf_gstring.glyphs);
1255 mfont__ft_decode_otf (MGlyph *g)
1257 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1258 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1260 return (c ? c : -1);
1263 #endif /* HAVE_OTF */
1265 #endif /* HAVE_FREETYPE */