Fix bug#10044
[emacs.git] / src / ftfont.c
blob7858a31be217f34dc6ad4debd2b77a6f4fcea024
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2011 Free Software Foundation, Inc.
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
7 This file is part of GNU Emacs.
9 GNU Emacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 #include <config.h>
23 #include <stdio.h>
24 #include <setjmp.h>
26 #include <fontconfig/fontconfig.h>
27 #include <fontconfig/fcfreetype.h>
29 #include "lisp.h"
30 #include "dispextern.h"
31 #include "frame.h"
32 #include "blockinput.h"
33 #include "character.h"
34 #include "charset.h"
35 #include "coding.h"
36 #include "composite.h"
37 #include "fontset.h"
38 #include "font.h"
39 #include "ftfont.h"
41 /* Symbolic type of this font-driver. */
42 static Lisp_Object Qfreetype;
44 /* Fontconfig's generic families and their aliases. */
45 static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
47 /* Flag to tell if FcInit is already called or not. */
48 static int fc_initialized;
50 /* Handle to a FreeType library instance. */
51 static FT_Library ft_library;
53 /* Cache for FreeType fonts. */
54 static Lisp_Object freetype_font_cache;
56 /* Cache for FT_Face and FcCharSet. */
57 static Lisp_Object ft_face_cache;
59 /* The actual structure for FreeType font that can be casted to struct
60 font. */
62 struct ftfont_info
64 struct font font;
65 #ifdef HAVE_LIBOTF
66 /* The following four members must be here in this order to be
67 compatible with struct xftfont_info (in xftfont.c). */
68 int maybe_otf; /* Flag to tell if this may be OTF or not. */
69 OTF *otf;
70 #endif /* HAVE_LIBOTF */
71 FT_Size ft_size;
72 int index;
73 FT_Matrix matrix;
76 enum ftfont_cache_for
78 FTFONT_CACHE_FOR_FACE,
79 FTFONT_CACHE_FOR_CHARSET,
80 FTFONT_CACHE_FOR_ENTITY
83 static Lisp_Object ftfont_pattern_entity (FcPattern *, Lisp_Object);
85 static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
86 FcPattern *);
87 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
88 enum ftfont_cache_for);
90 static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
92 Lisp_Object ftfont_font_format (FcPattern *, Lisp_Object);
94 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
96 static struct
98 /* registry name */
99 const char *name;
100 /* characters to distinguish the charset from the others */
101 int uniquifier[6];
102 /* additional constraint by language */
103 const char *lang;
104 /* set on demand */
105 FcCharSet *fc_charset;
106 } fc_charset_table[] =
107 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
108 { "iso8859-2", { 0x00A0, 0x010E }},
109 { "iso8859-3", { 0x00A0, 0x0108 }},
110 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
111 { "iso8859-5", { 0x00A0, 0x0401 }},
112 { "iso8859-6", { 0x00A0, 0x060C }},
113 { "iso8859-7", { 0x00A0, 0x0384 }},
114 { "iso8859-8", { 0x00A0, 0x05D0 }},
115 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
116 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
117 { "iso8859-11", { 0x00A0, 0x0E01 }},
118 { "iso8859-13", { 0x00A0, 0x201C }},
119 { "iso8859-14", { 0x00A0, 0x0174 }},
120 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
121 { "iso8859-16", { 0x00A0, 0x0218}},
122 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
123 { "big5-0", { 0xF6B1 }, "zh-tw" },
124 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
125 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
126 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
127 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
128 { "cns11643.1992-3", { 0x201A9 }},
129 { "cns11643.1992-4", { 0x20057 }},
130 { "cns11643.1992-5", { 0x20000 }},
131 { "cns11643.1992-6", { 0x20003 }},
132 { "cns11643.1992-7", { 0x20055 }},
133 { "gbk-0", { 0x4E06 }, "zh-cn"},
134 { "jisx0212.1990-0", { 0x4E44 }},
135 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
136 { "jisx0213.2000-2", { 0xFA49 }},
137 { "jisx0213.2004-1", { 0x20B9F }},
138 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
139 { "tis620.2529-1", { 0x0E01 }, "th"},
140 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
141 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
142 { "mulelao-1", { 0x0E81 }, "lo"},
143 { "unicode-sip", { 0x20000 }},
144 { NULL }
147 /* Dirty hack for handing ADSTYLE property.
149 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
150 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
151 "Oblique", "Italic", or any non-normal SWIDTH property names
152 (e.g. SemiCondensed) are appended. In addition, if there's no
153 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
154 "Regular" is used for FC_STYLE (see the function
155 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
157 Unfortunately this behavior is not documented, so the following
158 code may fail if FreeType changes the behavior in the future. */
160 static Lisp_Object
161 get_adstyle_property (FcPattern *p)
163 FcChar8 *fcstr;
164 char *str, *end;
165 Lisp_Object adstyle;
167 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
168 return Qnil;
169 str = (char *) fcstr;
170 for (end = str; *end && *end != ' '; end++);
171 if (*end)
173 char *newstr = alloca (end - str + 1);
174 memcpy (newstr, str, end - str);
175 newstr[end - str] = '\0';
176 end = newstr + (end - str);
177 str = newstr;
179 if (xstrcasecmp (str, "Regular") == 0
180 || xstrcasecmp (str, "Bold") == 0
181 || xstrcasecmp (str, "Oblique") == 0
182 || xstrcasecmp (str, "Italic") == 0)
183 return Qnil;
184 adstyle = font_intern_prop (str, end - str, 1);
185 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
186 return Qnil;
187 return adstyle;
190 static Lisp_Object
191 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
193 Lisp_Object key, cache, entity;
194 FcChar8 *str;
195 char *file;
196 int idx;
197 int numeric;
198 double dbl;
199 FcBool b;
201 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
202 return Qnil;
203 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
204 return Qnil;
206 file = (char *) str;
207 key = Fcons (make_unibyte_string (file, strlen (file)), make_number (idx));
208 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
209 entity = XCAR (cache);
210 if (! NILP (entity))
212 Lisp_Object val = font_make_entity ();
213 int i;
215 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
216 ASET (val, i, AREF (entity, i));
218 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
219 font_put_extra (val, QCfont_entity, key);
221 return val;
223 entity = font_make_entity ();
224 XSETCAR (cache, entity);
226 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
227 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
229 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
231 char *s = (char *) str;
232 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
234 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
236 char *s = (char *) str;
237 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
239 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
241 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
242 numeric = FC_WEIGHT_MEDIUM;
243 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
245 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
247 numeric += 100;
248 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
250 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
252 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
254 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
256 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
258 else
259 ASET (entity, FONT_SIZE_INDEX, make_number (0));
260 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
261 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
262 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
264 int dpi = dbl;
265 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
267 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
268 && b == FcTrue)
270 ASET (entity, FONT_SIZE_INDEX, make_number (0));
271 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
273 else
275 /* As this font is not scalable, parhaps this is a BDF or PCF
276 font. */
277 FT_Face ft_face;
279 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
280 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
281 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
283 BDF_PropertyRec rec;
285 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
286 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
287 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
288 FT_Done_Face (ft_face);
292 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
293 font_put_extra (entity, QCfont_entity, key);
294 return entity;
298 static Lisp_Object ftfont_generic_family_list;
300 static Lisp_Object
301 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
303 Lisp_Object slot;
304 FcPattern *match;
305 FcResult result;
306 FcLangSet *langset;
308 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
309 if (EQ (family, Qmono))
310 family = Qmonospace;
311 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
312 family = Qsans_serif;
313 slot = assq_no_quit (family, ftfont_generic_family_list);
314 if (! CONSP (slot))
315 return Qnil;
316 if (! EQ (XCDR (slot), Qt))
317 return XCDR (slot);
318 pattern = FcPatternDuplicate (pattern);
319 if (! pattern)
320 goto err;
321 FcPatternDel (pattern, FC_FOUNDRY);
322 FcPatternDel (pattern, FC_FAMILY);
323 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
324 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
326 /* This is to avoid the effect of locale. */
327 static const FcChar8 lang[] = "en";
328 langset = FcLangSetCreate ();
329 FcLangSetAdd (langset, lang);
330 FcPatternAddLangSet (pattern, FC_LANG, langset);
331 FcLangSetDestroy (langset);
333 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
334 FcDefaultSubstitute (pattern);
335 match = FcFontMatch (NULL, pattern, &result);
336 if (match)
338 FcChar8 *fam;
340 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
341 family = intern ((char *) fam);
343 else
344 family = Qnil;
345 XSETCDR (slot, family);
346 if (match) FcPatternDestroy (match);
347 err:
348 if (pattern) FcPatternDestroy (pattern);
349 return family;
352 struct ftfont_cache_data
354 FT_Face ft_face;
355 FcCharSet *fc_charset;
358 static Lisp_Object
359 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
361 Lisp_Object cache, val, entity;
362 struct ftfont_cache_data *cache_data;
364 if (FONT_ENTITY_P (key))
366 entity = key;
367 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
368 xassert (CONSP (val));
369 key = XCDR (val);
371 else
372 entity = Qnil;
374 if (NILP (ft_face_cache))
375 cache = Qnil;
376 else
377 cache = Fgethash (key, ft_face_cache, Qnil);
378 if (NILP (cache))
380 if (NILP (ft_face_cache))
382 Lisp_Object args[2];
384 args[0] = QCtest;
385 args[1] = Qequal;
386 ft_face_cache = Fmake_hash_table (2, args);
388 cache_data = xmalloc (sizeof (struct ftfont_cache_data));
389 cache_data->ft_face = NULL;
390 cache_data->fc_charset = NULL;
391 val = make_save_value (NULL, 0);
392 XSAVE_VALUE (val)->integer = 0;
393 XSAVE_VALUE (val)->pointer = cache_data;
394 cache = Fcons (Qnil, val);
395 Fputhash (key, cache, ft_face_cache);
397 else
399 val = XCDR (cache);
400 cache_data = XSAVE_VALUE (val)->pointer;
403 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
404 return cache;
406 if (cache_for == FTFONT_CACHE_FOR_FACE
407 ? ! cache_data->ft_face : ! cache_data->fc_charset)
409 char *filename = SSDATA (XCAR (key));
410 int idx = XINT (XCDR (key));
412 if (cache_for == FTFONT_CACHE_FOR_FACE)
414 if (! ft_library
415 && FT_Init_FreeType (&ft_library) != 0)
416 return Qnil;
417 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
418 != 0)
419 return Qnil;
421 else
423 FcPattern *pat = NULL;
424 FcFontSet *fontset = NULL;
425 FcObjectSet *objset = NULL;
426 FcCharSet *charset = NULL;
428 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
429 FC_INDEX, FcTypeInteger, idx, NULL);
430 if (! pat)
431 goto finish;
432 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
433 if (! objset)
434 goto finish;
435 fontset = FcFontList (NULL, pat, objset);
436 if (! fontset)
437 goto finish;
438 if (fontset && fontset->nfont > 0
439 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
440 &charset)
441 == FcResultMatch))
442 cache_data->fc_charset = FcCharSetCopy (charset);
443 else
444 cache_data->fc_charset = FcCharSetCreate ();
446 finish:
447 if (fontset)
448 FcFontSetDestroy (fontset);
449 if (objset)
450 FcObjectSetDestroy (objset);
451 if (pat)
452 FcPatternDestroy (pat);
455 return cache;
458 FcCharSet *
459 ftfont_get_fc_charset (Lisp_Object entity)
461 Lisp_Object val, cache;
462 struct ftfont_cache_data *cache_data;
464 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
465 val = XCDR (cache);
466 cache_data = XSAVE_VALUE (val)->pointer;
467 return cache_data->fc_charset;
470 #ifdef HAVE_LIBOTF
471 static OTF *
472 ftfont_get_otf (struct ftfont_info *ftfont_info)
474 OTF *otf;
476 if (ftfont_info->otf)
477 return ftfont_info->otf;
478 if (! ftfont_info->maybe_otf)
479 return NULL;
480 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
481 if (! otf || OTF_get_table (otf, "head") < 0)
483 if (otf)
484 OTF_close (otf);
485 ftfont_info->maybe_otf = 0;
486 return NULL;
488 ftfont_info->otf = otf;
489 return otf;
491 #endif /* HAVE_LIBOTF */
493 static Lisp_Object ftfont_get_cache (FRAME_PTR);
494 static Lisp_Object ftfont_list (Lisp_Object, Lisp_Object);
495 static Lisp_Object ftfont_match (Lisp_Object, Lisp_Object);
496 static Lisp_Object ftfont_list_family (Lisp_Object);
497 static Lisp_Object ftfont_open (FRAME_PTR, Lisp_Object, int);
498 static void ftfont_close (FRAME_PTR, struct font *);
499 static int ftfont_has_char (Lisp_Object, int);
500 static unsigned ftfont_encode_char (struct font *, int);
501 static int ftfont_text_extents (struct font *, unsigned *, int,
502 struct font_metrics *);
503 static int ftfont_get_bitmap (struct font *, unsigned,
504 struct font_bitmap *, int);
505 static int ftfont_anchor_point (struct font *, unsigned, int,
506 int *, int *);
507 #ifdef HAVE_LIBOTF
508 static Lisp_Object ftfont_otf_capability (struct font *);
509 # ifdef HAVE_M17N_FLT
510 static Lisp_Object ftfont_shape (Lisp_Object);
511 # endif
512 #endif
514 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
515 static int ftfont_variation_glyphs (struct font *, int c,
516 unsigned variations[256]);
517 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
519 struct font_driver ftfont_driver =
521 0, /* Qfreetype */
522 0, /* case insensitive */
523 ftfont_get_cache,
524 ftfont_list,
525 ftfont_match,
526 ftfont_list_family,
527 NULL, /* free_entity */
528 ftfont_open,
529 ftfont_close,
530 /* We can't draw a text without device dependent functions. */
531 NULL, /* prepare_face */
532 NULL, /* done_face */
533 ftfont_has_char,
534 ftfont_encode_char,
535 ftfont_text_extents,
536 /* We can't draw a text without device dependent functions. */
537 NULL, /* draw */
538 ftfont_get_bitmap,
539 NULL, /* get_bitmap */
540 NULL, /* free_bitmap */
541 NULL, /* get_outline */
542 ftfont_anchor_point,
543 #ifdef HAVE_LIBOTF
544 ftfont_otf_capability,
545 #else /* not HAVE_LIBOTF */
546 NULL,
547 #endif /* not HAVE_LIBOTF */
548 NULL, /* otf_drive */
549 NULL, /* start_for_frame */
550 NULL, /* end_for_frame */
551 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
552 ftfont_shape,
553 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
554 NULL,
555 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
556 NULL, /* check */
558 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
559 ftfont_variation_glyphs,
560 #else
561 NULL,
562 #endif
564 ftfont_filter_properties, /* filter_properties */
567 static Lisp_Object
568 ftfont_get_cache (FRAME_PTR f)
570 return freetype_font_cache;
573 static int
574 ftfont_get_charset (Lisp_Object registry)
576 char *str = SSDATA (SYMBOL_NAME (registry));
577 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
578 Lisp_Object regexp;
579 int i, j;
581 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
583 if (str[i] == '.')
584 re[j++] = '\\';
585 else if (str[i] == '*')
586 re[j++] = '.';
587 re[j] = str[i];
588 if (re[j] == '?')
589 re[j] = '.';
591 re[j] = '\0';
592 regexp = make_unibyte_string (re, j);
593 for (i = 0; fc_charset_table[i].name; i++)
594 if (fast_c_string_match_ignore_case (regexp, fc_charset_table[i].name) >= 0)
595 break;
596 if (! fc_charset_table[i].name)
597 return -1;
598 if (! fc_charset_table[i].fc_charset)
600 FcCharSet *charset = FcCharSetCreate ();
601 int *uniquifier = fc_charset_table[i].uniquifier;
603 if (! charset)
604 return -1;
605 for (j = 0; uniquifier[j]; j++)
606 if (! FcCharSetAddChar (charset, uniquifier[j]))
608 FcCharSetDestroy (charset);
609 return -1;
611 fc_charset_table[i].fc_charset = charset;
613 return i;
616 struct OpenTypeSpec
618 Lisp_Object script;
619 unsigned int script_tag, langsys_tag;
620 int nfeatures[2];
621 unsigned int *features[2];
624 #define OTF_SYM_TAG(SYM, TAG) \
625 do { \
626 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
627 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
628 } while (0)
630 #define OTF_TAG_STR(TAG, P) \
631 do { \
632 (P)[0] = (char) (TAG >> 24); \
633 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
634 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
635 (P)[3] = (char) (TAG & 0xFF); \
636 (P)[4] = '\0'; \
637 } while (0)
639 #ifdef HAVE_LIBOTF
640 #define OTF_TAG_SYM(SYM, TAG) \
641 do { \
642 char str[5]; \
644 OTF_TAG_STR (TAG, str); \
645 (SYM) = font_intern_prop (str, 4, 1); \
646 } while (0)
647 #endif
650 static struct OpenTypeSpec *
651 ftfont_get_open_type_spec (Lisp_Object otf_spec)
653 struct OpenTypeSpec *spec = malloc (sizeof (struct OpenTypeSpec));
654 Lisp_Object val;
655 int i, j, negative;
657 if (! spec)
658 return NULL;
659 spec->script = XCAR (otf_spec);
660 if (! NILP (spec->script))
662 OTF_SYM_TAG (spec->script, spec->script_tag);
663 val = assq_no_quit (spec->script, Votf_script_alist);
664 if (CONSP (val) && SYMBOLP (XCDR (val)))
665 spec->script = XCDR (val);
666 else
667 spec->script = Qnil;
669 else
670 spec->script_tag = 0x44464C54; /* "DFLT" */
671 otf_spec = XCDR (otf_spec);
672 spec->langsys_tag = 0;
673 if (! NILP (otf_spec))
675 val = XCAR (otf_spec);
676 if (! NILP (val))
677 OTF_SYM_TAG (val, spec->langsys_tag);
678 otf_spec = XCDR (otf_spec);
680 spec->nfeatures[0] = spec->nfeatures[1] = 0;
681 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
683 Lisp_Object len;
685 val = XCAR (otf_spec);
686 if (NILP (val))
687 continue;
688 len = Flength (val);
689 spec->features[i] =
690 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
692 : malloc (sizeof (int) * XINT (len)));
693 if (! spec->features[i])
695 if (i > 0 && spec->features[0])
696 free (spec->features[0]);
697 free (spec);
698 return NULL;
700 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
702 if (NILP (XCAR (val)))
703 negative = 1;
704 else
706 unsigned int tag;
708 OTF_SYM_TAG (XCAR (val), tag);
709 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
712 spec->nfeatures[i] = j;
714 return spec;
717 static FcPattern *
718 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
720 Lisp_Object tmp, extra;
721 FcPattern *pattern = NULL;
722 FcCharSet *charset = NULL;
723 FcLangSet *langset = NULL;
724 int n;
725 int dpi = -1;
726 int scalable = -1;
727 Lisp_Object script = Qnil;
728 Lisp_Object registry;
729 int fc_charset_idx;
731 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
732 && n < 100)
733 /* Fontconfig doesn't support reverse-italic/obligue. */
734 return NULL;
736 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
737 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
738 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
739 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
740 scalable = 1;
742 registry = AREF (spec, FONT_REGISTRY_INDEX);
743 if (NILP (registry)
744 || EQ (registry, Qascii_0)
745 || EQ (registry, Qiso10646_1)
746 || EQ (registry, Qunicode_bmp))
747 fc_charset_idx = -1;
748 else
750 FcChar8 *lang;
752 fc_charset_idx = ftfont_get_charset (registry);
753 if (fc_charset_idx < 0)
754 return NULL;
755 charset = fc_charset_table[fc_charset_idx].fc_charset;
756 *langname = fc_charset_table[fc_charset_idx].lang;
757 lang = (FcChar8 *) *langname;
758 if (lang)
760 langset = FcLangSetCreate ();
761 if (! langset)
762 goto err;
763 FcLangSetAdd (langset, lang);
767 otlayout[0] = '\0';
768 for (extra = AREF (spec, FONT_EXTRA_INDEX);
769 CONSP (extra); extra = XCDR (extra))
771 Lisp_Object key, val;
773 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
774 if (EQ (key, QCdpi))
776 if (INTEGERP (val))
777 dpi = XINT (val);
779 else if (EQ (key, QClang))
781 if (! langset)
782 langset = FcLangSetCreate ();
783 if (! langset)
784 goto err;
785 if (SYMBOLP (val))
787 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
788 goto err;
790 else
791 for (; CONSP (val); val = XCDR (val))
792 if (SYMBOLP (XCAR (val))
793 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
794 goto err;
796 else if (EQ (key, QCotf))
798 if (CONSP (val))
800 *otspec = ftfont_get_open_type_spec (val);
801 if (! *otspec)
802 return NULL;
803 strcat (otlayout, "otlayout:");
804 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
805 script = (*otspec)->script;
808 else if (EQ (key, QCscript))
809 script = val;
810 else if (EQ (key, QCscalable))
811 scalable = ! NILP (val);
814 if (! NILP (script) && ! charset)
816 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
818 if (CONSP (chars) && CONSP (CDR (chars)))
820 charset = FcCharSetCreate ();
821 if (! charset)
822 goto err;
823 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
824 if (CHARACTERP (XCAR (chars))
825 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
826 goto err;
830 pattern = FcPatternCreate ();
831 if (! pattern)
832 goto err;
833 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
834 if (! NILP (tmp)
835 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
836 goto err;
837 tmp = AREF (spec, FONT_FAMILY_INDEX);
838 if (! NILP (tmp)
839 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
840 goto err;
841 if (charset
842 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
843 goto err;
844 if (langset
845 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
846 goto err;
847 if (dpi >= 0
848 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
849 goto err;
850 if (scalable >= 0
851 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
852 goto err;
854 goto finish;
856 err:
857 /* We come here because of unexpected error in fontconfig API call
858 (usually insufficient memory). */
859 if (pattern)
861 FcPatternDestroy (pattern);
862 pattern = NULL;
864 if (*otspec)
866 if ((*otspec)->nfeatures[0] > 0)
867 free ((*otspec)->features[0]);
868 if ((*otspec)->nfeatures[1] > 0)
869 free ((*otspec)->features[1]);
870 free (*otspec);
871 *otspec = NULL;
874 finish:
875 if (langset) FcLangSetDestroy (langset);
876 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
877 return pattern;
880 static Lisp_Object
881 ftfont_list (Lisp_Object frame, Lisp_Object spec)
883 Lisp_Object val = Qnil, family, adstyle;
884 int i;
885 FcPattern *pattern;
886 FcFontSet *fontset = NULL;
887 FcObjectSet *objset = NULL;
888 FcCharSet *charset;
889 Lisp_Object chars = Qnil;
890 char otlayout[15]; /* For "otlayout:XXXX" */
891 struct OpenTypeSpec *otspec = NULL;
892 int spacing = -1;
893 const char *langname = NULL;
895 if (! fc_initialized)
897 FcInit ();
898 fc_initialized = 1;
901 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
902 if (! pattern)
903 return Qnil;
904 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
906 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
907 if (! NILP (val))
909 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
910 if (CONSP (val) && VECTORP (XCDR (val)))
911 chars = XCDR (val);
913 val = Qnil;
915 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
916 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
917 family = AREF (spec, FONT_FAMILY_INDEX);
918 if (! NILP (family))
920 Lisp_Object resolved;
922 resolved = ftfont_resolve_generic_family (family, pattern);
923 if (! NILP (resolved))
925 FcPatternDel (pattern, FC_FAMILY);
926 if (! FcPatternAddString (pattern, FC_FAMILY,
927 SYMBOL_FcChar8 (resolved)))
928 goto err;
931 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
932 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
933 adstyle = Qnil;
934 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
935 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
936 FC_STYLE, FC_FILE, FC_INDEX,
937 #ifdef FC_CAPABILITY
938 FC_CAPABILITY,
939 #endif /* FC_CAPABILITY */
940 #ifdef FC_FONTFORMAT
941 FC_FONTFORMAT,
942 #endif
943 NULL);
944 if (! objset)
945 goto err;
946 if (! NILP (chars))
947 FcObjectSetAdd (objset, FC_CHARSET);
949 fontset = FcFontList (NULL, pattern, objset);
950 if (! fontset || fontset->nfont == 0)
951 goto finish;
952 #if 0
953 /* Need fix because this finds any fonts. */
954 if (fontset->nfont == 0 && ! NILP (family))
956 /* Try maching with configuration. For instance, the
957 configuration may specify "Nimbus Mono L" as an alias of
958 "Courier". */
959 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
960 SYMBOL_FcChar8 (family), NULL);
961 FcChar8 *fam;
963 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
965 for (i = 0;
966 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
967 i++)
969 FcPatternDel (pattern, FC_FAMILY);
970 FcPatternAddString (pattern, FC_FAMILY, fam);
971 FcFontSetDestroy (fontset);
972 fontset = FcFontList (NULL, pattern, objset);
973 if (fontset && fontset->nfont > 0)
974 break;
978 #endif
979 for (i = 0; i < fontset->nfont; i++)
981 Lisp_Object entity;
983 if (spacing >= 0)
985 int this;
987 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
988 == FcResultMatch)
989 && spacing != this)
990 continue;
993 #ifdef FC_CAPABILITY
994 if (otlayout[0])
996 FcChar8 *this;
998 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
999 != FcResultMatch
1000 || ! strstr ((char *) this, otlayout))
1001 continue;
1003 #endif /* FC_CAPABILITY */
1004 #ifdef HAVE_LIBOTF
1005 if (otspec)
1007 FcChar8 *file;
1008 OTF *otf;
1010 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1011 != FcResultMatch)
1012 continue;
1013 otf = OTF_open ((char *) file);
1014 if (! otf)
1015 continue;
1016 if (OTF_check_features (otf, 1,
1017 otspec->script_tag, otspec->langsys_tag,
1018 otspec->features[0],
1019 otspec->nfeatures[0]) != 1
1020 || OTF_check_features (otf, 0,
1021 otspec->script_tag, otspec->langsys_tag,
1022 otspec->features[1],
1023 otspec->nfeatures[1]) != 1)
1024 continue;
1026 #endif /* HAVE_LIBOTF */
1027 if (VECTORP (chars))
1029 int j;
1031 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1032 != FcResultMatch)
1033 continue;
1034 for (j = 0; j < ASIZE (chars); j++)
1035 if (NATNUMP (AREF (chars, j))
1036 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1037 break;
1038 if (j == ASIZE (chars))
1039 continue;
1041 if (! NILP (adstyle) || langname)
1043 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1045 if (! NILP (adstyle)
1046 && (NILP (this_adstyle)
1047 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1048 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1049 continue;
1050 if (langname
1051 && ! NILP (this_adstyle)
1052 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1053 continue;
1055 entity = ftfont_pattern_entity (fontset->fonts[i],
1056 AREF (spec, FONT_EXTRA_INDEX));
1057 if (! NILP (entity))
1058 val = Fcons (entity, val);
1060 val = Fnreverse (val);
1061 goto finish;
1063 err:
1064 /* We come here because of unexpected error in fontconfig API call
1065 (usually insufficient memory). */
1066 val = Qnil;
1068 finish:
1069 FONT_ADD_LOG ("ftfont-list", spec, val);
1070 if (objset) FcObjectSetDestroy (objset);
1071 if (fontset) FcFontSetDestroy (fontset);
1072 if (pattern) FcPatternDestroy (pattern);
1073 return val;
1076 static Lisp_Object
1077 ftfont_match (Lisp_Object frame, Lisp_Object spec)
1079 Lisp_Object entity = Qnil;
1080 FcPattern *pattern, *match = NULL;
1081 FcResult result;
1082 char otlayout[15]; /* For "otlayout:XXXX" */
1083 struct OpenTypeSpec *otspec = NULL;
1084 const char *langname = NULL;
1086 if (! fc_initialized)
1088 FcInit ();
1089 fc_initialized = 1;
1092 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1093 if (! pattern)
1094 return Qnil;
1096 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1098 FcValue value;
1100 value.type = FcTypeDouble;
1101 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1102 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1104 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1106 FcDefaultSubstitute (pattern);
1107 match = FcFontMatch (NULL, pattern, &result);
1108 if (match)
1110 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1111 FcPatternDestroy (match);
1112 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1113 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1114 ftfont_generic_family_list))
1115 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1116 AREF (entity, FONT_FAMILY_INDEX))))
1117 entity = Qnil;
1120 FcPatternDestroy (pattern);
1122 FONT_ADD_LOG ("ftfont-match", spec, entity);
1123 return entity;
1126 static Lisp_Object
1127 ftfont_list_family (Lisp_Object frame)
1129 Lisp_Object list = Qnil;
1130 FcPattern *pattern = NULL;
1131 FcFontSet *fontset = NULL;
1132 FcObjectSet *objset = NULL;
1133 int i;
1135 if (! fc_initialized)
1137 FcInit ();
1138 fc_initialized = 1;
1141 pattern = FcPatternCreate ();
1142 if (! pattern)
1143 goto finish;
1144 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1145 if (! objset)
1146 goto finish;
1147 fontset = FcFontList (NULL, pattern, objset);
1148 if (! fontset)
1149 goto finish;
1151 for (i = 0; i < fontset->nfont; i++)
1153 FcPattern *pat = fontset->fonts[i];
1154 FcChar8 *str;
1156 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1157 list = Fcons (intern ((char *) str), list);
1160 finish:
1161 if (objset) FcObjectSetDestroy (objset);
1162 if (fontset) FcFontSetDestroy (fontset);
1163 if (pattern) FcPatternDestroy (pattern);
1165 return list;
1169 static Lisp_Object
1170 ftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
1172 struct ftfont_info *ftfont_info;
1173 struct font *font;
1174 struct ftfont_cache_data *cache_data;
1175 FT_Face ft_face;
1176 FT_Size ft_size;
1177 FT_UInt size;
1178 Lisp_Object val, filename, idx, cache, font_object;
1179 int scalable;
1180 int spacing;
1181 char name[256];
1182 int i, len;
1183 int upEM;
1185 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1186 if (! CONSP (val))
1187 return Qnil;
1188 val = XCDR (val);
1189 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1190 if (NILP (cache))
1191 return Qnil;
1192 filename = XCAR (val);
1193 idx = XCDR (val);
1194 val = XCDR (cache);
1195 cache_data = XSAVE_VALUE (XCDR (cache))->pointer;
1196 ft_face = cache_data->ft_face;
1197 if (XSAVE_VALUE (val)->integer > 0)
1199 /* FT_Face in this cache is already used by the different size. */
1200 if (FT_New_Size (ft_face, &ft_size) != 0)
1201 return Qnil;
1202 if (FT_Activate_Size (ft_size) != 0)
1204 FT_Done_Size (ft_size);
1205 return Qnil;
1208 XSAVE_VALUE (val)->integer++;
1209 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1210 if (size == 0)
1211 size = pixel_size;
1212 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1214 if (XSAVE_VALUE (val)->integer == 0)
1215 FT_Done_Face (ft_face);
1216 return Qnil;
1219 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
1220 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
1221 len = font_unparse_xlfd (entity, size, name, 256);
1222 if (len > 0)
1223 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
1224 len = font_unparse_fcname (entity, size, name, 256);
1225 if (len > 0)
1226 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
1227 else
1228 ASET (font_object, FONT_FULLNAME_INDEX,
1229 AREF (font_object, FONT_NAME_INDEX));
1230 ASET (font_object, FONT_FILE_INDEX, filename);
1231 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
1232 font = XFONT_OBJECT (font_object);
1233 ftfont_info = (struct ftfont_info *) font;
1234 ftfont_info->ft_size = ft_face->size;
1235 ftfont_info->index = XINT (idx);
1236 #ifdef HAVE_LIBOTF
1237 ftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
1238 ftfont_info->otf = NULL;
1239 #endif /* HAVE_LIBOTF */
1240 /* This means that there's no need of transformation. */
1241 ftfont_info->matrix.xx = 0;
1242 font->pixel_size = size;
1243 font->driver = &ftfont_driver;
1244 font->encoding_charset = font->repertory_charset = -1;
1246 upEM = ft_face->units_per_EM;
1247 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1248 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1249 if (scalable)
1251 font->ascent = ft_face->ascender * size / upEM;
1252 font->descent = - ft_face->descender * size / upEM;
1253 font->height = ft_face->height * size / upEM;
1255 else
1257 font->ascent = ft_face->size->metrics.ascender >> 6;
1258 font->descent = - ft_face->size->metrics.descender >> 6;
1259 font->height = ft_face->size->metrics.height >> 6;
1261 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1262 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1263 else
1264 spacing = FC_PROPORTIONAL;
1265 if (spacing != FC_PROPORTIONAL
1266 #ifdef FC_DUAL
1267 && spacing != FC_DUAL
1268 #endif /* FC_DUAL */
1270 font->min_width = font->average_width = font->space_width
1271 = (scalable ? ft_face->max_advance_width * size / upEM
1272 : ft_face->size->metrics.max_advance >> 6);
1273 else
1275 int n;
1277 font->min_width = font->average_width = font->space_width = 0;
1278 for (i = 32, n = 0; i < 127; i++)
1279 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1281 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1283 if (this_width > 0
1284 && (! font->min_width || font->min_width > this_width))
1285 font->min_width = this_width;
1286 if (i == 32)
1287 font->space_width = this_width;
1288 font->average_width += this_width;
1289 n++;
1291 if (n > 0)
1292 font->average_width /= n;
1295 font->baseline_offset = 0;
1296 font->relative_compose = 0;
1297 font->default_ascent = 0;
1298 font->vertical_centering = 0;
1299 if (scalable)
1301 font->underline_position = -ft_face->underline_position * size / upEM;
1302 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1304 else
1306 font->underline_position = -1;
1307 font->underline_thickness = 0;
1310 return font_object;
1313 static void
1314 ftfont_close (FRAME_PTR f, struct font *font)
1316 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1317 Lisp_Object val, cache;
1319 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1320 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1321 xassert (CONSP (cache));
1322 val = XCDR (cache);
1323 (XSAVE_VALUE (val)->integer)--;
1324 if (XSAVE_VALUE (val)->integer == 0)
1326 struct ftfont_cache_data *cache_data = XSAVE_VALUE (val)->pointer;
1328 FT_Done_Face (cache_data->ft_face);
1329 #ifdef HAVE_LIBOTF
1330 if (ftfont_info->otf)
1331 OTF_close (ftfont_info->otf);
1332 #endif
1333 cache_data->ft_face = NULL;
1335 else
1336 FT_Done_Size (ftfont_info->ft_size);
1339 static int
1340 ftfont_has_char (Lisp_Object font, int c)
1342 struct charset *cs = NULL;
1344 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1345 && charset_jisx0208 >= 0)
1346 cs = CHARSET_FROM_ID (charset_jisx0208);
1347 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1348 && charset_ksc5601 >= 0)
1349 cs = CHARSET_FROM_ID (charset_ksc5601);
1350 if (cs)
1351 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1353 if (FONT_ENTITY_P (font))
1355 FcCharSet *charset = ftfont_get_fc_charset (font);
1357 return (FcCharSetHasChar (charset, c) == FcTrue);
1359 else
1361 struct ftfont_info *ftfont_info;
1363 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1364 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1365 != 0);
1369 static unsigned
1370 ftfont_encode_char (struct font *font, int c)
1372 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1373 FT_Face ft_face = ftfont_info->ft_size->face;
1374 FT_ULong charcode = c;
1375 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1377 return (code > 0 ? code : FONT_INVALID_CODE);
1380 static int
1381 ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
1383 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1384 FT_Face ft_face = ftfont_info->ft_size->face;
1385 int width = 0;
1386 int i, first;
1388 if (ftfont_info->ft_size != ft_face->size)
1389 FT_Activate_Size (ftfont_info->ft_size);
1390 if (metrics)
1391 memset (metrics, 0, sizeof (struct font_metrics));
1392 for (i = 0, first = 1; i < nglyphs; i++)
1394 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1396 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1398 if (first)
1400 if (metrics)
1402 metrics->lbearing = m->horiBearingX >> 6;
1403 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1404 metrics->ascent = m->horiBearingY >> 6;
1405 metrics->descent = (m->height - m->horiBearingY) >> 6;
1407 first = 0;
1409 if (metrics)
1411 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1412 metrics->lbearing = width + (m->horiBearingX >> 6);
1413 if (metrics->rbearing
1414 < width + ((m->horiBearingX + m->width) >> 6))
1415 metrics->rbearing
1416 = width + ((m->horiBearingX + m->width) >> 6);
1417 if (metrics->ascent < (m->horiBearingY >> 6))
1418 metrics->ascent = m->horiBearingY >> 6;
1419 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1420 metrics->descent = (m->height - m->horiBearingY) >> 6;
1422 width += m->horiAdvance >> 6;
1424 else
1426 width += font->space_width;
1429 if (metrics)
1430 metrics->width = width;
1432 return width;
1435 static int
1436 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1438 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1439 FT_Face ft_face = ftfont_info->ft_size->face;
1440 FT_Int32 load_flags = FT_LOAD_RENDER;
1442 if (ftfont_info->ft_size != ft_face->size)
1443 FT_Activate_Size (ftfont_info->ft_size);
1444 if (bits_per_pixel == 1)
1446 #ifdef FT_LOAD_TARGET_MONO
1447 load_flags |= FT_LOAD_TARGET_MONO;
1448 #else
1449 load_flags |= FT_LOAD_MONOCHROME;
1450 #endif
1452 else if (bits_per_pixel != 8)
1453 /* We don't support such a rendering. */
1454 return -1;
1456 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1457 return -1;
1458 bitmap->bits_per_pixel
1459 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1460 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1461 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1462 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1463 : -1);
1464 if (bitmap->bits_per_pixel < 0)
1465 /* We don't suport that kind of pixel mode. */
1466 return -1;
1467 bitmap->rows = ft_face->glyph->bitmap.rows;
1468 bitmap->width = ft_face->glyph->bitmap.width;
1469 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1470 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1471 bitmap->left = ft_face->glyph->bitmap_left;
1472 bitmap->top = ft_face->glyph->bitmap_top;
1473 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1474 bitmap->extra = NULL;
1476 return 0;
1479 static int
1480 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1481 int *x, int *y)
1483 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1484 FT_Face ft_face = ftfont_info->ft_size->face;
1486 if (ftfont_info->ft_size != ft_face->size)
1487 FT_Activate_Size (ftfont_info->ft_size);
1488 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1489 return -1;
1490 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1491 return -1;
1492 if (idx >= ft_face->glyph->outline.n_points)
1493 return -1;
1494 *x = ft_face->glyph->outline.points[idx].x;
1495 *y = ft_face->glyph->outline.points[idx].y;
1496 return 0;
1499 #ifdef HAVE_LIBOTF
1501 static Lisp_Object
1502 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1504 Lisp_Object scripts, langsyses, features, sym;
1505 int i, j, k, l;
1507 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1509 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1511 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1513 OTF_LangSys *otf_langsys;
1515 if (j >= 0)
1516 otf_langsys = otf_script->LangSys + j;
1517 else if (otf_script->DefaultLangSysOffset)
1518 otf_langsys = &otf_script->DefaultLangSys;
1519 else
1520 break;
1522 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1524 l = otf_langsys->FeatureIndex[k];
1525 if (l >= gsub_gpos->FeatureList.FeatureCount)
1526 continue;
1527 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1528 features = Fcons (sym, features);
1530 if (j >= 0)
1531 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1532 else
1533 sym = Qnil;
1534 langsyses = Fcons (Fcons (sym, features), langsyses);
1537 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1538 scripts = Fcons (Fcons (sym, langsyses), scripts);
1540 return scripts;
1545 static Lisp_Object
1546 ftfont_otf_capability (struct font *font)
1548 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1549 OTF *otf = ftfont_get_otf (ftfont_info);
1550 Lisp_Object gsub_gpos;
1552 if (! otf)
1553 return Qnil;
1554 gsub_gpos = Fcons (Qnil, Qnil);
1555 if (OTF_get_table (otf, "GSUB") == 0
1556 && otf->gsub->FeatureList.FeatureCount > 0)
1557 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1558 if (OTF_get_table (otf, "GPOS") == 0
1559 && otf->gpos->FeatureList.FeatureCount > 0)
1560 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1561 return gsub_gpos;
1564 #ifdef HAVE_M17N_FLT
1566 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1567 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1568 /* We can use the new feature of libotf and m17n-flt to handle the
1569 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1570 some Agian scripts. */
1571 #define M17N_FLT_USE_NEW_FEATURE
1572 #endif
1574 struct MFLTFontFT
1576 MFLTFont flt_font;
1577 struct font *font;
1578 FT_Face ft_face;
1579 OTF *otf;
1580 FT_Matrix *matrix;
1583 static int
1584 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1585 int from, int to)
1587 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1588 FT_Face ft_face = flt_font_ft->ft_face;
1589 MFLTGlyph *g;
1591 for (g = gstring->glyphs + from; from < to; g++, from++)
1592 if (! g->encoded)
1594 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1596 g->code = code > 0 ? code : FONT_INVALID_CODE;
1597 g->encoded = 1;
1599 return 0;
1602 /* Operators for 26.6 fixed fractional pixel format */
1604 #define FLOOR(x) ((x) & -64)
1605 #define CEIL(x) (((x)+63) & -64)
1606 #define ROUND(x) (((x)+32) & -64)
1608 static int
1609 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1610 int from, int to)
1612 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1613 FT_Face ft_face = flt_font_ft->ft_face;
1614 MFLTGlyph *g;
1616 for (g = gstring->glyphs + from; from < to; g++, from++)
1617 if (! g->measured)
1619 if (g->code != FONT_INVALID_CODE)
1621 FT_Glyph_Metrics *m;
1623 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1624 abort ();
1625 m = &ft_face->glyph->metrics;
1626 if (flt_font_ft->matrix)
1628 FT_Vector v[4];
1629 int i;
1631 v[0].x = v[1].x = m->horiBearingX;
1632 v[2].x = v[3].x = m->horiBearingX + m->width;
1633 v[0].y = v[2].y = m->horiBearingY;
1634 v[1].y = v[3].y = m->horiBearingY - m->height;
1635 for (i = 0; i < 4; i++)
1636 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1637 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1638 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1639 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1640 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1642 else
1644 g->lbearing = FLOOR (m->horiBearingX);
1645 g->rbearing = CEIL (m->horiBearingX + m->width);
1646 g->ascent = CEIL (m->horiBearingY);
1647 g->descent = - FLOOR (m->horiBearingY - m->height);
1649 g->xadv = ROUND (ft_face->glyph->advance.x);
1651 else
1653 g->lbearing = 0;
1654 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1655 g->ascent = flt_font_ft->font->ascent << 6;
1656 g->descent = flt_font_ft->font->descent << 6;
1658 g->yadv = 0;
1659 g->measured = 1;
1661 return 0;
1664 static int
1665 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1667 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1669 #define FEATURE_ANY(IDX) \
1670 (spec->features[IDX] \
1671 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1673 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1674 OTF *otf = flt_font_ft->otf;
1675 OTF_Tag *tags;
1676 int i, n, negative;
1678 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1679 /* Return 1 iff any of GSUB or GPOS support the script (and language). */
1680 return (otf
1681 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1682 NULL, 0) > 0
1683 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1684 NULL, 0) > 0));
1686 for (i = 0; i < 2; i++)
1687 if (! FEATURE_ANY (i))
1689 if (FEATURE_NONE (i))
1691 if (otf
1692 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1693 NULL, 0) > 0)
1694 return 0;
1695 continue;
1697 if (spec->features[i][0] == 0xFFFFFFFF)
1699 if (! otf
1700 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1701 NULL, 0) <= 0)
1702 continue;
1704 else if (! otf)
1705 return 0;
1706 for (n = 1; spec->features[i][n]; n++);
1707 tags = alloca (sizeof (OTF_Tag) * n);
1708 for (n = 0, negative = 0; spec->features[i][n]; n++)
1710 if (spec->features[i][n] == 0xFFFFFFFF)
1711 negative = 1;
1712 else if (negative)
1713 tags[n - 1] = spec->features[i][n] | 0x80000000;
1714 else
1715 tags[n] = spec->features[i][n];
1717 #ifdef M17N_FLT_USE_NEW_FEATURE
1718 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1719 tags, n - negative) != 1)
1720 return 0;
1721 #else /* not M17N_FLT_USE_NEW_FEATURE */
1722 if (n - negative > 0
1723 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1724 tags, n - negative) != 1)
1725 return 0;
1726 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1728 return 1;
1729 #undef FEATURE_NONE
1730 #undef FEATURE_ANY
1733 #define DEVICE_DELTA(table, size) \
1734 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1735 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1736 : 0)
1738 static void
1739 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1740 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1742 if (anchor->AnchorFormat == 2)
1744 FT_Outline *outline;
1745 int ap = anchor->f.f1.AnchorPoint;
1747 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1748 outline = &ft_face->glyph->outline;
1749 if (ap < outline->n_points)
1751 *x = outline->points[ap].x << 6;
1752 *y = outline->points[ap].y << 6;
1755 else if (anchor->AnchorFormat == 3)
1757 if (anchor->f.f2.XDeviceTable.offset
1758 && anchor->f.f2.XDeviceTable.DeltaValue)
1759 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1760 if (anchor->f.f2.YDeviceTable.offset
1761 && anchor->f.f2.YDeviceTable.DeltaValue)
1762 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1766 static OTF_GlyphString otf_gstring;
1768 static void
1769 setup_otf_gstring (int size)
1771 if (otf_gstring.size < size)
1773 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1774 size, sizeof (OTF_Glyph));
1775 otf_gstring.size = size;
1777 otf_gstring.used = size;
1778 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1781 #ifdef M17N_FLT_USE_NEW_FEATURE
1783 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1784 #define PACK_OTF_TAG(TAG) \
1785 ((((TAG) & 0x7F000000) >> 3) \
1786 | (((TAG) & 0x7F0000) >> 2) \
1787 | (((TAG) & 0x7F00) >> 1) \
1788 | ((TAG) & 0x7F))
1790 /* Assuming that FONT is an OpenType font, apply OpenType features
1791 specified in SPEC on glyphs between FROM and TO of IN, and record
1792 the lastly applied feature in each glyph of IN. If OUT is not
1793 NULL, append the resulting glyphs to OUT while storing glyph
1794 position adjustment information in ADJUSTMENT. */
1796 static int
1797 ftfont_drive_otf (MFLTFont *font,
1798 MFLTOtfSpec *spec,
1799 MFLTGlyphString *in,
1800 int from,
1801 int to,
1802 MFLTGlyphString *out,
1803 MFLTGlyphAdjustment *adjustment)
1805 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1806 FT_Face ft_face = flt_font_ft->ft_face;
1807 OTF *otf = flt_font_ft->otf;
1808 int len = to - from;
1809 int i, j, gidx;
1810 OTF_Glyph *otfg;
1811 char script[5], *langsys = NULL;
1812 char *gsub_features = NULL, *gpos_features = NULL;
1813 OTF_Feature *features;
1815 if (len == 0)
1816 return from;
1817 OTF_tag_name (spec->script, script);
1818 if (spec->langsys)
1820 langsys = alloca (5);
1821 OTF_tag_name (spec->langsys, langsys);
1823 for (i = 0; i < 2; i++)
1825 char *p;
1827 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1829 for (j = 0; spec->features[i][j]; j++);
1830 if (i == 0)
1831 p = gsub_features = alloca (6 * j);
1832 else
1833 p = gpos_features = alloca (6 * j);
1834 for (j = 0; spec->features[i][j]; j++)
1836 if (spec->features[i][j] == 0xFFFFFFFF)
1837 *p++ = '*', *p++ = ',';
1838 else
1840 OTF_tag_name (spec->features[i][j], p);
1841 p[4] = ',';
1842 p += 5;
1845 *--p = '\0';
1849 setup_otf_gstring (len);
1850 for (i = 0; i < len; i++)
1852 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
1853 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1856 OTF_drive_gdef (otf, &otf_gstring);
1857 gidx = out ? out->used : from;
1859 if (gsub_features && out)
1861 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1862 gsub_features) < 0)
1863 goto simple_copy;
1864 if (out->allocated < out->used + otf_gstring.used)
1865 return -2;
1866 features = otf->gsub->FeatureList.Feature;
1867 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1869 MFLTGlyph *g;
1870 int min_from, max_to;
1871 int feature_idx = otfg->positioning_type >> 4;
1873 g = out->glyphs + out->used;
1874 *g = in->glyphs[from + otfg->f.index.from];
1875 if (g->code != otfg->glyph_id)
1877 g->c = 0;
1878 g->code = otfg->glyph_id;
1879 g->measured = 0;
1881 out->used++;
1882 min_from = g->from;
1883 max_to = g->to;
1884 if (otfg->f.index.from < otfg->f.index.to)
1886 /* OTFG substitutes multiple glyphs in IN. */
1887 for (j = from + otfg->f.index.from + 1;
1888 j <= from + otfg->f.index.to; j++)
1890 if (min_from > in->glyphs[j].from)
1891 min_from = in->glyphs[j].from;
1892 if (max_to < in->glyphs[j].to)
1893 max_to = in->glyphs[j].to;
1895 g->from = min_from;
1896 g->to = max_to;
1898 if (feature_idx)
1900 unsigned int tag = features[feature_idx - 1].FeatureTag;
1901 tag = PACK_OTF_TAG (tag);
1902 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1904 for (i++, otfg++; (i < otf_gstring.used
1905 && otfg->f.index.from == otfg[-1].f.index.from);
1906 i++, otfg++)
1908 g = out->glyphs + out->used;
1909 *g = in->glyphs[from + otfg->f.index.to];
1910 if (g->code != otfg->glyph_id)
1912 g->c = 0;
1913 g->code = otfg->glyph_id;
1914 g->measured = 0;
1916 feature_idx = otfg->positioning_type >> 4;
1917 if (feature_idx)
1919 unsigned int tag = features[feature_idx - 1].FeatureTag;
1920 tag = PACK_OTF_TAG (tag);
1921 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1923 out->used++;
1927 else if (gsub_features)
1929 /* Just for checking which features will be applied. */
1930 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1931 gsub_features) < 0)
1932 goto simple_copy;
1933 features = otf->gsub->FeatureList.Feature;
1934 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1935 otfg++)
1937 int feature_idx = otfg->positioning_type >> 4;
1939 if (feature_idx)
1941 unsigned int tag = features[feature_idx - 1].FeatureTag;
1942 tag = PACK_OTF_TAG (tag);
1943 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1945 MFLTGlyph *g = in->glyphs + (from + j);
1946 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1951 else if (out)
1953 if (out->allocated < out->used + len)
1954 return -2;
1955 for (i = 0; i < len; i++)
1956 out->glyphs[out->used++] = in->glyphs[from + i];
1959 if (gpos_features && out)
1961 MFLTGlyph *base = NULL, *mark = NULL, *g;
1962 int x_ppem, y_ppem, x_scale, y_scale;
1964 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1965 gpos_features) < 0)
1966 return to;
1967 features = otf->gpos->FeatureList.Feature;
1968 x_ppem = ft_face->size->metrics.x_ppem;
1969 y_ppem = ft_face->size->metrics.y_ppem;
1970 x_scale = ft_face->size->metrics.x_scale;
1971 y_scale = ft_face->size->metrics.y_scale;
1973 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1974 i < otf_gstring.used; i++, otfg++, g++)
1976 MFLTGlyph *prev;
1977 int feature_idx = otfg->positioning_type >> 4;
1979 if (feature_idx)
1981 unsigned int tag = features[feature_idx - 1].FeatureTag;
1982 tag = PACK_OTF_TAG (tag);
1983 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1986 if (! otfg->glyph_id)
1987 continue;
1988 switch (otfg->positioning_type & 0xF)
1990 case 0:
1991 break;
1992 case 1: /* Single */
1993 case 2: /* Pair */
1995 int format = otfg->f.f1.format;
1997 if (format & OTF_XPlacement)
1998 adjustment[i].xoff
1999 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2000 if (format & OTF_XPlaDevice)
2001 adjustment[i].xoff
2002 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2003 if (format & OTF_YPlacement)
2004 adjustment[i].yoff
2005 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2006 if (format & OTF_YPlaDevice)
2007 adjustment[i].yoff
2008 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2009 if (format & OTF_XAdvance)
2010 adjustment[i].xadv
2011 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2012 if (format & OTF_XAdvDevice)
2013 adjustment[i].xadv
2014 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2015 if (format & OTF_YAdvance)
2016 adjustment[i].yadv
2017 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2018 if (format & OTF_YAdvDevice)
2019 adjustment[i].yadv
2020 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2021 adjustment[i].set = 1;
2023 break;
2024 case 3: /* Cursive */
2025 /* Not yet supported. */
2026 break;
2027 case 4: /* Mark-to-Base */
2028 case 5: /* Mark-to-Ligature */
2029 if (! base)
2030 break;
2031 prev = base;
2032 goto label_adjust_anchor;
2033 default: /* i.e. case 6 Mark-to-Mark */
2034 if (! mark)
2035 break;
2036 prev = mark;
2038 label_adjust_anchor:
2040 int base_x, base_y, mark_x, mark_y;
2041 int this_from, this_to;
2043 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2044 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2045 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2046 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2048 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2049 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2050 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2051 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2052 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2053 x_ppem, y_ppem, &mark_x, &mark_y);
2054 adjustment[i].xoff = (base_x - mark_x);
2055 adjustment[i].yoff = - (base_y - mark_y);
2056 adjustment[i].back = (g - prev);
2057 adjustment[i].xadv = 0;
2058 adjustment[i].advance_is_absolute = 1;
2059 adjustment[i].set = 1;
2060 this_from = g->from;
2061 this_to = g->to;
2062 for (j = 0; prev + j < g; j++)
2064 if (this_from > prev[j].from)
2065 this_from = prev[j].from;
2066 if (this_to < prev[j].to)
2067 this_to = prev[j].to;
2069 for (; prev <= g; prev++)
2071 prev->from = this_from;
2072 prev->to = this_to;
2076 if (otfg->GlyphClass == OTF_GlyphClass0)
2077 base = mark = g;
2078 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2079 mark = g;
2080 else
2081 base = g;
2084 else if (gpos_features)
2086 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2087 gpos_features) < 0)
2088 return to;
2089 features = otf->gpos->FeatureList.Feature;
2090 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2091 i++, otfg++)
2092 if (otfg->positioning_type & 0xF)
2094 int feature_idx = otfg->positioning_type >> 4;
2096 if (feature_idx)
2098 unsigned int tag = features[feature_idx - 1].FeatureTag;
2099 tag = PACK_OTF_TAG (tag);
2100 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2102 MFLTGlyph *g = in->glyphs + (from + j);
2103 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2108 return to;
2110 simple_copy:
2111 if (! out)
2112 return to;
2113 if (out->allocated < out->used + len)
2114 return -2;
2115 font->get_metrics (font, in, from, to);
2116 memcpy (out->glyphs + out->used, in->glyphs + from,
2117 sizeof (MFLTGlyph) * len);
2118 out->used += len;
2119 return to;
2122 static int
2123 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2124 MFLTGlyphString *in, int from, int to)
2126 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2129 #else /* not M17N_FLT_USE_NEW_FEATURE */
2131 static int
2132 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2133 int from, int to,
2134 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2136 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2137 FT_Face ft_face = flt_font_ft->ft_face;
2138 OTF *otf = flt_font_ft->otf;
2139 int len = to - from;
2140 int i, j, gidx;
2141 OTF_Glyph *otfg;
2142 char script[5], *langsys = NULL;
2143 char *gsub_features = NULL, *gpos_features = NULL;
2145 if (len == 0)
2146 return from;
2147 OTF_tag_name (spec->script, script);
2148 if (spec->langsys)
2150 langsys = alloca (5);
2151 OTF_tag_name (spec->langsys, langsys);
2153 for (i = 0; i < 2; i++)
2155 char *p;
2157 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2159 for (j = 0; spec->features[i][j]; j++);
2160 if (i == 0)
2161 p = gsub_features = alloca (6 * j);
2162 else
2163 p = gpos_features = alloca (6 * j);
2164 for (j = 0; spec->features[i][j]; j++)
2166 if (spec->features[i][j] == 0xFFFFFFFF)
2167 *p++ = '*', *p++ = ',';
2168 else
2170 OTF_tag_name (spec->features[i][j], p);
2171 p[4] = ',';
2172 p += 5;
2175 *--p = '\0';
2179 setup_otf_gstring (len);
2180 for (i = 0; i < len; i++)
2182 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2183 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2186 OTF_drive_gdef (otf, &otf_gstring);
2187 gidx = out->used;
2189 if (gsub_features)
2191 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2192 < 0)
2193 goto simple_copy;
2194 if (out->allocated < out->used + otf_gstring.used)
2195 return -2;
2196 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2198 MFLTGlyph *g;
2199 int min_from, max_to;
2200 int j;
2202 g = out->glyphs + out->used;
2203 *g = in->glyphs[from + otfg->f.index.from];
2204 if (g->code != otfg->glyph_id)
2206 g->c = 0;
2207 g->code = otfg->glyph_id;
2208 g->measured = 0;
2210 out->used++;
2211 min_from = g->from;
2212 max_to = g->to;
2213 if (otfg->f.index.from < otfg->f.index.to)
2215 /* OTFG substitutes multiple glyphs in IN. */
2216 for (j = from + otfg->f.index.from + 1;
2217 j <= from + otfg->f.index.to; j++)
2219 if (min_from > in->glyphs[j].from)
2220 min_from = in->glyphs[j].from;
2221 if (max_to < in->glyphs[j].to)
2222 max_to = in->glyphs[j].to;
2224 g->from = min_from;
2225 g->to = max_to;
2227 for (i++, otfg++; (i < otf_gstring.used
2228 && otfg->f.index.from == otfg[-1].f.index.from);
2229 i++, otfg++)
2231 g = out->glyphs + out->used;
2232 *g = in->glyphs[from + otfg->f.index.to];
2233 if (g->code != otfg->glyph_id)
2235 g->c = 0;
2236 g->code = otfg->glyph_id;
2237 g->measured = 0;
2239 out->used++;
2243 else
2245 if (out->allocated < out->used + len)
2246 return -2;
2247 for (i = 0; i < len; i++)
2248 out->glyphs[out->used++] = in->glyphs[from + i];
2251 if (gpos_features)
2253 MFLTGlyph *base = NULL, *mark = NULL, *g;
2254 int x_ppem, y_ppem, x_scale, y_scale;
2256 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2257 < 0)
2258 return to;
2260 x_ppem = ft_face->size->metrics.x_ppem;
2261 y_ppem = ft_face->size->metrics.y_ppem;
2262 x_scale = ft_face->size->metrics.x_scale;
2263 y_scale = ft_face->size->metrics.y_scale;
2265 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2266 i < otf_gstring.used; i++, otfg++, g++)
2268 MFLTGlyph *prev;
2270 if (! otfg->glyph_id)
2271 continue;
2272 switch (otfg->positioning_type)
2274 case 0:
2275 break;
2276 case 1: /* Single */
2277 case 2: /* Pair */
2279 int format = otfg->f.f1.format;
2281 if (format & OTF_XPlacement)
2282 adjustment[i].xoff
2283 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2284 if (format & OTF_XPlaDevice)
2285 adjustment[i].xoff
2286 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2287 if (format & OTF_YPlacement)
2288 adjustment[i].yoff
2289 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2290 if (format & OTF_YPlaDevice)
2291 adjustment[i].yoff
2292 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2293 if (format & OTF_XAdvance)
2294 adjustment[i].xadv
2295 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2296 if (format & OTF_XAdvDevice)
2297 adjustment[i].xadv
2298 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2299 if (format & OTF_YAdvance)
2300 adjustment[i].yadv
2301 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2302 if (format & OTF_YAdvDevice)
2303 adjustment[i].yadv
2304 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2305 adjustment[i].set = 1;
2307 break;
2308 case 3: /* Cursive */
2309 /* Not yet supported. */
2310 break;
2311 case 4: /* Mark-to-Base */
2312 case 5: /* Mark-to-Ligature */
2313 if (! base)
2314 break;
2315 prev = base;
2316 goto label_adjust_anchor;
2317 default: /* i.e. case 6 Mark-to-Mark */
2318 if (! mark)
2319 break;
2320 prev = mark;
2322 label_adjust_anchor:
2324 int base_x, base_y, mark_x, mark_y;
2325 int this_from, this_to;
2327 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2328 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2329 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2330 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2332 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2333 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2334 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2335 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2336 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2337 x_ppem, y_ppem, &mark_x, &mark_y);
2338 adjustment[i].xoff = (base_x - mark_x);
2339 adjustment[i].yoff = - (base_y - mark_y);
2340 adjustment[i].back = (g - prev);
2341 adjustment[i].xadv = 0;
2342 adjustment[i].advance_is_absolute = 1;
2343 adjustment[i].set = 1;
2344 this_from = g->from;
2345 this_to = g->to;
2346 for (j = 0; prev + j < g; j++)
2348 if (this_from > prev[j].from)
2349 this_from = prev[j].from;
2350 if (this_to < prev[j].to)
2351 this_to = prev[j].to;
2353 for (; prev <= g; prev++)
2355 prev->from = this_from;
2356 prev->to = this_to;
2360 if (otfg->GlyphClass == OTF_GlyphClass0)
2361 base = mark = g;
2362 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2363 mark = g;
2364 else
2365 base = g;
2368 return to;
2370 simple_copy:
2371 if (out->allocated < out->used + len)
2372 return -2;
2373 font->get_metrics (font, in, from, to);
2374 memcpy (out->glyphs + out->used, in->glyphs + from,
2375 sizeof (MFLTGlyph) * len);
2376 out->used += len;
2377 return to;
2380 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2382 static MFLTGlyphString gstring;
2384 static int m17n_flt_initialized;
2386 static Lisp_Object
2387 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2388 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2390 EMACS_INT len = LGSTRING_GLYPH_LEN (lgstring);
2391 EMACS_INT i;
2392 struct MFLTFontFT flt_font_ft;
2393 MFLT *flt = NULL;
2394 int with_variation_selector = 0;
2396 if (! m17n_flt_initialized)
2398 M17N_INIT ();
2399 #ifdef M17N_FLT_USE_NEW_FEATURE
2400 mflt_enable_new_feature = 1;
2401 mflt_try_otf = ftfont_try_otf;
2402 #endif /* M17N_FLT_USE_NEW_FEATURE */
2403 m17n_flt_initialized = 1;
2406 for (i = 0; i < len; i++)
2408 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2409 int c;
2411 if (NILP (g))
2412 break;
2413 c = LGLYPH_CHAR (g);
2414 if (CHAR_VARIATION_SELECTOR_P (c))
2415 with_variation_selector++;
2418 len = i;
2419 lint_assume (len <= TYPE_MAXIMUM (EMACS_INT) - 2);
2421 if (with_variation_selector)
2423 setup_otf_gstring (len);
2424 for (i = 0; i < len; i++)
2426 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2428 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2429 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2430 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2432 OTF_drive_cmap (otf, &otf_gstring);
2433 for (i = 0; i < otf_gstring.used; i++)
2435 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2436 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2437 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2439 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2440 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2441 LGSTRING_SET_GLYPH (lgstring, i, g0);
2443 if (len > otf_gstring.used)
2445 len = otf_gstring.used;
2446 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2450 if (INT_MAX / 2 < len)
2451 memory_full (SIZE_MAX);
2453 if (gstring.allocated == 0)
2455 gstring.glyph_size = sizeof (MFLTGlyph);
2456 gstring.glyphs = xnmalloc (len * 2, sizeof (MFLTGlyph));
2457 gstring.allocated = len * 2;
2459 else if (gstring.allocated < len * 2)
2461 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2, sizeof (MFLTGlyph));
2462 gstring.allocated = len * 2;
2464 memset (gstring.glyphs, 0, sizeof (MFLTGlyph) * len);
2465 for (i = 0; i < len; i++)
2467 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2469 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2470 if (with_variation_selector)
2472 gstring.glyphs[i].code = LGLYPH_CODE (g);
2473 gstring.glyphs[i].encoded = 1;
2477 gstring.used = len;
2478 gstring.r2l = 0;
2481 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2483 if (NILP (family))
2484 flt_font_ft.flt_font.family = Mnil;
2485 else
2486 flt_font_ft.flt_font.family
2487 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2489 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2490 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2491 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2492 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2493 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2494 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2495 flt_font_ft.flt_font.internal = NULL;
2496 flt_font_ft.font = font;
2497 flt_font_ft.ft_face = ft_face;
2498 flt_font_ft.otf = otf;
2499 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2500 if (len > 1
2501 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2502 /* A little bit ad hoc. Perhaps, shaper must get script and
2503 language information, and select a proper flt for them
2504 here. */
2505 flt = mflt_get (msymbol ("combining"));
2506 for (i = 0; i < 3; i++)
2508 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2509 if (result != -2)
2510 break;
2511 if (INT_MAX / 2 < gstring.allocated)
2512 memory_full (SIZE_MAX);
2513 gstring.glyphs = xnrealloc (gstring.glyphs,
2514 gstring.allocated, 2 * sizeof (MFLTGlyph));
2515 gstring.allocated *= 2;
2517 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2518 return Qnil;
2519 for (i = 0; i < gstring.used; i++)
2521 MFLTGlyph *g = gstring.glyphs + i;
2523 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2524 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2527 for (i = 0; i < gstring.used; i++)
2529 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2530 MFLTGlyph *g = gstring.glyphs + i;
2532 if (NILP (lglyph))
2534 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2535 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2537 LGLYPH_SET_FROM (lglyph, g->from);
2538 LGLYPH_SET_TO (lglyph, g->to);
2539 LGLYPH_SET_CHAR (lglyph, g->c);
2540 LGLYPH_SET_CODE (lglyph, g->code);
2541 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2542 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2543 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2544 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2545 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2546 if (g->adjusted)
2548 Lisp_Object vec;
2550 vec = Fmake_vector (make_number (3), Qnil);
2551 ASET (vec, 0, make_number (g->xoff >> 6));
2552 ASET (vec, 1, make_number (g->yoff >> 6));
2553 ASET (vec, 2, make_number (g->xadv >> 6));
2554 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2557 return make_number (i);
2560 Lisp_Object
2561 ftfont_shape (Lisp_Object lgstring)
2563 struct font *font;
2564 struct ftfont_info *ftfont_info;
2565 OTF *otf;
2567 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2568 ftfont_info = (struct ftfont_info *) font;
2569 otf = ftfont_get_otf (ftfont_info);
2570 if (! otf)
2571 return make_number (0);
2572 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2573 &ftfont_info->matrix);
2576 #endif /* HAVE_M17N_FLT */
2578 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2580 static int
2581 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2583 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2584 OTF *otf = ftfont_get_otf (ftfont_info);
2586 if (! otf)
2587 return 0;
2588 return OTF_get_variation_glyphs (otf, c, variations);
2591 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2592 #endif /* HAVE_LIBOTF */
2594 Lisp_Object
2595 ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
2597 FcChar8 *str;
2599 #ifdef FC_FONTFORMAT
2600 if (pattern)
2602 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2603 return Qnil;
2604 if (strcmp ((char *) str, "TrueType") == 0)
2605 return intern ("truetype");
2606 if (strcmp ((char *) str, "Type 1") == 0)
2607 return intern ("type1");
2608 if (strcmp ((char *) str, "PCF") == 0)
2609 return intern ("pcf");
2610 if (strcmp ((char *) str, "BDF") == 0)
2611 return intern ("bdf");
2613 #endif /* FC_FONTFORMAT */
2614 if (STRINGP (filename))
2616 int len = SBYTES (filename);
2618 if (len >= 4)
2620 str = (FcChar8 *) (SDATA (filename) + len - 4);
2621 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2622 return intern ("truetype");
2623 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2624 return intern ("type1");
2625 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2626 return intern ("pcf");
2627 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2628 return intern ("bdf");
2631 return intern ("unknown");
2634 static const char *const ftfont_booleans [] = {
2635 ":antialias",
2636 ":hinting",
2637 ":verticallayout",
2638 ":autohint",
2639 ":globaladvance",
2640 ":outline",
2641 ":scalable",
2642 ":minspace",
2643 ":embolden",
2644 NULL,
2647 static const char *const ftfont_non_booleans [] = {
2648 ":family",
2649 ":familylang",
2650 ":style",
2651 ":stylelang",
2652 ":fullname",
2653 ":fullnamelang",
2654 ":slant",
2655 ":weight",
2656 ":size",
2657 ":width",
2658 ":aspect",
2659 ":pixelsize",
2660 ":spacing",
2661 ":foundry",
2662 ":hintstyle",
2663 ":file",
2664 ":index",
2665 ":ftface",
2666 ":rasterizer",
2667 ":scale",
2668 ":dpi",
2669 ":rgba",
2670 ":lcdfilter",
2671 ":charset",
2672 ":lang",
2673 ":fontversion",
2674 ":capability",
2675 NULL,
2678 static void
2679 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2681 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2685 void
2686 syms_of_ftfont (void)
2688 DEFSYM (Qfreetype, "freetype");
2689 DEFSYM (Qmonospace, "monospace");
2690 DEFSYM (Qsans_serif, "sans-serif");
2691 DEFSYM (Qserif, "serif");
2692 DEFSYM (Qmono, "mono");
2693 DEFSYM (Qsans, "sans");
2694 DEFSYM (Qsans__serif, "sans serif");
2696 staticpro (&freetype_font_cache);
2697 freetype_font_cache = Fcons (Qt, Qnil);
2699 staticpro (&ftfont_generic_family_list);
2700 ftfont_generic_family_list
2701 = Fcons (Fcons (Qmonospace, Qt),
2702 Fcons (Fcons (Qsans_serif, Qt),
2703 Fcons (Fcons (Qsans, Qt), Qnil)));
2705 staticpro (&ft_face_cache);
2706 ft_face_cache = Qnil;
2708 ftfont_driver.type = Qfreetype;
2709 register_font_driver (&ftfont_driver, NULL);