Backport the :end-of-capability fix
[emacs.git] / src / ftfont.c
blob20482be818948506f87425381eeba3cd7aa9b80c
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2015 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 <fontconfig/fontconfig.h>
25 #include <fontconfig/fcfreetype.h>
27 #include "lisp.h"
28 #include "dispextern.h"
29 #include "frame.h"
30 #include "blockinput.h"
31 #include "character.h"
32 #include "charset.h"
33 #include "coding.h"
34 #include "composite.h"
35 #include "fontset.h"
36 #include "font.h"
37 #include "ftfont.h"
39 /* Symbolic type of this font-driver. */
40 static Lisp_Object Qfreetype;
42 /* Fontconfig's generic families and their aliases. */
43 static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
45 /* Flag to tell if FcInit is already called or not. */
46 static bool fc_initialized;
48 /* Handle to a FreeType library instance. */
49 static FT_Library ft_library;
51 /* Cache for FreeType fonts. */
52 static Lisp_Object freetype_font_cache;
54 /* Cache for FT_Face and FcCharSet. */
55 static Lisp_Object ft_face_cache;
57 /* The actual structure for FreeType font that can be cast to struct
58 font. */
60 struct ftfont_info
62 struct font font;
63 #ifdef HAVE_LIBOTF
64 /* The following four members must be here in this order to be
65 compatible with struct xftfont_info (in xftfont.c). */
66 bool maybe_otf; /* Flag to tell if this may be OTF or not. */
67 OTF *otf;
68 #endif /* HAVE_LIBOTF */
69 FT_Size ft_size;
70 int index;
71 FT_Matrix matrix;
74 enum ftfont_cache_for
76 FTFONT_CACHE_FOR_FACE,
77 FTFONT_CACHE_FOR_CHARSET,
78 FTFONT_CACHE_FOR_ENTITY
81 static Lisp_Object ftfont_pattern_entity (FcPattern *, Lisp_Object);
83 static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
84 FcPattern *);
85 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
86 enum ftfont_cache_for);
88 static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
90 Lisp_Object ftfont_font_format (FcPattern *, Lisp_Object);
92 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
94 static struct
96 /* registry name */
97 const char *name;
98 /* characters to distinguish the charset from the others */
99 int uniquifier[6];
100 /* additional constraint by language */
101 const char *lang;
102 /* set on demand */
103 FcCharSet *fc_charset;
104 } fc_charset_table[] =
105 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
106 { "iso8859-2", { 0x00A0, 0x010E }},
107 { "iso8859-3", { 0x00A0, 0x0108 }},
108 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
109 { "iso8859-5", { 0x00A0, 0x0401 }},
110 { "iso8859-6", { 0x00A0, 0x060C }},
111 { "iso8859-7", { 0x00A0, 0x0384 }},
112 { "iso8859-8", { 0x00A0, 0x05D0 }},
113 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
114 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
115 { "iso8859-11", { 0x00A0, 0x0E01 }},
116 { "iso8859-13", { 0x00A0, 0x201C }},
117 { "iso8859-14", { 0x00A0, 0x0174 }},
118 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
119 { "iso8859-16", { 0x00A0, 0x0218}},
120 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
121 { "big5-0", { 0xF6B1 }, "zh-tw" },
122 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
123 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
124 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
125 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
126 { "cns11643.1992-3", { 0x201A9 }},
127 { "cns11643.1992-4", { 0x20057 }},
128 { "cns11643.1992-5", { 0x20000 }},
129 { "cns11643.1992-6", { 0x20003 }},
130 { "cns11643.1992-7", { 0x20055 }},
131 { "gbk-0", { 0x4E06 }, "zh-cn"},
132 { "jisx0212.1990-0", { 0x4E44 }},
133 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
134 { "jisx0213.2000-2", { 0xFA49 }},
135 { "jisx0213.2004-1", { 0x20B9F }},
136 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
137 { "tis620.2529-1", { 0x0E01 }, "th"},
138 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
139 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
140 { "mulelao-1", { 0x0E81 }, "lo"},
141 { "unicode-sip", { 0x20000 }},
142 { NULL }
145 /* Dirty hack for handing ADSTYLE property.
147 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
148 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
149 "Oblique", "Italic", or any non-normal SWIDTH property names
150 (e.g. SemiCondensed) are appended. In addition, if there's no
151 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
152 "Regular" is used for FC_STYLE (see the function
153 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
155 Unfortunately this behavior is not documented, so the following
156 code may fail if FreeType changes the behavior in the future. */
158 static Lisp_Object
159 get_adstyle_property (FcPattern *p)
161 FcChar8 *fcstr;
162 char *str, *end;
163 Lisp_Object adstyle;
165 #ifdef FC_FONTFORMAT
166 if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
167 && xstrcasecmp ((char *) fcstr, "bdf") != 0
168 && xstrcasecmp ((char *) fcstr, "pcf") != 0)
169 /* Not a BDF nor PCF font. */
170 return Qnil;
171 #endif
172 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
173 return Qnil;
174 str = (char *) fcstr;
175 for (end = str; *end && *end != ' '; end++);
176 if (*end)
178 char *newstr = alloca (end - str + 1);
179 memcpy (newstr, str, end - str);
180 newstr[end - str] = '\0';
181 end = newstr + (end - str);
182 str = newstr;
184 if (xstrcasecmp (str, "Regular") == 0
185 || xstrcasecmp (str, "Bold") == 0
186 || xstrcasecmp (str, "Oblique") == 0
187 || xstrcasecmp (str, "Italic") == 0)
188 return Qnil;
189 adstyle = font_intern_prop (str, end - str, 1);
190 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
191 return Qnil;
192 return adstyle;
195 static Lisp_Object
196 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
198 Lisp_Object key, cache, entity;
199 FcChar8 *str;
200 char *file;
201 int idx;
202 int numeric;
203 double dbl;
204 FcBool b;
206 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
207 return Qnil;
208 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
209 return Qnil;
211 file = (char *) str;
212 key = Fcons (build_unibyte_string (file), make_number (idx));
213 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
214 entity = XCAR (cache);
215 if (! NILP (entity))
217 Lisp_Object val = font_make_entity ();
218 int i;
220 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
221 ASET (val, i, AREF (entity, i));
223 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
224 font_put_extra (val, QCfont_entity, key);
226 return val;
228 entity = font_make_entity ();
229 XSETCAR (cache, entity);
231 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
232 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
234 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
236 char *s = (char *) str;
237 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
239 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
241 char *s = (char *) str;
242 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
244 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
246 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
247 numeric = FC_WEIGHT_MEDIUM;
248 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
250 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
252 numeric += 100;
253 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
255 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
257 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
259 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
261 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
263 else
264 ASET (entity, FONT_SIZE_INDEX, make_number (0));
265 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
266 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
267 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
269 int dpi = dbl;
270 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
272 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
273 && b == FcTrue)
275 ASET (entity, FONT_SIZE_INDEX, make_number (0));
276 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
278 else
280 /* As this font is not scalable, perhaps this is a BDF or PCF
281 font. */
282 FT_Face ft_face;
284 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
285 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
286 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
288 BDF_PropertyRec rec;
290 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
291 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
292 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
293 FT_Done_Face (ft_face);
297 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
298 font_put_extra (entity, QCfont_entity, key);
299 return entity;
303 static Lisp_Object ftfont_generic_family_list;
305 static Lisp_Object
306 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
308 Lisp_Object slot;
309 FcPattern *match;
310 FcResult result;
311 FcLangSet *langset;
313 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
314 if (EQ (family, Qmono))
315 family = Qmonospace;
316 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
317 family = Qsans_serif;
318 slot = assq_no_quit (family, ftfont_generic_family_list);
319 if (! CONSP (slot))
320 return Qnil;
321 if (! EQ (XCDR (slot), Qt))
322 return XCDR (slot);
323 pattern = FcPatternDuplicate (pattern);
324 if (! pattern)
325 goto err;
326 FcPatternDel (pattern, FC_FOUNDRY);
327 FcPatternDel (pattern, FC_FAMILY);
328 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
329 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
331 /* This is to avoid the effect of locale. */
332 static const FcChar8 lang[] = "en";
333 langset = FcLangSetCreate ();
334 FcLangSetAdd (langset, lang);
335 FcPatternAddLangSet (pattern, FC_LANG, langset);
336 FcLangSetDestroy (langset);
338 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
339 FcDefaultSubstitute (pattern);
340 match = FcFontMatch (NULL, pattern, &result);
341 if (match)
343 FcChar8 *fam;
345 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
346 family = intern ((char *) fam);
348 else
349 family = Qnil;
350 XSETCDR (slot, family);
351 if (match) FcPatternDestroy (match);
352 err:
353 if (pattern) FcPatternDestroy (pattern);
354 return family;
357 struct ftfont_cache_data
359 FT_Face ft_face;
360 FcCharSet *fc_charset;
363 static Lisp_Object
364 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
366 Lisp_Object cache, val, entity;
367 struct ftfont_cache_data *cache_data;
369 if (FONT_ENTITY_P (key))
371 entity = key;
372 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
373 eassert (CONSP (val));
374 key = XCDR (val);
376 else
377 entity = Qnil;
379 if (NILP (ft_face_cache))
380 cache = Qnil;
381 else
382 cache = Fgethash (key, ft_face_cache, Qnil);
383 if (NILP (cache))
385 if (NILP (ft_face_cache))
387 Lisp_Object args[2];
389 args[0] = QCtest;
390 args[1] = Qequal;
391 ft_face_cache = Fmake_hash_table (2, args);
393 cache_data = xmalloc (sizeof *cache_data);
394 cache_data->ft_face = NULL;
395 cache_data->fc_charset = NULL;
396 val = make_save_ptr_int (cache_data, 0);
397 cache = Fcons (Qnil, val);
398 Fputhash (key, cache, ft_face_cache);
400 else
402 val = XCDR (cache);
403 cache_data = XSAVE_POINTER (val, 0);
406 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
407 return cache;
409 if (cache_for == FTFONT_CACHE_FOR_FACE
410 ? ! cache_data->ft_face : ! cache_data->fc_charset)
412 char *filename = SSDATA (XCAR (key));
413 int idx = XINT (XCDR (key));
415 if (cache_for == FTFONT_CACHE_FOR_FACE)
417 if (! ft_library
418 && FT_Init_FreeType (&ft_library) != 0)
419 return Qnil;
420 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
421 != 0)
422 return Qnil;
424 else
426 FcPattern *pat = NULL;
427 FcFontSet *fontset = NULL;
428 FcObjectSet *objset = NULL;
429 FcCharSet *charset = NULL;
431 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
432 FC_INDEX, FcTypeInteger, idx, NULL);
433 if (! pat)
434 goto finish;
435 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
436 if (! objset)
437 goto finish;
438 fontset = FcFontList (NULL, pat, objset);
439 if (! fontset)
440 goto finish;
441 if (fontset && fontset->nfont > 0
442 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
443 &charset)
444 == FcResultMatch))
445 cache_data->fc_charset = FcCharSetCopy (charset);
446 else
447 cache_data->fc_charset = FcCharSetCreate ();
449 finish:
450 if (fontset)
451 FcFontSetDestroy (fontset);
452 if (objset)
453 FcObjectSetDestroy (objset);
454 if (pat)
455 FcPatternDestroy (pat);
458 return cache;
461 FcCharSet *
462 ftfont_get_fc_charset (Lisp_Object entity)
464 Lisp_Object val, cache;
465 struct ftfont_cache_data *cache_data;
467 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
468 val = XCDR (cache);
469 cache_data = XSAVE_POINTER (val, 0);
470 return cache_data->fc_charset;
473 #ifdef HAVE_LIBOTF
474 static OTF *
475 ftfont_get_otf (struct ftfont_info *ftfont_info)
477 OTF *otf;
479 if (ftfont_info->otf)
480 return ftfont_info->otf;
481 if (! ftfont_info->maybe_otf)
482 return NULL;
483 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
484 if (! otf || OTF_get_table (otf, "head") < 0)
486 if (otf)
487 OTF_close (otf);
488 ftfont_info->maybe_otf = 0;
489 return NULL;
491 ftfont_info->otf = otf;
492 return otf;
494 #endif /* HAVE_LIBOTF */
496 static Lisp_Object ftfont_get_cache (struct frame *);
497 static Lisp_Object ftfont_list (struct frame *, Lisp_Object);
498 static Lisp_Object ftfont_match (struct frame *, Lisp_Object);
499 static Lisp_Object ftfont_list_family (struct frame *);
500 static Lisp_Object ftfont_open (struct frame *, Lisp_Object, int);
501 static void ftfont_close (struct font *);
502 static int ftfont_has_char (Lisp_Object, int);
503 static unsigned ftfont_encode_char (struct font *, int);
504 static int ftfont_text_extents (struct font *, unsigned *, int,
505 struct font_metrics *);
506 static int ftfont_get_bitmap (struct font *, unsigned,
507 struct font_bitmap *, int);
508 static int ftfont_anchor_point (struct font *, unsigned, int,
509 int *, int *);
510 #ifdef HAVE_LIBOTF
511 static Lisp_Object ftfont_otf_capability (struct font *);
512 # ifdef HAVE_M17N_FLT
513 static Lisp_Object ftfont_shape (Lisp_Object);
514 # endif
515 #endif
517 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
518 static int ftfont_variation_glyphs (struct font *, int c,
519 unsigned variations[256]);
520 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
522 struct font_driver ftfont_driver =
524 LISP_INITIALLY_ZERO, /* Qfreetype */
525 0, /* case insensitive */
526 ftfont_get_cache,
527 ftfont_list,
528 ftfont_match,
529 ftfont_list_family,
530 NULL, /* free_entity */
531 ftfont_open,
532 ftfont_close,
533 /* We can't draw a text without device dependent functions. */
534 NULL, /* prepare_face */
535 NULL, /* done_face */
536 ftfont_has_char,
537 ftfont_encode_char,
538 ftfont_text_extents,
539 /* We can't draw a text without device dependent functions. */
540 NULL, /* draw */
541 ftfont_get_bitmap,
542 NULL, /* free_bitmap */
543 NULL, /* get_outline */
544 NULL, /* free_outline */
545 ftfont_anchor_point,
546 #ifdef HAVE_LIBOTF
547 ftfont_otf_capability,
548 #else /* not HAVE_LIBOTF */
549 NULL,
550 #endif /* not HAVE_LIBOTF */
551 NULL, /* otf_drive */
552 NULL, /* start_for_frame */
553 NULL, /* end_for_frame */
554 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
555 ftfont_shape,
556 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
557 NULL,
558 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
559 NULL, /* check */
561 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
562 ftfont_variation_glyphs,
563 #else
564 NULL,
565 #endif
567 ftfont_filter_properties, /* filter_properties */
570 static Lisp_Object
571 ftfont_get_cache (struct frame *f)
573 return freetype_font_cache;
576 static int
577 ftfont_get_charset (Lisp_Object registry)
579 char *str = SSDATA (SYMBOL_NAME (registry));
580 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
581 Lisp_Object regexp;
582 int i, j;
584 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
586 if (str[i] == '.')
587 re[j++] = '\\';
588 else if (str[i] == '*')
589 re[j++] = '.';
590 re[j] = str[i];
591 if (re[j] == '?')
592 re[j] = '.';
594 re[j] = '\0';
595 regexp = make_unibyte_string (re, j);
596 for (i = 0; fc_charset_table[i].name; i++)
597 if (fast_c_string_match_ignore_case
598 (regexp, fc_charset_table[i].name,
599 strlen (fc_charset_table[i].name)) >= 0)
600 break;
601 if (! fc_charset_table[i].name)
602 return -1;
603 if (! fc_charset_table[i].fc_charset)
605 FcCharSet *charset = FcCharSetCreate ();
606 int *uniquifier = fc_charset_table[i].uniquifier;
608 if (! charset)
609 return -1;
610 for (j = 0; uniquifier[j]; j++)
611 if (! FcCharSetAddChar (charset, uniquifier[j]))
613 FcCharSetDestroy (charset);
614 return -1;
616 fc_charset_table[i].fc_charset = charset;
618 return i;
621 struct OpenTypeSpec
623 Lisp_Object script;
624 unsigned int script_tag, langsys_tag;
625 int nfeatures[2];
626 unsigned int *features[2];
629 #define OTF_SYM_TAG(SYM, TAG) \
630 do { \
631 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
632 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
633 } while (0)
635 #define OTF_TAG_STR(TAG, P) \
636 do { \
637 (P)[0] = (char) (TAG >> 24); \
638 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
639 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
640 (P)[3] = (char) (TAG & 0xFF); \
641 (P)[4] = '\0'; \
642 } while (0)
644 #ifdef HAVE_LIBOTF
645 #define OTF_TAG_SYM(SYM, TAG) \
646 do { \
647 char str[5]; \
649 OTF_TAG_STR (TAG, str); \
650 (SYM) = font_intern_prop (str, 4, 1); \
651 } while (0)
652 #endif
655 static struct OpenTypeSpec *
656 ftfont_get_open_type_spec (Lisp_Object otf_spec)
658 struct OpenTypeSpec *spec = malloc (sizeof *spec);
659 Lisp_Object val;
660 int i, j;
661 bool negative;
663 if (! spec)
664 return NULL;
665 spec->script = XCAR (otf_spec);
666 if (! NILP (spec->script))
668 OTF_SYM_TAG (spec->script, spec->script_tag);
669 val = assq_no_quit (spec->script, Votf_script_alist);
670 if (CONSP (val) && SYMBOLP (XCDR (val)))
671 spec->script = XCDR (val);
672 else
673 spec->script = Qnil;
675 else
676 spec->script_tag = 0x44464C54; /* "DFLT" */
677 otf_spec = XCDR (otf_spec);
678 spec->langsys_tag = 0;
679 if (! NILP (otf_spec))
681 val = XCAR (otf_spec);
682 if (! NILP (val))
683 OTF_SYM_TAG (val, spec->langsys_tag);
684 otf_spec = XCDR (otf_spec);
686 spec->nfeatures[0] = spec->nfeatures[1] = 0;
687 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
689 Lisp_Object len;
691 val = XCAR (otf_spec);
692 if (NILP (val))
693 continue;
694 len = Flength (val);
695 spec->features[i] =
696 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
698 : malloc (XINT (len) * sizeof *spec->features[i]));
699 if (! spec->features[i])
701 if (i > 0 && spec->features[0])
702 free (spec->features[0]);
703 free (spec);
704 return NULL;
706 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
708 if (NILP (XCAR (val)))
709 negative = 1;
710 else
712 unsigned int tag;
714 OTF_SYM_TAG (XCAR (val), tag);
715 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
718 spec->nfeatures[i] = j;
720 return spec;
723 static FcPattern *
724 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
726 Lisp_Object tmp, extra;
727 FcPattern *pattern = NULL;
728 FcCharSet *charset = NULL;
729 FcLangSet *langset = NULL;
730 int n;
731 int dpi = -1;
732 int scalable = -1;
733 Lisp_Object script = Qnil;
734 Lisp_Object registry;
735 int fc_charset_idx;
737 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
738 && n < 100)
739 /* Fontconfig doesn't support reverse-italic/oblique. */
740 return NULL;
742 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
743 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
744 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
745 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
746 scalable = 1;
748 registry = AREF (spec, FONT_REGISTRY_INDEX);
749 if (NILP (registry)
750 || EQ (registry, Qascii_0)
751 || EQ (registry, Qiso10646_1)
752 || EQ (registry, Qunicode_bmp))
753 fc_charset_idx = -1;
754 else
756 FcChar8 *lang;
758 fc_charset_idx = ftfont_get_charset (registry);
759 if (fc_charset_idx < 0)
760 return NULL;
761 charset = fc_charset_table[fc_charset_idx].fc_charset;
762 *langname = fc_charset_table[fc_charset_idx].lang;
763 lang = (FcChar8 *) *langname;
764 if (lang)
766 langset = FcLangSetCreate ();
767 if (! langset)
768 goto err;
769 FcLangSetAdd (langset, lang);
773 otlayout[0] = '\0';
774 for (extra = AREF (spec, FONT_EXTRA_INDEX);
775 CONSP (extra); extra = XCDR (extra))
777 Lisp_Object key, val;
779 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
780 if (EQ (key, QCdpi))
782 if (INTEGERP (val))
783 dpi = XINT (val);
785 else if (EQ (key, QClang))
787 if (! langset)
788 langset = FcLangSetCreate ();
789 if (! langset)
790 goto err;
791 if (SYMBOLP (val))
793 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
794 goto err;
796 else
797 for (; CONSP (val); val = XCDR (val))
798 if (SYMBOLP (XCAR (val))
799 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
800 goto err;
802 else if (EQ (key, QCotf))
804 if (CONSP (val))
806 *otspec = ftfont_get_open_type_spec (val);
807 if (! *otspec)
808 return NULL;
809 strcat (otlayout, "otlayout:");
810 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
811 script = (*otspec)->script;
814 else if (EQ (key, QCscript))
815 script = val;
816 else if (EQ (key, QCscalable))
817 scalable = ! NILP (val);
820 if (! NILP (script) && ! charset)
822 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
824 if (CONSP (chars) && CONSP (CDR (chars)))
826 charset = FcCharSetCreate ();
827 if (! charset)
828 goto err;
829 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
830 if (CHARACTERP (XCAR (chars))
831 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
832 goto err;
836 pattern = FcPatternCreate ();
837 if (! pattern)
838 goto err;
839 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
840 if (! NILP (tmp)
841 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
842 goto err;
843 tmp = AREF (spec, FONT_FAMILY_INDEX);
844 if (! NILP (tmp)
845 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
846 goto err;
847 if (charset
848 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
849 goto err;
850 if (langset
851 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
852 goto err;
853 if (dpi >= 0
854 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
855 goto err;
856 if (scalable >= 0
857 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
858 goto err;
860 goto finish;
862 err:
863 /* We come here because of unexpected error in fontconfig API call
864 (usually insufficient memory). */
865 if (pattern)
867 FcPatternDestroy (pattern);
868 pattern = NULL;
870 if (*otspec)
872 if ((*otspec)->nfeatures[0] > 0)
873 free ((*otspec)->features[0]);
874 if ((*otspec)->nfeatures[1] > 0)
875 free ((*otspec)->features[1]);
876 free (*otspec);
877 *otspec = NULL;
880 finish:
881 if (langset) FcLangSetDestroy (langset);
882 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
883 return pattern;
886 static Lisp_Object
887 ftfont_list (struct frame *f, Lisp_Object spec)
889 Lisp_Object val = Qnil, family, adstyle;
890 int i;
891 FcPattern *pattern;
892 FcFontSet *fontset = NULL;
893 FcObjectSet *objset = NULL;
894 FcCharSet *charset;
895 Lisp_Object chars = Qnil;
896 char otlayout[15]; /* For "otlayout:XXXX" */
897 struct OpenTypeSpec *otspec = NULL;
898 int spacing = -1;
899 const char *langname = NULL;
901 if (! fc_initialized)
903 FcInit ();
904 fc_initialized = 1;
907 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
908 if (! pattern)
909 return Qnil;
910 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
912 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
913 if (! NILP (val))
915 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
916 if (CONSP (val) && VECTORP (XCDR (val)))
917 chars = XCDR (val);
919 val = Qnil;
921 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
922 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
923 family = AREF (spec, FONT_FAMILY_INDEX);
924 if (! NILP (family))
926 Lisp_Object resolved;
928 resolved = ftfont_resolve_generic_family (family, pattern);
929 if (! NILP (resolved))
931 FcPatternDel (pattern, FC_FAMILY);
932 if (! FcPatternAddString (pattern, FC_FAMILY,
933 SYMBOL_FcChar8 (resolved)))
934 goto err;
937 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
938 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
939 adstyle = Qnil;
940 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
941 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
942 FC_STYLE, FC_FILE, FC_INDEX,
943 #ifdef FC_CAPABILITY
944 FC_CAPABILITY,
945 #endif /* FC_CAPABILITY */
946 #ifdef FC_FONTFORMAT
947 FC_FONTFORMAT,
948 #endif
949 NULL);
950 if (! objset)
951 goto err;
952 if (! NILP (chars))
953 FcObjectSetAdd (objset, FC_CHARSET);
955 fontset = FcFontList (NULL, pattern, objset);
956 if (! fontset || fontset->nfont == 0)
957 goto finish;
958 #if 0
959 /* Need fix because this finds any fonts. */
960 if (fontset->nfont == 0 && ! NILP (family))
962 /* Try matching with configuration. For instance, the
963 configuration may specify "Nimbus Mono L" as an alias of
964 "Courier". */
965 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
966 SYMBOL_FcChar8 (family), NULL);
967 FcChar8 *fam;
969 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
971 for (i = 0;
972 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
973 i++)
975 FcPatternDel (pattern, FC_FAMILY);
976 FcPatternAddString (pattern, FC_FAMILY, fam);
977 FcFontSetDestroy (fontset);
978 fontset = FcFontList (NULL, pattern, objset);
979 if (fontset && fontset->nfont > 0)
980 break;
984 #endif
985 for (i = 0; i < fontset->nfont; i++)
987 Lisp_Object entity;
989 if (spacing >= 0)
991 int this;
993 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
994 == FcResultMatch)
995 && spacing != this)
996 continue;
999 #ifdef FC_CAPABILITY
1000 if (otlayout[0])
1002 FcChar8 *this;
1004 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
1005 != FcResultMatch
1006 || ! strstr ((char *) this, otlayout))
1007 continue;
1009 #endif /* FC_CAPABILITY */
1010 #ifdef HAVE_LIBOTF
1011 if (otspec)
1013 FcChar8 *file;
1014 bool passed;
1015 OTF *otf;
1017 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1018 != FcResultMatch)
1019 continue;
1020 otf = OTF_open ((char *) file);
1021 if (! otf)
1022 continue;
1023 passed = (OTF_check_features (otf, 1, otspec->script_tag,
1024 otspec->langsys_tag,
1025 otspec->features[0],
1026 otspec->nfeatures[0]) == 1
1027 && OTF_check_features (otf, 0, otspec->script_tag,
1028 otspec->langsys_tag,
1029 otspec->features[1],
1030 otspec->nfeatures[1]) == 1);
1031 OTF_close (otf);
1032 if (!passed)
1033 continue;
1035 #endif /* HAVE_LIBOTF */
1036 if (VECTORP (chars))
1038 ptrdiff_t j;
1040 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1041 != FcResultMatch)
1042 continue;
1043 for (j = 0; j < ASIZE (chars); j++)
1044 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1045 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1046 break;
1047 if (j == ASIZE (chars))
1048 continue;
1050 if (! NILP (adstyle) || langname)
1052 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1054 if (! NILP (adstyle)
1055 && (NILP (this_adstyle)
1056 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1057 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1058 continue;
1059 if (langname
1060 && ! NILP (this_adstyle)
1061 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1062 continue;
1064 entity = ftfont_pattern_entity (fontset->fonts[i],
1065 AREF (spec, FONT_EXTRA_INDEX));
1066 if (! NILP (entity))
1067 val = Fcons (entity, val);
1069 val = Fnreverse (val);
1070 goto finish;
1072 err:
1073 /* We come here because of unexpected error in fontconfig API call
1074 (usually insufficient memory). */
1075 val = Qnil;
1077 finish:
1078 FONT_ADD_LOG ("ftfont-list", spec, val);
1079 if (objset) FcObjectSetDestroy (objset);
1080 if (fontset) FcFontSetDestroy (fontset);
1081 if (pattern) FcPatternDestroy (pattern);
1082 return val;
1085 static Lisp_Object
1086 ftfont_match (struct frame *f, Lisp_Object spec)
1088 Lisp_Object entity = Qnil;
1089 FcPattern *pattern, *match = NULL;
1090 FcResult result;
1091 char otlayout[15]; /* For "otlayout:XXXX" */
1092 struct OpenTypeSpec *otspec = NULL;
1093 const char *langname = NULL;
1095 if (! fc_initialized)
1097 FcInit ();
1098 fc_initialized = 1;
1101 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1102 if (! pattern)
1103 return Qnil;
1105 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1107 FcValue value;
1109 value.type = FcTypeDouble;
1110 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1111 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1113 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1115 FcDefaultSubstitute (pattern);
1116 match = FcFontMatch (NULL, pattern, &result);
1117 if (match)
1119 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1120 FcPatternDestroy (match);
1121 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1122 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1123 ftfont_generic_family_list))
1124 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1125 AREF (entity, FONT_FAMILY_INDEX))))
1126 entity = Qnil;
1129 FcPatternDestroy (pattern);
1131 FONT_ADD_LOG ("ftfont-match", spec, entity);
1132 return entity;
1135 static Lisp_Object
1136 ftfont_list_family (struct frame *f)
1138 Lisp_Object list = Qnil;
1139 FcPattern *pattern = NULL;
1140 FcFontSet *fontset = NULL;
1141 FcObjectSet *objset = NULL;
1142 int i;
1144 if (! fc_initialized)
1146 FcInit ();
1147 fc_initialized = 1;
1150 pattern = FcPatternCreate ();
1151 if (! pattern)
1152 goto finish;
1153 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1154 if (! objset)
1155 goto finish;
1156 fontset = FcFontList (NULL, pattern, objset);
1157 if (! fontset)
1158 goto finish;
1160 for (i = 0; i < fontset->nfont; i++)
1162 FcPattern *pat = fontset->fonts[i];
1163 FcChar8 *str;
1165 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1166 list = Fcons (intern ((char *) str), list);
1169 finish:
1170 if (objset) FcObjectSetDestroy (objset);
1171 if (fontset) FcFontSetDestroy (fontset);
1172 if (pattern) FcPatternDestroy (pattern);
1174 return list;
1178 static Lisp_Object
1179 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1181 struct ftfont_info *ftfont_info;
1182 struct font *font;
1183 struct ftfont_cache_data *cache_data;
1184 FT_Face ft_face;
1185 FT_Size ft_size;
1186 FT_UInt size;
1187 Lisp_Object val, filename, idx, cache, font_object;
1188 bool scalable;
1189 int spacing;
1190 char name[256];
1191 int i, len;
1192 int upEM;
1194 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1195 if (! CONSP (val))
1196 return Qnil;
1197 val = XCDR (val);
1198 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1199 if (NILP (cache))
1200 return Qnil;
1201 filename = XCAR (val);
1202 idx = XCDR (val);
1203 val = XCDR (cache);
1204 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1205 ft_face = cache_data->ft_face;
1206 if (XSAVE_INTEGER (val, 1) > 0)
1208 /* FT_Face in this cache is already used by the different size. */
1209 if (FT_New_Size (ft_face, &ft_size) != 0)
1210 return Qnil;
1211 if (FT_Activate_Size (ft_size) != 0)
1213 FT_Done_Size (ft_size);
1214 return Qnil;
1217 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1218 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1219 if (size == 0)
1220 size = pixel_size;
1221 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1223 if (XSAVE_INTEGER (val, 1) == 0)
1224 FT_Done_Face (ft_face);
1225 return Qnil;
1228 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
1229 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
1230 len = font_unparse_xlfd (entity, size, name, 256);
1231 if (len > 0)
1232 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
1233 len = font_unparse_fcname (entity, size, name, 256);
1234 if (len > 0)
1235 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
1236 else
1237 ASET (font_object, FONT_FULLNAME_INDEX,
1238 AREF (font_object, FONT_NAME_INDEX));
1239 ASET (font_object, FONT_FILE_INDEX, filename);
1240 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
1241 font = XFONT_OBJECT (font_object);
1242 ftfont_info = (struct ftfont_info *) font;
1243 ftfont_info->ft_size = ft_face->size;
1244 ftfont_info->index = XINT (idx);
1245 #ifdef HAVE_LIBOTF
1246 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1247 ftfont_info->otf = NULL;
1248 #endif /* HAVE_LIBOTF */
1249 /* This means that there's no need of transformation. */
1250 ftfont_info->matrix.xx = 0;
1251 font->pixel_size = size;
1252 font->driver = &ftfont_driver;
1253 font->encoding_charset = font->repertory_charset = -1;
1255 upEM = ft_face->units_per_EM;
1256 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1257 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1258 if (scalable)
1260 font->ascent = ft_face->ascender * size / upEM;
1261 font->descent = - ft_face->descender * size / upEM;
1262 font->height = ft_face->height * size / upEM;
1264 else
1266 font->ascent = ft_face->size->metrics.ascender >> 6;
1267 font->descent = - ft_face->size->metrics.descender >> 6;
1268 font->height = ft_face->size->metrics.height >> 6;
1270 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1271 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1272 else
1273 spacing = FC_PROPORTIONAL;
1274 if (spacing != FC_PROPORTIONAL
1275 #ifdef FC_DUAL
1276 && spacing != FC_DUAL
1277 #endif /* FC_DUAL */
1279 font->min_width = font->average_width = font->space_width
1280 = (scalable ? ft_face->max_advance_width * size / upEM
1281 : ft_face->size->metrics.max_advance >> 6);
1282 else
1284 int n;
1286 font->min_width = font->average_width = font->space_width = 0;
1287 for (i = 32, n = 0; i < 127; i++)
1288 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1290 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1292 if (this_width > 0
1293 && (! font->min_width || font->min_width > this_width))
1294 font->min_width = this_width;
1295 if (i == 32)
1296 font->space_width = this_width;
1297 font->average_width += this_width;
1298 n++;
1300 if (n > 0)
1301 font->average_width /= n;
1304 font->baseline_offset = 0;
1305 font->relative_compose = 0;
1306 font->default_ascent = 0;
1307 font->vertical_centering = 0;
1308 if (scalable)
1310 font->underline_position = -ft_face->underline_position * size / upEM;
1311 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1313 else
1315 font->underline_position = -1;
1316 font->underline_thickness = 0;
1319 return font_object;
1322 static void
1323 ftfont_close (struct font *font)
1325 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1326 Lisp_Object val, cache;
1328 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1329 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1330 eassert (CONSP (cache));
1331 val = XCDR (cache);
1332 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1333 if (XSAVE_INTEGER (val, 1) == 0)
1335 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1337 FT_Done_Face (cache_data->ft_face);
1338 #ifdef HAVE_LIBOTF
1339 if (ftfont_info->otf)
1340 OTF_close (ftfont_info->otf);
1341 #endif
1342 cache_data->ft_face = NULL;
1344 else
1345 FT_Done_Size (ftfont_info->ft_size);
1348 static int
1349 ftfont_has_char (Lisp_Object font, int c)
1351 struct charset *cs = NULL;
1353 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1354 && charset_jisx0208 >= 0)
1355 cs = CHARSET_FROM_ID (charset_jisx0208);
1356 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1357 && charset_ksc5601 >= 0)
1358 cs = CHARSET_FROM_ID (charset_ksc5601);
1359 if (cs)
1360 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1362 if (FONT_ENTITY_P (font))
1364 FcCharSet *charset = ftfont_get_fc_charset (font);
1366 return (FcCharSetHasChar (charset, c) == FcTrue);
1368 else
1370 struct ftfont_info *ftfont_info;
1372 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1373 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1374 != 0);
1378 static unsigned
1379 ftfont_encode_char (struct font *font, int c)
1381 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1382 FT_Face ft_face = ftfont_info->ft_size->face;
1383 FT_ULong charcode = c;
1384 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1386 return (code > 0 ? code : FONT_INVALID_CODE);
1389 static int
1390 ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
1392 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1393 FT_Face ft_face = ftfont_info->ft_size->face;
1394 int width = 0;
1395 int i;
1396 bool first;
1398 if (ftfont_info->ft_size != ft_face->size)
1399 FT_Activate_Size (ftfont_info->ft_size);
1400 if (metrics)
1401 memset (metrics, 0, sizeof (struct font_metrics));
1402 for (i = 0, first = 1; i < nglyphs; i++)
1404 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1406 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1408 if (first)
1410 if (metrics)
1412 metrics->lbearing = m->horiBearingX >> 6;
1413 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1414 metrics->ascent = m->horiBearingY >> 6;
1415 metrics->descent = (m->height - m->horiBearingY) >> 6;
1417 first = 0;
1419 if (metrics)
1421 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1422 metrics->lbearing = width + (m->horiBearingX >> 6);
1423 if (metrics->rbearing
1424 < width + ((m->horiBearingX + m->width) >> 6))
1425 metrics->rbearing
1426 = width + ((m->horiBearingX + m->width) >> 6);
1427 if (metrics->ascent < (m->horiBearingY >> 6))
1428 metrics->ascent = m->horiBearingY >> 6;
1429 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1430 metrics->descent = (m->height - m->horiBearingY) >> 6;
1432 width += m->horiAdvance >> 6;
1434 else
1436 width += font->space_width;
1439 if (metrics)
1440 metrics->width = width;
1442 return width;
1445 static int
1446 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1448 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1449 FT_Face ft_face = ftfont_info->ft_size->face;
1450 FT_Int32 load_flags = FT_LOAD_RENDER;
1452 if (ftfont_info->ft_size != ft_face->size)
1453 FT_Activate_Size (ftfont_info->ft_size);
1454 if (bits_per_pixel == 1)
1456 #ifdef FT_LOAD_TARGET_MONO
1457 load_flags |= FT_LOAD_TARGET_MONO;
1458 #else
1459 load_flags |= FT_LOAD_MONOCHROME;
1460 #endif
1462 else if (bits_per_pixel != 8)
1463 /* We don't support such a rendering. */
1464 return -1;
1466 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1467 return -1;
1468 bitmap->bits_per_pixel
1469 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1470 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1471 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1472 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1473 : -1);
1474 if (bitmap->bits_per_pixel < 0)
1475 /* We don't support that kind of pixel mode. */
1476 return -1;
1477 bitmap->rows = ft_face->glyph->bitmap.rows;
1478 bitmap->width = ft_face->glyph->bitmap.width;
1479 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1480 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1481 bitmap->left = ft_face->glyph->bitmap_left;
1482 bitmap->top = ft_face->glyph->bitmap_top;
1483 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1485 return 0;
1488 static int
1489 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1490 int *x, int *y)
1492 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1493 FT_Face ft_face = ftfont_info->ft_size->face;
1495 if (ftfont_info->ft_size != ft_face->size)
1496 FT_Activate_Size (ftfont_info->ft_size);
1497 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1498 return -1;
1499 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1500 return -1;
1501 if (idx >= ft_face->glyph->outline.n_points)
1502 return -1;
1503 *x = ft_face->glyph->outline.points[idx].x;
1504 *y = ft_face->glyph->outline.points[idx].y;
1505 return 0;
1508 #ifdef HAVE_LIBOTF
1510 static Lisp_Object
1511 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1513 Lisp_Object scripts, langsyses, features, sym;
1514 int i, j, k, l;
1516 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1518 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1520 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1522 OTF_LangSys *otf_langsys;
1524 if (j >= 0)
1525 otf_langsys = otf_script->LangSys + j;
1526 else if (otf_script->DefaultLangSysOffset)
1527 otf_langsys = &otf_script->DefaultLangSys;
1528 else
1529 break;
1531 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1533 l = otf_langsys->FeatureIndex[k];
1534 if (l >= gsub_gpos->FeatureList.FeatureCount)
1535 continue;
1536 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1537 features = Fcons (sym, features);
1539 if (j >= 0)
1540 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1541 else
1542 sym = Qnil;
1543 langsyses = Fcons (Fcons (sym, features), langsyses);
1546 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1547 scripts = Fcons (Fcons (sym, langsyses), scripts);
1549 return scripts;
1554 static Lisp_Object
1555 ftfont_otf_capability (struct font *font)
1557 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1558 OTF *otf = ftfont_get_otf (ftfont_info);
1559 Lisp_Object gsub_gpos;
1561 if (! otf)
1562 return Qnil;
1563 gsub_gpos = Fcons (Qnil, Qnil);
1564 if (OTF_get_table (otf, "GSUB") == 0
1565 && otf->gsub->FeatureList.FeatureCount > 0)
1566 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1567 if (OTF_get_table (otf, "GPOS") == 0
1568 && otf->gpos->FeatureList.FeatureCount > 0)
1569 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1570 return gsub_gpos;
1573 #ifdef HAVE_M17N_FLT
1575 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1576 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1577 /* We can use the new feature of libotf and m17n-flt to handle the
1578 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1579 some Agian scripts. */
1580 #define M17N_FLT_USE_NEW_FEATURE
1581 #endif
1583 struct MFLTFontFT
1585 MFLTFont flt_font;
1586 struct font *font;
1587 FT_Face ft_face;
1588 OTF *otf;
1589 FT_Matrix *matrix;
1592 static int
1593 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1594 int from, int to)
1596 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1597 FT_Face ft_face = flt_font_ft->ft_face;
1598 MFLTGlyph *g;
1600 for (g = gstring->glyphs + from; from < to; g++, from++)
1601 if (! g->encoded)
1603 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1605 g->code = code > 0 ? code : FONT_INVALID_CODE;
1606 g->encoded = 1;
1608 return 0;
1611 /* Operators for 26.6 fixed fractional pixel format */
1613 #define FLOOR(x) ((x) & -64)
1614 #define CEIL(x) (((x)+63) & -64)
1615 #define ROUND(x) (((x)+32) & -64)
1617 static int
1618 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1619 int from, int to)
1621 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1622 FT_Face ft_face = flt_font_ft->ft_face;
1623 MFLTGlyph *g;
1625 for (g = gstring->glyphs + from; from < to; g++, from++)
1626 if (! g->measured)
1628 if (g->code != FONT_INVALID_CODE)
1630 FT_Glyph_Metrics *m;
1632 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1633 emacs_abort ();
1634 m = &ft_face->glyph->metrics;
1635 if (flt_font_ft->matrix)
1637 FT_Vector v[4];
1638 int i;
1640 v[0].x = v[1].x = m->horiBearingX;
1641 v[2].x = v[3].x = m->horiBearingX + m->width;
1642 v[0].y = v[2].y = m->horiBearingY;
1643 v[1].y = v[3].y = m->horiBearingY - m->height;
1644 for (i = 0; i < 4; i++)
1645 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1646 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1647 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1648 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1649 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1651 else
1653 g->lbearing = FLOOR (m->horiBearingX);
1654 g->rbearing = CEIL (m->horiBearingX + m->width);
1655 g->ascent = CEIL (m->horiBearingY);
1656 g->descent = - FLOOR (m->horiBearingY - m->height);
1658 g->xadv = ROUND (ft_face->glyph->advance.x);
1660 else
1662 g->lbearing = 0;
1663 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1664 g->ascent = flt_font_ft->font->ascent << 6;
1665 g->descent = flt_font_ft->font->descent << 6;
1667 g->yadv = 0;
1668 g->measured = 1;
1670 return 0;
1673 static int
1674 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1676 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1678 #define FEATURE_ANY(IDX) \
1679 (spec->features[IDX] \
1680 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1682 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1683 OTF *otf = flt_font_ft->otf;
1684 OTF_Tag *tags;
1685 int i, n;
1686 bool negative;
1688 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1689 /* Return true iff any of GSUB or GPOS support the script (and
1690 language). */
1691 return (otf
1692 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1693 NULL, 0) > 0
1694 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1695 NULL, 0) > 0));
1697 for (i = 0; i < 2; i++)
1698 if (! FEATURE_ANY (i))
1700 if (FEATURE_NONE (i))
1702 if (otf
1703 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1704 NULL, 0) > 0)
1705 return 0;
1706 continue;
1708 if (spec->features[i][0] == 0xFFFFFFFF)
1710 if (! otf
1711 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1712 NULL, 0) <= 0)
1713 continue;
1715 else if (! otf)
1716 return 0;
1717 for (n = 1; spec->features[i][n]; n++);
1718 tags = alloca (sizeof (OTF_Tag) * n);
1719 for (n = 0, negative = 0; spec->features[i][n]; n++)
1721 if (spec->features[i][n] == 0xFFFFFFFF)
1722 negative = 1;
1723 else if (negative)
1724 tags[n - 1] = spec->features[i][n] | 0x80000000;
1725 else
1726 tags[n] = spec->features[i][n];
1728 #ifdef M17N_FLT_USE_NEW_FEATURE
1729 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1730 tags, n - negative) != 1)
1731 return 0;
1732 #else /* not M17N_FLT_USE_NEW_FEATURE */
1733 if (n - negative > 0
1734 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1735 tags, n - negative) != 1)
1736 return 0;
1737 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1739 return 1;
1740 #undef FEATURE_NONE
1741 #undef FEATURE_ANY
1744 #define DEVICE_DELTA(table, size) \
1745 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1746 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1747 : 0)
1749 static void
1750 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1751 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1753 if (anchor->AnchorFormat == 2)
1755 FT_Outline *outline;
1756 int ap = anchor->f.f1.AnchorPoint;
1758 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1759 outline = &ft_face->glyph->outline;
1760 if (ap < outline->n_points)
1762 *x = outline->points[ap].x << 6;
1763 *y = outline->points[ap].y << 6;
1766 else if (anchor->AnchorFormat == 3)
1768 if (anchor->f.f2.XDeviceTable.offset
1769 && anchor->f.f2.XDeviceTable.DeltaValue)
1770 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1771 if (anchor->f.f2.YDeviceTable.offset
1772 && anchor->f.f2.YDeviceTable.DeltaValue)
1773 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1777 static OTF_GlyphString otf_gstring;
1779 static void
1780 setup_otf_gstring (int size)
1782 if (otf_gstring.size < size)
1784 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1785 size, sizeof (OTF_Glyph));
1786 otf_gstring.size = size;
1788 otf_gstring.used = size;
1789 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1792 #ifdef M17N_FLT_USE_NEW_FEATURE
1794 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1795 #define PACK_OTF_TAG(TAG) \
1796 ((((TAG) & 0x7F000000) >> 3) \
1797 | (((TAG) & 0x7F0000) >> 2) \
1798 | (((TAG) & 0x7F00) >> 1) \
1799 | ((TAG) & 0x7F))
1801 /* Assuming that FONT is an OpenType font, apply OpenType features
1802 specified in SPEC on glyphs between FROM and TO of IN, and record
1803 the lastly applied feature in each glyph of IN. If OUT is not
1804 NULL, append the resulting glyphs to OUT while storing glyph
1805 position adjustment information in ADJUSTMENT. */
1807 static int
1808 ftfont_drive_otf (MFLTFont *font,
1809 MFLTOtfSpec *spec,
1810 MFLTGlyphString *in,
1811 int from,
1812 int to,
1813 MFLTGlyphString *out,
1814 MFLTGlyphAdjustment *adjustment)
1816 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1817 FT_Face ft_face = flt_font_ft->ft_face;
1818 OTF *otf = flt_font_ft->otf;
1819 int len = to - from;
1820 int i, j, gidx;
1821 OTF_Glyph *otfg;
1822 char script[5], *langsys = NULL;
1823 char *gsub_features = NULL, *gpos_features = NULL;
1824 OTF_Feature *features;
1826 if (len == 0)
1827 return from;
1828 OTF_tag_name (spec->script, script);
1829 if (spec->langsys)
1831 langsys = alloca (5);
1832 OTF_tag_name (spec->langsys, langsys);
1834 for (i = 0; i < 2; i++)
1836 char *p;
1838 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1840 for (j = 0; spec->features[i][j]; j++);
1841 if (i == 0)
1842 p = gsub_features = alloca (6 * j);
1843 else
1844 p = gpos_features = alloca (6 * j);
1845 for (j = 0; spec->features[i][j]; j++)
1847 if (spec->features[i][j] == 0xFFFFFFFF)
1848 *p++ = '*', *p++ = ',';
1849 else
1851 OTF_tag_name (spec->features[i][j], p);
1852 p[4] = ',';
1853 p += 5;
1856 *--p = '\0';
1860 setup_otf_gstring (len);
1861 for (i = 0; i < len; i++)
1863 otf_gstring.glyphs[i].c = in->glyphs[from + i].c & 0x11FFFF;
1864 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1867 OTF_drive_gdef (otf, &otf_gstring);
1868 gidx = out ? out->used : from;
1870 if (gsub_features && out)
1872 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1873 gsub_features) < 0)
1874 goto simple_copy;
1875 if (out->allocated < out->used + otf_gstring.used)
1876 return -2;
1877 features = otf->gsub->FeatureList.Feature;
1878 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1880 MFLTGlyph *g;
1881 int min_from, max_to;
1882 int feature_idx = otfg->positioning_type >> 4;
1884 g = out->glyphs + out->used;
1885 *g = in->glyphs[from + otfg->f.index.from];
1886 if (g->code != otfg->glyph_id)
1888 g->c = 0;
1889 g->code = otfg->glyph_id;
1890 g->measured = 0;
1892 out->used++;
1893 min_from = g->from;
1894 max_to = g->to;
1895 if (otfg->f.index.from < otfg->f.index.to)
1897 /* OTFG substitutes multiple glyphs in IN. */
1898 for (j = from + otfg->f.index.from + 1;
1899 j <= from + otfg->f.index.to; j++)
1901 if (min_from > in->glyphs[j].from)
1902 min_from = in->glyphs[j].from;
1903 if (max_to < in->glyphs[j].to)
1904 max_to = in->glyphs[j].to;
1906 g->from = min_from;
1907 g->to = max_to;
1909 if (feature_idx)
1911 unsigned int tag = features[feature_idx - 1].FeatureTag;
1912 tag = PACK_OTF_TAG (tag);
1913 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1915 for (i++, otfg++; (i < otf_gstring.used
1916 && otfg->f.index.from == otfg[-1].f.index.from);
1917 i++, otfg++)
1919 g = out->glyphs + out->used;
1920 *g = in->glyphs[from + otfg->f.index.to];
1921 if (g->code != otfg->glyph_id)
1923 g->c = 0;
1924 g->code = otfg->glyph_id;
1925 g->measured = 0;
1927 feature_idx = otfg->positioning_type >> 4;
1928 if (feature_idx)
1930 unsigned int tag = features[feature_idx - 1].FeatureTag;
1931 tag = PACK_OTF_TAG (tag);
1932 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1934 out->used++;
1938 else if (gsub_features)
1940 /* Just for checking which features will be applied. */
1941 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1942 gsub_features) < 0)
1943 goto simple_copy;
1944 features = otf->gsub->FeatureList.Feature;
1945 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1946 otfg++)
1948 int feature_idx = otfg->positioning_type >> 4;
1950 if (feature_idx)
1952 unsigned int tag = features[feature_idx - 1].FeatureTag;
1953 tag = PACK_OTF_TAG (tag);
1954 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1956 MFLTGlyph *g = in->glyphs + (from + j);
1957 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1962 else if (out)
1964 if (out->allocated < out->used + len)
1965 return -2;
1966 for (i = 0; i < len; i++)
1967 out->glyphs[out->used++] = in->glyphs[from + i];
1970 if (gpos_features && out)
1972 MFLTGlyph *base = NULL, *mark = NULL, *g;
1973 int x_ppem, y_ppem, x_scale, y_scale;
1975 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1976 gpos_features) < 0)
1977 return to;
1978 features = otf->gpos->FeatureList.Feature;
1979 x_ppem = ft_face->size->metrics.x_ppem;
1980 y_ppem = ft_face->size->metrics.y_ppem;
1981 x_scale = ft_face->size->metrics.x_scale;
1982 y_scale = ft_face->size->metrics.y_scale;
1984 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1985 i < otf_gstring.used; i++, otfg++, g++)
1987 MFLTGlyph *prev;
1988 int feature_idx = otfg->positioning_type >> 4;
1990 if (feature_idx)
1992 unsigned int tag = features[feature_idx - 1].FeatureTag;
1993 tag = PACK_OTF_TAG (tag);
1994 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1997 if (! otfg->glyph_id)
1998 continue;
1999 switch (otfg->positioning_type & 0xF)
2001 case 0:
2002 break;
2003 case 1: /* Single */
2004 case 2: /* Pair */
2006 int format = otfg->f.f1.format;
2008 if (format & OTF_XPlacement)
2009 adjustment[i].xoff
2010 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2011 if (format & OTF_XPlaDevice)
2012 adjustment[i].xoff
2013 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2014 if (format & OTF_YPlacement)
2015 adjustment[i].yoff
2016 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2017 if (format & OTF_YPlaDevice)
2018 adjustment[i].yoff
2019 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2020 if (format & OTF_XAdvance)
2021 adjustment[i].xadv
2022 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2023 if (format & OTF_XAdvDevice)
2024 adjustment[i].xadv
2025 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2026 if (format & OTF_YAdvance)
2027 adjustment[i].yadv
2028 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2029 if (format & OTF_YAdvDevice)
2030 adjustment[i].yadv
2031 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2032 adjustment[i].set = 1;
2034 break;
2035 case 3: /* Cursive */
2036 /* Not yet supported. */
2037 break;
2038 case 4: /* Mark-to-Base */
2039 case 5: /* Mark-to-Ligature */
2040 if (! base)
2041 break;
2042 prev = base;
2043 goto label_adjust_anchor;
2044 default: /* i.e. case 6 Mark-to-Mark */
2045 if (! mark)
2046 break;
2047 prev = mark;
2049 label_adjust_anchor:
2051 int base_x, base_y, mark_x, mark_y;
2052 int this_from, this_to;
2054 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2055 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2056 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2057 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2059 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2060 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2061 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2062 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2063 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2064 x_ppem, y_ppem, &mark_x, &mark_y);
2065 adjustment[i].xoff = (base_x - mark_x);
2066 adjustment[i].yoff = - (base_y - mark_y);
2067 adjustment[i].back = (g - prev);
2068 adjustment[i].xadv = 0;
2069 adjustment[i].advance_is_absolute = 1;
2070 adjustment[i].set = 1;
2071 this_from = g->from;
2072 this_to = g->to;
2073 for (j = 0; prev + j < g; j++)
2075 if (this_from > prev[j].from)
2076 this_from = prev[j].from;
2077 if (this_to < prev[j].to)
2078 this_to = prev[j].to;
2080 for (; prev <= g; prev++)
2082 prev->from = this_from;
2083 prev->to = this_to;
2087 if (otfg->GlyphClass == OTF_GlyphClass0)
2088 base = mark = g;
2089 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2090 mark = g;
2091 else
2092 base = g;
2095 else if (gpos_features)
2097 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2098 gpos_features) < 0)
2099 return to;
2100 features = otf->gpos->FeatureList.Feature;
2101 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2102 i++, otfg++)
2103 if (otfg->positioning_type & 0xF)
2105 int feature_idx = otfg->positioning_type >> 4;
2107 if (feature_idx)
2109 unsigned int tag = features[feature_idx - 1].FeatureTag;
2110 tag = PACK_OTF_TAG (tag);
2111 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2113 MFLTGlyph *g = in->glyphs + (from + j);
2114 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2119 return to;
2121 simple_copy:
2122 if (! out)
2123 return to;
2124 if (out->allocated < out->used + len)
2125 return -2;
2126 font->get_metrics (font, in, from, to);
2127 memcpy (out->glyphs + out->used, in->glyphs + from,
2128 sizeof (MFLTGlyph) * len);
2129 out->used += len;
2130 return to;
2133 static int
2134 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2135 MFLTGlyphString *in, int from, int to)
2137 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2140 #else /* not M17N_FLT_USE_NEW_FEATURE */
2142 static int
2143 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2144 int from, int to,
2145 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2147 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2148 FT_Face ft_face = flt_font_ft->ft_face;
2149 OTF *otf = flt_font_ft->otf;
2150 int len = to - from;
2151 int i, j, gidx;
2152 OTF_Glyph *otfg;
2153 char script[5], *langsys = NULL;
2154 char *gsub_features = NULL, *gpos_features = NULL;
2156 if (len == 0)
2157 return from;
2158 OTF_tag_name (spec->script, script);
2159 if (spec->langsys)
2161 langsys = alloca (5);
2162 OTF_tag_name (spec->langsys, langsys);
2164 for (i = 0; i < 2; i++)
2166 char *p;
2168 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2170 for (j = 0; spec->features[i][j]; j++);
2171 if (i == 0)
2172 p = gsub_features = alloca (6 * j);
2173 else
2174 p = gpos_features = alloca (6 * j);
2175 for (j = 0; spec->features[i][j]; j++)
2177 if (spec->features[i][j] == 0xFFFFFFFF)
2178 *p++ = '*', *p++ = ',';
2179 else
2181 OTF_tag_name (spec->features[i][j], p);
2182 p[4] = ',';
2183 p += 5;
2186 *--p = '\0';
2190 setup_otf_gstring (len);
2191 for (i = 0; i < len; i++)
2193 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2194 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2197 OTF_drive_gdef (otf, &otf_gstring);
2198 gidx = out->used;
2200 if (gsub_features)
2202 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2203 < 0)
2204 goto simple_copy;
2205 if (out->allocated < out->used + otf_gstring.used)
2206 return -2;
2207 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2209 MFLTGlyph *g;
2210 int min_from, max_to;
2211 int j;
2213 g = out->glyphs + out->used;
2214 *g = in->glyphs[from + otfg->f.index.from];
2215 if (g->code != otfg->glyph_id)
2217 g->c = 0;
2218 g->code = otfg->glyph_id;
2219 g->measured = 0;
2221 out->used++;
2222 min_from = g->from;
2223 max_to = g->to;
2224 if (otfg->f.index.from < otfg->f.index.to)
2226 /* OTFG substitutes multiple glyphs in IN. */
2227 for (j = from + otfg->f.index.from + 1;
2228 j <= from + otfg->f.index.to; j++)
2230 if (min_from > in->glyphs[j].from)
2231 min_from = in->glyphs[j].from;
2232 if (max_to < in->glyphs[j].to)
2233 max_to = in->glyphs[j].to;
2235 g->from = min_from;
2236 g->to = max_to;
2238 for (i++, otfg++; (i < otf_gstring.used
2239 && otfg->f.index.from == otfg[-1].f.index.from);
2240 i++, otfg++)
2242 g = out->glyphs + out->used;
2243 *g = in->glyphs[from + otfg->f.index.to];
2244 if (g->code != otfg->glyph_id)
2246 g->c = 0;
2247 g->code = otfg->glyph_id;
2248 g->measured = 0;
2250 out->used++;
2254 else
2256 if (out->allocated < out->used + len)
2257 return -2;
2258 for (i = 0; i < len; i++)
2259 out->glyphs[out->used++] = in->glyphs[from + i];
2262 if (gpos_features)
2264 MFLTGlyph *base = NULL, *mark = NULL, *g;
2265 int x_ppem, y_ppem, x_scale, y_scale;
2267 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2268 < 0)
2269 return to;
2271 x_ppem = ft_face->size->metrics.x_ppem;
2272 y_ppem = ft_face->size->metrics.y_ppem;
2273 x_scale = ft_face->size->metrics.x_scale;
2274 y_scale = ft_face->size->metrics.y_scale;
2276 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2277 i < otf_gstring.used; i++, otfg++, g++)
2279 MFLTGlyph *prev;
2281 if (! otfg->glyph_id)
2282 continue;
2283 switch (otfg->positioning_type)
2285 case 0:
2286 break;
2287 case 1: /* Single */
2288 case 2: /* Pair */
2290 int format = otfg->f.f1.format;
2292 if (format & OTF_XPlacement)
2293 adjustment[i].xoff
2294 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2295 if (format & OTF_XPlaDevice)
2296 adjustment[i].xoff
2297 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2298 if (format & OTF_YPlacement)
2299 adjustment[i].yoff
2300 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2301 if (format & OTF_YPlaDevice)
2302 adjustment[i].yoff
2303 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2304 if (format & OTF_XAdvance)
2305 adjustment[i].xadv
2306 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2307 if (format & OTF_XAdvDevice)
2308 adjustment[i].xadv
2309 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2310 if (format & OTF_YAdvance)
2311 adjustment[i].yadv
2312 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2313 if (format & OTF_YAdvDevice)
2314 adjustment[i].yadv
2315 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2316 adjustment[i].set = 1;
2318 break;
2319 case 3: /* Cursive */
2320 /* Not yet supported. */
2321 break;
2322 case 4: /* Mark-to-Base */
2323 case 5: /* Mark-to-Ligature */
2324 if (! base)
2325 break;
2326 prev = base;
2327 goto label_adjust_anchor;
2328 default: /* i.e. case 6 Mark-to-Mark */
2329 if (! mark)
2330 break;
2331 prev = mark;
2333 label_adjust_anchor:
2335 int base_x, base_y, mark_x, mark_y;
2336 int this_from, this_to;
2338 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2339 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2340 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2341 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2343 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2344 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2345 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2346 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2347 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2348 x_ppem, y_ppem, &mark_x, &mark_y);
2349 adjustment[i].xoff = (base_x - mark_x);
2350 adjustment[i].yoff = - (base_y - mark_y);
2351 adjustment[i].back = (g - prev);
2352 adjustment[i].xadv = 0;
2353 adjustment[i].advance_is_absolute = 1;
2354 adjustment[i].set = 1;
2355 this_from = g->from;
2356 this_to = g->to;
2357 for (j = 0; prev + j < g; j++)
2359 if (this_from > prev[j].from)
2360 this_from = prev[j].from;
2361 if (this_to < prev[j].to)
2362 this_to = prev[j].to;
2364 for (; prev <= g; prev++)
2366 prev->from = this_from;
2367 prev->to = this_to;
2371 if (otfg->GlyphClass == OTF_GlyphClass0)
2372 base = mark = g;
2373 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2374 mark = g;
2375 else
2376 base = g;
2379 return to;
2381 simple_copy:
2382 if (out->allocated < out->used + len)
2383 return -2;
2384 font->get_metrics (font, in, from, to);
2385 memcpy (out->glyphs + out->used, in->glyphs + from,
2386 sizeof (MFLTGlyph) * len);
2387 out->used += len;
2388 return to;
2391 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2393 static MFLTGlyphString gstring;
2395 static bool m17n_flt_initialized;
2397 static Lisp_Object
2398 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2399 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2401 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2402 ptrdiff_t i;
2403 struct MFLTFontFT flt_font_ft;
2404 MFLT *flt = NULL;
2405 bool with_variation_selector = 0;
2407 if (! m17n_flt_initialized)
2409 M17N_INIT ();
2410 #ifdef M17N_FLT_USE_NEW_FEATURE
2411 mflt_enable_new_feature = 1;
2412 mflt_try_otf = ftfont_try_otf;
2413 #endif /* M17N_FLT_USE_NEW_FEATURE */
2414 m17n_flt_initialized = 1;
2417 for (i = 0; i < len; i++)
2419 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2420 int c;
2422 if (NILP (g))
2423 break;
2424 c = LGLYPH_CHAR (g);
2425 if (CHAR_VARIATION_SELECTOR_P (c))
2426 with_variation_selector = 1;
2429 len = i;
2431 if (with_variation_selector)
2433 setup_otf_gstring (len);
2434 for (i = 0; i < len; i++)
2436 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2438 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2439 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2440 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2442 OTF_drive_cmap (otf, &otf_gstring);
2443 for (i = 0; i < otf_gstring.used; i++)
2445 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2446 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2447 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2449 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2450 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2451 LGSTRING_SET_GLYPH (lgstring, i, g0);
2453 if (len > otf_gstring.used)
2455 len = otf_gstring.used;
2456 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2460 if (INT_MAX / 2 < len)
2461 memory_full (SIZE_MAX);
2463 if (gstring.allocated == 0)
2465 gstring.glyph_size = sizeof (MFLTGlyph);
2466 gstring.glyphs = xnmalloc (len * 2, sizeof *gstring.glyphs);
2467 gstring.allocated = len * 2;
2469 else if (gstring.allocated < len * 2)
2471 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2,
2472 sizeof *gstring.glyphs);
2473 gstring.allocated = len * 2;
2475 memset (gstring.glyphs, 0, len * sizeof *gstring.glyphs);
2476 for (i = 0; i < len; i++)
2478 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2480 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2481 if (with_variation_selector)
2483 gstring.glyphs[i].code = LGLYPH_CODE (g);
2484 gstring.glyphs[i].encoded = 1;
2488 gstring.used = len;
2489 gstring.r2l = 0;
2492 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2494 if (NILP (family))
2495 flt_font_ft.flt_font.family = Mnil;
2496 else
2497 flt_font_ft.flt_font.family
2498 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2500 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2501 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2502 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2503 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2504 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2505 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2506 flt_font_ft.flt_font.internal = NULL;
2507 flt_font_ft.font = font;
2508 flt_font_ft.ft_face = ft_face;
2509 flt_font_ft.otf = otf;
2510 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2511 if (len > 1
2512 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2513 /* A little bit ad hoc. Perhaps, shaper must get script and
2514 language information, and select a proper flt for them
2515 here. */
2516 flt = mflt_get (msymbol ("combining"));
2517 for (i = 0; i < 3; i++)
2519 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2520 if (result != -2)
2521 break;
2522 if (INT_MAX / 2 < gstring.allocated)
2523 memory_full (SIZE_MAX);
2524 gstring.glyphs = xnrealloc (gstring.glyphs,
2525 gstring.allocated, 2 * sizeof (MFLTGlyph));
2526 gstring.allocated *= 2;
2528 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2529 return Qnil;
2530 for (i = 0; i < gstring.used; i++)
2532 MFLTGlyph *g = gstring.glyphs + i;
2534 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2535 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2538 for (i = 0; i < gstring.used; i++)
2540 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2541 MFLTGlyph *g = gstring.glyphs + i;
2543 if (NILP (lglyph))
2545 lglyph = LGLYPH_NEW ();
2546 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2548 LGLYPH_SET_FROM (lglyph, g->from);
2549 LGLYPH_SET_TO (lglyph, g->to);
2550 LGLYPH_SET_CHAR (lglyph, g->c);
2551 LGLYPH_SET_CODE (lglyph, g->code);
2552 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2553 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2554 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2555 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2556 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2557 if (g->adjusted)
2559 Lisp_Object vec = make_uninit_vector (3);
2561 ASET (vec, 0, make_number (g->xoff >> 6));
2562 ASET (vec, 1, make_number (g->yoff >> 6));
2563 ASET (vec, 2, make_number (g->xadv >> 6));
2564 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2567 return make_number (i);
2570 Lisp_Object
2571 ftfont_shape (Lisp_Object lgstring)
2573 struct font *font;
2574 struct ftfont_info *ftfont_info;
2575 OTF *otf;
2577 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2578 ftfont_info = (struct ftfont_info *) font;
2579 otf = ftfont_get_otf (ftfont_info);
2580 if (! otf)
2581 return make_number (0);
2582 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2583 &ftfont_info->matrix);
2586 #endif /* HAVE_M17N_FLT */
2588 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2590 static int
2591 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2593 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2594 OTF *otf = ftfont_get_otf (ftfont_info);
2596 if (! otf)
2597 return 0;
2598 return OTF_get_variation_glyphs (otf, c, variations);
2601 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2602 #endif /* HAVE_LIBOTF */
2604 Lisp_Object
2605 ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
2607 FcChar8 *str;
2609 #ifdef FC_FONTFORMAT
2610 if (pattern)
2612 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2613 return Qnil;
2614 if (strcmp ((char *) str, "TrueType") == 0)
2615 return intern ("truetype");
2616 if (strcmp ((char *) str, "Type 1") == 0)
2617 return intern ("type1");
2618 if (strcmp ((char *) str, "PCF") == 0)
2619 return intern ("pcf");
2620 if (strcmp ((char *) str, "BDF") == 0)
2621 return intern ("bdf");
2623 #endif /* FC_FONTFORMAT */
2624 if (STRINGP (filename))
2626 int len = SBYTES (filename);
2628 if (len >= 4)
2630 str = (FcChar8 *) (SDATA (filename) + len - 4);
2631 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2632 return intern ("truetype");
2633 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2634 return intern ("type1");
2635 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2636 return intern ("pcf");
2637 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2638 return intern ("bdf");
2641 return intern ("unknown");
2644 static const char *const ftfont_booleans [] = {
2645 ":antialias",
2646 ":hinting",
2647 ":verticallayout",
2648 ":autohint",
2649 ":globaladvance",
2650 ":outline",
2651 ":scalable",
2652 ":minspace",
2653 ":embolden",
2654 NULL,
2657 static const char *const ftfont_non_booleans [] = {
2658 ":family",
2659 ":familylang",
2660 ":style",
2661 ":stylelang",
2662 ":fullname",
2663 ":fullnamelang",
2664 ":slant",
2665 ":weight",
2666 ":size",
2667 ":width",
2668 ":aspect",
2669 ":pixelsize",
2670 ":spacing",
2671 ":foundry",
2672 ":hintstyle",
2673 ":file",
2674 ":index",
2675 ":ftface",
2676 ":rasterizer",
2677 ":scale",
2678 ":dpi",
2679 ":rgba",
2680 ":lcdfilter",
2681 ":charset",
2682 ":lang",
2683 ":fontversion",
2684 ":capability",
2685 NULL,
2688 static void
2689 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2691 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2695 void
2696 syms_of_ftfont (void)
2698 DEFSYM (Qfreetype, "freetype");
2699 DEFSYM (Qmonospace, "monospace");
2700 DEFSYM (Qsans_serif, "sans-serif");
2701 DEFSYM (Qserif, "serif");
2702 DEFSYM (Qmono, "mono");
2703 DEFSYM (Qsans, "sans");
2704 DEFSYM (Qsans__serif, "sans serif");
2706 staticpro (&freetype_font_cache);
2707 freetype_font_cache = list1 (Qt);
2709 staticpro (&ftfont_generic_family_list);
2710 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2711 Fcons (Qsans_serif, Qt),
2712 Fcons (Qsans, Qt));
2714 staticpro (&ft_face_cache);
2715 ft_face_cache = Qnil;
2717 ftfont_driver.type = Qfreetype;
2718 register_font_driver (&ftfont_driver, NULL);