Allow comma separated lists after Java "implements".
[emacs.git] / src / ftfont.c
blobeeee56891ecc7b54e438a5feeae19be0926a9da7
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2013 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 casted 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 frame *, 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 OTF *otf;
1016 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1017 != FcResultMatch)
1018 continue;
1019 otf = OTF_open ((char *) file);
1020 if (! otf)
1021 continue;
1022 if (OTF_check_features (otf, 1,
1023 otspec->script_tag, otspec->langsys_tag,
1024 otspec->features[0],
1025 otspec->nfeatures[0]) != 1
1026 || OTF_check_features (otf, 0,
1027 otspec->script_tag, otspec->langsys_tag,
1028 otspec->features[1],
1029 otspec->nfeatures[1]) != 1)
1030 continue;
1032 #endif /* HAVE_LIBOTF */
1033 if (VECTORP (chars))
1035 ptrdiff_t j;
1037 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1038 != FcResultMatch)
1039 continue;
1040 for (j = 0; j < ASIZE (chars); j++)
1041 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1042 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1043 break;
1044 if (j == ASIZE (chars))
1045 continue;
1047 if (! NILP (adstyle) || langname)
1049 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1051 if (! NILP (adstyle)
1052 && (NILP (this_adstyle)
1053 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1054 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1055 continue;
1056 if (langname
1057 && ! NILP (this_adstyle)
1058 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1059 continue;
1061 entity = ftfont_pattern_entity (fontset->fonts[i],
1062 AREF (spec, FONT_EXTRA_INDEX));
1063 if (! NILP (entity))
1064 val = Fcons (entity, val);
1066 val = Fnreverse (val);
1067 goto finish;
1069 err:
1070 /* We come here because of unexpected error in fontconfig API call
1071 (usually insufficient memory). */
1072 val = Qnil;
1074 finish:
1075 FONT_ADD_LOG ("ftfont-list", spec, val);
1076 if (objset) FcObjectSetDestroy (objset);
1077 if (fontset) FcFontSetDestroy (fontset);
1078 if (pattern) FcPatternDestroy (pattern);
1079 return val;
1082 static Lisp_Object
1083 ftfont_match (struct frame *f, Lisp_Object spec)
1085 Lisp_Object entity = Qnil;
1086 FcPattern *pattern, *match = NULL;
1087 FcResult result;
1088 char otlayout[15]; /* For "otlayout:XXXX" */
1089 struct OpenTypeSpec *otspec = NULL;
1090 const char *langname = NULL;
1092 if (! fc_initialized)
1094 FcInit ();
1095 fc_initialized = 1;
1098 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1099 if (! pattern)
1100 return Qnil;
1102 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1104 FcValue value;
1106 value.type = FcTypeDouble;
1107 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1108 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1110 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1112 FcDefaultSubstitute (pattern);
1113 match = FcFontMatch (NULL, pattern, &result);
1114 if (match)
1116 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1117 FcPatternDestroy (match);
1118 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1119 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1120 ftfont_generic_family_list))
1121 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1122 AREF (entity, FONT_FAMILY_INDEX))))
1123 entity = Qnil;
1126 FcPatternDestroy (pattern);
1128 FONT_ADD_LOG ("ftfont-match", spec, entity);
1129 return entity;
1132 static Lisp_Object
1133 ftfont_list_family (struct frame *f)
1135 Lisp_Object list = Qnil;
1136 FcPattern *pattern = NULL;
1137 FcFontSet *fontset = NULL;
1138 FcObjectSet *objset = NULL;
1139 int i;
1141 if (! fc_initialized)
1143 FcInit ();
1144 fc_initialized = 1;
1147 pattern = FcPatternCreate ();
1148 if (! pattern)
1149 goto finish;
1150 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1151 if (! objset)
1152 goto finish;
1153 fontset = FcFontList (NULL, pattern, objset);
1154 if (! fontset)
1155 goto finish;
1157 for (i = 0; i < fontset->nfont; i++)
1159 FcPattern *pat = fontset->fonts[i];
1160 FcChar8 *str;
1162 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1163 list = Fcons (intern ((char *) str), list);
1166 finish:
1167 if (objset) FcObjectSetDestroy (objset);
1168 if (fontset) FcFontSetDestroy (fontset);
1169 if (pattern) FcPatternDestroy (pattern);
1171 return list;
1175 static Lisp_Object
1176 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1178 struct ftfont_info *ftfont_info;
1179 struct font *font;
1180 struct ftfont_cache_data *cache_data;
1181 FT_Face ft_face;
1182 FT_Size ft_size;
1183 FT_UInt size;
1184 Lisp_Object val, filename, idx, cache, font_object;
1185 bool scalable;
1186 int spacing;
1187 char name[256];
1188 int i, len;
1189 int upEM;
1191 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1192 if (! CONSP (val))
1193 return Qnil;
1194 val = XCDR (val);
1195 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1196 if (NILP (cache))
1197 return Qnil;
1198 filename = XCAR (val);
1199 idx = XCDR (val);
1200 val = XCDR (cache);
1201 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1202 ft_face = cache_data->ft_face;
1203 if (XSAVE_INTEGER (val, 1) > 0)
1205 /* FT_Face in this cache is already used by the different size. */
1206 if (FT_New_Size (ft_face, &ft_size) != 0)
1207 return Qnil;
1208 if (FT_Activate_Size (ft_size) != 0)
1210 FT_Done_Size (ft_size);
1211 return Qnil;
1214 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1215 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1216 if (size == 0)
1217 size = pixel_size;
1218 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1220 if (XSAVE_INTEGER (val, 1) == 0)
1221 FT_Done_Face (ft_face);
1222 return Qnil;
1225 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
1226 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
1227 len = font_unparse_xlfd (entity, size, name, 256);
1228 if (len > 0)
1229 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
1230 len = font_unparse_fcname (entity, size, name, 256);
1231 if (len > 0)
1232 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
1233 else
1234 ASET (font_object, FONT_FULLNAME_INDEX,
1235 AREF (font_object, FONT_NAME_INDEX));
1236 ASET (font_object, FONT_FILE_INDEX, filename);
1237 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
1238 font = XFONT_OBJECT (font_object);
1239 ftfont_info = (struct ftfont_info *) font;
1240 ftfont_info->ft_size = ft_face->size;
1241 ftfont_info->index = XINT (idx);
1242 #ifdef HAVE_LIBOTF
1243 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1244 ftfont_info->otf = NULL;
1245 #endif /* HAVE_LIBOTF */
1246 /* This means that there's no need of transformation. */
1247 ftfont_info->matrix.xx = 0;
1248 font->pixel_size = size;
1249 font->driver = &ftfont_driver;
1250 font->encoding_charset = font->repertory_charset = -1;
1252 upEM = ft_face->units_per_EM;
1253 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1254 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1255 if (scalable)
1257 font->ascent = ft_face->ascender * size / upEM;
1258 font->descent = - ft_face->descender * size / upEM;
1259 font->height = ft_face->height * size / upEM;
1261 else
1263 font->ascent = ft_face->size->metrics.ascender >> 6;
1264 font->descent = - ft_face->size->metrics.descender >> 6;
1265 font->height = ft_face->size->metrics.height >> 6;
1267 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1268 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1269 else
1270 spacing = FC_PROPORTIONAL;
1271 if (spacing != FC_PROPORTIONAL
1272 #ifdef FC_DUAL
1273 && spacing != FC_DUAL
1274 #endif /* FC_DUAL */
1276 font->min_width = font->average_width = font->space_width
1277 = (scalable ? ft_face->max_advance_width * size / upEM
1278 : ft_face->size->metrics.max_advance >> 6);
1279 else
1281 int n;
1283 font->min_width = font->average_width = font->space_width = 0;
1284 for (i = 32, n = 0; i < 127; i++)
1285 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1287 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1289 if (this_width > 0
1290 && (! font->min_width || font->min_width > this_width))
1291 font->min_width = this_width;
1292 if (i == 32)
1293 font->space_width = this_width;
1294 font->average_width += this_width;
1295 n++;
1297 if (n > 0)
1298 font->average_width /= n;
1301 font->baseline_offset = 0;
1302 font->relative_compose = 0;
1303 font->default_ascent = 0;
1304 font->vertical_centering = 0;
1305 if (scalable)
1307 font->underline_position = -ft_face->underline_position * size / upEM;
1308 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1310 else
1312 font->underline_position = -1;
1313 font->underline_thickness = 0;
1316 return font_object;
1319 static void
1320 ftfont_close (struct frame *f, struct font *font)
1322 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1323 Lisp_Object val, cache;
1325 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1326 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1327 eassert (CONSP (cache));
1328 val = XCDR (cache);
1329 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1330 if (XSAVE_INTEGER (val, 1) == 0)
1332 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1334 FT_Done_Face (cache_data->ft_face);
1335 #ifdef HAVE_LIBOTF
1336 if (ftfont_info->otf)
1337 OTF_close (ftfont_info->otf);
1338 #endif
1339 cache_data->ft_face = NULL;
1341 else
1342 FT_Done_Size (ftfont_info->ft_size);
1345 static int
1346 ftfont_has_char (Lisp_Object font, int c)
1348 struct charset *cs = NULL;
1350 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1351 && charset_jisx0208 >= 0)
1352 cs = CHARSET_FROM_ID (charset_jisx0208);
1353 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1354 && charset_ksc5601 >= 0)
1355 cs = CHARSET_FROM_ID (charset_ksc5601);
1356 if (cs)
1357 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1359 if (FONT_ENTITY_P (font))
1361 FcCharSet *charset = ftfont_get_fc_charset (font);
1363 return (FcCharSetHasChar (charset, c) == FcTrue);
1365 else
1367 struct ftfont_info *ftfont_info;
1369 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1370 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1371 != 0);
1375 static unsigned
1376 ftfont_encode_char (struct font *font, int c)
1378 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1379 FT_Face ft_face = ftfont_info->ft_size->face;
1380 FT_ULong charcode = c;
1381 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1383 return (code > 0 ? code : FONT_INVALID_CODE);
1386 static int
1387 ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
1389 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1390 FT_Face ft_face = ftfont_info->ft_size->face;
1391 int width = 0;
1392 int i;
1393 bool first;
1395 if (ftfont_info->ft_size != ft_face->size)
1396 FT_Activate_Size (ftfont_info->ft_size);
1397 if (metrics)
1398 memset (metrics, 0, sizeof (struct font_metrics));
1399 for (i = 0, first = 1; i < nglyphs; i++)
1401 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1403 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1405 if (first)
1407 if (metrics)
1409 metrics->lbearing = m->horiBearingX >> 6;
1410 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1411 metrics->ascent = m->horiBearingY >> 6;
1412 metrics->descent = (m->height - m->horiBearingY) >> 6;
1414 first = 0;
1416 if (metrics)
1418 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1419 metrics->lbearing = width + (m->horiBearingX >> 6);
1420 if (metrics->rbearing
1421 < width + ((m->horiBearingX + m->width) >> 6))
1422 metrics->rbearing
1423 = width + ((m->horiBearingX + m->width) >> 6);
1424 if (metrics->ascent < (m->horiBearingY >> 6))
1425 metrics->ascent = m->horiBearingY >> 6;
1426 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1427 metrics->descent = (m->height - m->horiBearingY) >> 6;
1429 width += m->horiAdvance >> 6;
1431 else
1433 width += font->space_width;
1436 if (metrics)
1437 metrics->width = width;
1439 return width;
1442 static int
1443 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1445 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1446 FT_Face ft_face = ftfont_info->ft_size->face;
1447 FT_Int32 load_flags = FT_LOAD_RENDER;
1449 if (ftfont_info->ft_size != ft_face->size)
1450 FT_Activate_Size (ftfont_info->ft_size);
1451 if (bits_per_pixel == 1)
1453 #ifdef FT_LOAD_TARGET_MONO
1454 load_flags |= FT_LOAD_TARGET_MONO;
1455 #else
1456 load_flags |= FT_LOAD_MONOCHROME;
1457 #endif
1459 else if (bits_per_pixel != 8)
1460 /* We don't support such a rendering. */
1461 return -1;
1463 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1464 return -1;
1465 bitmap->bits_per_pixel
1466 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1467 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1468 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1469 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1470 : -1);
1471 if (bitmap->bits_per_pixel < 0)
1472 /* We don't support that kind of pixel mode. */
1473 return -1;
1474 bitmap->rows = ft_face->glyph->bitmap.rows;
1475 bitmap->width = ft_face->glyph->bitmap.width;
1476 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1477 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1478 bitmap->left = ft_face->glyph->bitmap_left;
1479 bitmap->top = ft_face->glyph->bitmap_top;
1480 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1481 bitmap->extra = NULL;
1483 return 0;
1486 static int
1487 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1488 int *x, int *y)
1490 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1491 FT_Face ft_face = ftfont_info->ft_size->face;
1493 if (ftfont_info->ft_size != ft_face->size)
1494 FT_Activate_Size (ftfont_info->ft_size);
1495 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1496 return -1;
1497 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1498 return -1;
1499 if (idx >= ft_face->glyph->outline.n_points)
1500 return -1;
1501 *x = ft_face->glyph->outline.points[idx].x;
1502 *y = ft_face->glyph->outline.points[idx].y;
1503 return 0;
1506 #ifdef HAVE_LIBOTF
1508 static Lisp_Object
1509 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1511 Lisp_Object scripts, langsyses, features, sym;
1512 int i, j, k, l;
1514 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1516 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1518 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1520 OTF_LangSys *otf_langsys;
1522 if (j >= 0)
1523 otf_langsys = otf_script->LangSys + j;
1524 else if (otf_script->DefaultLangSysOffset)
1525 otf_langsys = &otf_script->DefaultLangSys;
1526 else
1527 break;
1529 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1531 l = otf_langsys->FeatureIndex[k];
1532 if (l >= gsub_gpos->FeatureList.FeatureCount)
1533 continue;
1534 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1535 features = Fcons (sym, features);
1537 if (j >= 0)
1538 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1539 else
1540 sym = Qnil;
1541 langsyses = Fcons (Fcons (sym, features), langsyses);
1544 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1545 scripts = Fcons (Fcons (sym, langsyses), scripts);
1547 return scripts;
1552 static Lisp_Object
1553 ftfont_otf_capability (struct font *font)
1555 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1556 OTF *otf = ftfont_get_otf (ftfont_info);
1557 Lisp_Object gsub_gpos;
1559 if (! otf)
1560 return Qnil;
1561 gsub_gpos = Fcons (Qnil, Qnil);
1562 if (OTF_get_table (otf, "GSUB") == 0
1563 && otf->gsub->FeatureList.FeatureCount > 0)
1564 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1565 if (OTF_get_table (otf, "GPOS") == 0
1566 && otf->gpos->FeatureList.FeatureCount > 0)
1567 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1568 return gsub_gpos;
1571 #ifdef HAVE_M17N_FLT
1573 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1574 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1575 /* We can use the new feature of libotf and m17n-flt to handle the
1576 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1577 some Agian scripts. */
1578 #define M17N_FLT_USE_NEW_FEATURE
1579 #endif
1581 struct MFLTFontFT
1583 MFLTFont flt_font;
1584 struct font *font;
1585 FT_Face ft_face;
1586 OTF *otf;
1587 FT_Matrix *matrix;
1590 static int
1591 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1592 int from, int to)
1594 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1595 FT_Face ft_face = flt_font_ft->ft_face;
1596 MFLTGlyph *g;
1598 for (g = gstring->glyphs + from; from < to; g++, from++)
1599 if (! g->encoded)
1601 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1603 g->code = code > 0 ? code : FONT_INVALID_CODE;
1604 g->encoded = 1;
1606 return 0;
1609 /* Operators for 26.6 fixed fractional pixel format */
1611 #define FLOOR(x) ((x) & -64)
1612 #define CEIL(x) (((x)+63) & -64)
1613 #define ROUND(x) (((x)+32) & -64)
1615 static int
1616 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1617 int from, int to)
1619 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1620 FT_Face ft_face = flt_font_ft->ft_face;
1621 MFLTGlyph *g;
1623 for (g = gstring->glyphs + from; from < to; g++, from++)
1624 if (! g->measured)
1626 if (g->code != FONT_INVALID_CODE)
1628 FT_Glyph_Metrics *m;
1630 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1631 emacs_abort ();
1632 m = &ft_face->glyph->metrics;
1633 if (flt_font_ft->matrix)
1635 FT_Vector v[4];
1636 int i;
1638 v[0].x = v[1].x = m->horiBearingX;
1639 v[2].x = v[3].x = m->horiBearingX + m->width;
1640 v[0].y = v[2].y = m->horiBearingY;
1641 v[1].y = v[3].y = m->horiBearingY - m->height;
1642 for (i = 0; i < 4; i++)
1643 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1644 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1645 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1646 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1647 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1649 else
1651 g->lbearing = FLOOR (m->horiBearingX);
1652 g->rbearing = CEIL (m->horiBearingX + m->width);
1653 g->ascent = CEIL (m->horiBearingY);
1654 g->descent = - FLOOR (m->horiBearingY - m->height);
1656 g->xadv = ROUND (ft_face->glyph->advance.x);
1658 else
1660 g->lbearing = 0;
1661 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1662 g->ascent = flt_font_ft->font->ascent << 6;
1663 g->descent = flt_font_ft->font->descent << 6;
1665 g->yadv = 0;
1666 g->measured = 1;
1668 return 0;
1671 static int
1672 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1674 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1676 #define FEATURE_ANY(IDX) \
1677 (spec->features[IDX] \
1678 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1680 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1681 OTF *otf = flt_font_ft->otf;
1682 OTF_Tag *tags;
1683 int i, n;
1684 bool negative;
1686 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1687 /* Return true iff any of GSUB or GPOS support the script (and
1688 language). */
1689 return (otf
1690 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1691 NULL, 0) > 0
1692 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1693 NULL, 0) > 0));
1695 for (i = 0; i < 2; i++)
1696 if (! FEATURE_ANY (i))
1698 if (FEATURE_NONE (i))
1700 if (otf
1701 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1702 NULL, 0) > 0)
1703 return 0;
1704 continue;
1706 if (spec->features[i][0] == 0xFFFFFFFF)
1708 if (! otf
1709 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1710 NULL, 0) <= 0)
1711 continue;
1713 else if (! otf)
1714 return 0;
1715 for (n = 1; spec->features[i][n]; n++);
1716 tags = alloca (sizeof (OTF_Tag) * n);
1717 for (n = 0, negative = 0; spec->features[i][n]; n++)
1719 if (spec->features[i][n] == 0xFFFFFFFF)
1720 negative = 1;
1721 else if (negative)
1722 tags[n - 1] = spec->features[i][n] | 0x80000000;
1723 else
1724 tags[n] = spec->features[i][n];
1726 #ifdef M17N_FLT_USE_NEW_FEATURE
1727 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1728 tags, n - negative) != 1)
1729 return 0;
1730 #else /* not M17N_FLT_USE_NEW_FEATURE */
1731 if (n - negative > 0
1732 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1733 tags, n - negative) != 1)
1734 return 0;
1735 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1737 return 1;
1738 #undef FEATURE_NONE
1739 #undef FEATURE_ANY
1742 #define DEVICE_DELTA(table, size) \
1743 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1744 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1745 : 0)
1747 static void
1748 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1749 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1751 if (anchor->AnchorFormat == 2)
1753 FT_Outline *outline;
1754 int ap = anchor->f.f1.AnchorPoint;
1756 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1757 outline = &ft_face->glyph->outline;
1758 if (ap < outline->n_points)
1760 *x = outline->points[ap].x << 6;
1761 *y = outline->points[ap].y << 6;
1764 else if (anchor->AnchorFormat == 3)
1766 if (anchor->f.f2.XDeviceTable.offset
1767 && anchor->f.f2.XDeviceTable.DeltaValue)
1768 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1769 if (anchor->f.f2.YDeviceTable.offset
1770 && anchor->f.f2.YDeviceTable.DeltaValue)
1771 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1775 static OTF_GlyphString otf_gstring;
1777 static void
1778 setup_otf_gstring (int size)
1780 if (otf_gstring.size < size)
1782 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1783 size, sizeof (OTF_Glyph));
1784 otf_gstring.size = size;
1786 otf_gstring.used = size;
1787 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1790 #ifdef M17N_FLT_USE_NEW_FEATURE
1792 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1793 #define PACK_OTF_TAG(TAG) \
1794 ((((TAG) & 0x7F000000) >> 3) \
1795 | (((TAG) & 0x7F0000) >> 2) \
1796 | (((TAG) & 0x7F00) >> 1) \
1797 | ((TAG) & 0x7F))
1799 /* Assuming that FONT is an OpenType font, apply OpenType features
1800 specified in SPEC on glyphs between FROM and TO of IN, and record
1801 the lastly applied feature in each glyph of IN. If OUT is not
1802 NULL, append the resulting glyphs to OUT while storing glyph
1803 position adjustment information in ADJUSTMENT. */
1805 static int
1806 ftfont_drive_otf (MFLTFont *font,
1807 MFLTOtfSpec *spec,
1808 MFLTGlyphString *in,
1809 int from,
1810 int to,
1811 MFLTGlyphString *out,
1812 MFLTGlyphAdjustment *adjustment)
1814 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1815 FT_Face ft_face = flt_font_ft->ft_face;
1816 OTF *otf = flt_font_ft->otf;
1817 int len = to - from;
1818 int i, j, gidx;
1819 OTF_Glyph *otfg;
1820 char script[5], *langsys = NULL;
1821 char *gsub_features = NULL, *gpos_features = NULL;
1822 OTF_Feature *features;
1824 if (len == 0)
1825 return from;
1826 OTF_tag_name (spec->script, script);
1827 if (spec->langsys)
1829 langsys = alloca (5);
1830 OTF_tag_name (spec->langsys, langsys);
1832 for (i = 0; i < 2; i++)
1834 char *p;
1836 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1838 for (j = 0; spec->features[i][j]; j++);
1839 if (i == 0)
1840 p = gsub_features = alloca (6 * j);
1841 else
1842 p = gpos_features = alloca (6 * j);
1843 for (j = 0; spec->features[i][j]; j++)
1845 if (spec->features[i][j] == 0xFFFFFFFF)
1846 *p++ = '*', *p++ = ',';
1847 else
1849 OTF_tag_name (spec->features[i][j], p);
1850 p[4] = ',';
1851 p += 5;
1854 *--p = '\0';
1858 setup_otf_gstring (len);
1859 for (i = 0; i < len; i++)
1861 otf_gstring.glyphs[i].c = in->glyphs[from + i].c & 0x11FFFF;
1862 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1865 OTF_drive_gdef (otf, &otf_gstring);
1866 gidx = out ? out->used : from;
1868 if (gsub_features && out)
1870 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1871 gsub_features) < 0)
1872 goto simple_copy;
1873 if (out->allocated < out->used + otf_gstring.used)
1874 return -2;
1875 features = otf->gsub->FeatureList.Feature;
1876 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1878 MFLTGlyph *g;
1879 int min_from, max_to;
1880 int feature_idx = otfg->positioning_type >> 4;
1882 g = out->glyphs + out->used;
1883 *g = in->glyphs[from + otfg->f.index.from];
1884 if (g->code != otfg->glyph_id)
1886 g->c = 0;
1887 g->code = otfg->glyph_id;
1888 g->measured = 0;
1890 out->used++;
1891 min_from = g->from;
1892 max_to = g->to;
1893 if (otfg->f.index.from < otfg->f.index.to)
1895 /* OTFG substitutes multiple glyphs in IN. */
1896 for (j = from + otfg->f.index.from + 1;
1897 j <= from + otfg->f.index.to; j++)
1899 if (min_from > in->glyphs[j].from)
1900 min_from = in->glyphs[j].from;
1901 if (max_to < in->glyphs[j].to)
1902 max_to = in->glyphs[j].to;
1904 g->from = min_from;
1905 g->to = max_to;
1907 if (feature_idx)
1909 unsigned int tag = features[feature_idx - 1].FeatureTag;
1910 tag = PACK_OTF_TAG (tag);
1911 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1913 for (i++, otfg++; (i < otf_gstring.used
1914 && otfg->f.index.from == otfg[-1].f.index.from);
1915 i++, otfg++)
1917 g = out->glyphs + out->used;
1918 *g = in->glyphs[from + otfg->f.index.to];
1919 if (g->code != otfg->glyph_id)
1921 g->c = 0;
1922 g->code = otfg->glyph_id;
1923 g->measured = 0;
1925 feature_idx = otfg->positioning_type >> 4;
1926 if (feature_idx)
1928 unsigned int tag = features[feature_idx - 1].FeatureTag;
1929 tag = PACK_OTF_TAG (tag);
1930 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1932 out->used++;
1936 else if (gsub_features)
1938 /* Just for checking which features will be applied. */
1939 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1940 gsub_features) < 0)
1941 goto simple_copy;
1942 features = otf->gsub->FeatureList.Feature;
1943 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1944 otfg++)
1946 int feature_idx = otfg->positioning_type >> 4;
1948 if (feature_idx)
1950 unsigned int tag = features[feature_idx - 1].FeatureTag;
1951 tag = PACK_OTF_TAG (tag);
1952 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1954 MFLTGlyph *g = in->glyphs + (from + j);
1955 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1960 else if (out)
1962 if (out->allocated < out->used + len)
1963 return -2;
1964 for (i = 0; i < len; i++)
1965 out->glyphs[out->used++] = in->glyphs[from + i];
1968 if (gpos_features && out)
1970 MFLTGlyph *base = NULL, *mark = NULL, *g;
1971 int x_ppem, y_ppem, x_scale, y_scale;
1973 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1974 gpos_features) < 0)
1975 return to;
1976 features = otf->gpos->FeatureList.Feature;
1977 x_ppem = ft_face->size->metrics.x_ppem;
1978 y_ppem = ft_face->size->metrics.y_ppem;
1979 x_scale = ft_face->size->metrics.x_scale;
1980 y_scale = ft_face->size->metrics.y_scale;
1982 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1983 i < otf_gstring.used; i++, otfg++, g++)
1985 MFLTGlyph *prev;
1986 int feature_idx = otfg->positioning_type >> 4;
1988 if (feature_idx)
1990 unsigned int tag = features[feature_idx - 1].FeatureTag;
1991 tag = PACK_OTF_TAG (tag);
1992 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1995 if (! otfg->glyph_id)
1996 continue;
1997 switch (otfg->positioning_type & 0xF)
1999 case 0:
2000 break;
2001 case 1: /* Single */
2002 case 2: /* Pair */
2004 int format = otfg->f.f1.format;
2006 if (format & OTF_XPlacement)
2007 adjustment[i].xoff
2008 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2009 if (format & OTF_XPlaDevice)
2010 adjustment[i].xoff
2011 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2012 if (format & OTF_YPlacement)
2013 adjustment[i].yoff
2014 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2015 if (format & OTF_YPlaDevice)
2016 adjustment[i].yoff
2017 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2018 if (format & OTF_XAdvance)
2019 adjustment[i].xadv
2020 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2021 if (format & OTF_XAdvDevice)
2022 adjustment[i].xadv
2023 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2024 if (format & OTF_YAdvance)
2025 adjustment[i].yadv
2026 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2027 if (format & OTF_YAdvDevice)
2028 adjustment[i].yadv
2029 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2030 adjustment[i].set = 1;
2032 break;
2033 case 3: /* Cursive */
2034 /* Not yet supported. */
2035 break;
2036 case 4: /* Mark-to-Base */
2037 case 5: /* Mark-to-Ligature */
2038 if (! base)
2039 break;
2040 prev = base;
2041 goto label_adjust_anchor;
2042 default: /* i.e. case 6 Mark-to-Mark */
2043 if (! mark)
2044 break;
2045 prev = mark;
2047 label_adjust_anchor:
2049 int base_x, base_y, mark_x, mark_y;
2050 int this_from, this_to;
2052 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2053 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2054 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2055 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2057 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2058 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2059 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2060 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2061 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2062 x_ppem, y_ppem, &mark_x, &mark_y);
2063 adjustment[i].xoff = (base_x - mark_x);
2064 adjustment[i].yoff = - (base_y - mark_y);
2065 adjustment[i].back = (g - prev);
2066 adjustment[i].xadv = 0;
2067 adjustment[i].advance_is_absolute = 1;
2068 adjustment[i].set = 1;
2069 this_from = g->from;
2070 this_to = g->to;
2071 for (j = 0; prev + j < g; j++)
2073 if (this_from > prev[j].from)
2074 this_from = prev[j].from;
2075 if (this_to < prev[j].to)
2076 this_to = prev[j].to;
2078 for (; prev <= g; prev++)
2080 prev->from = this_from;
2081 prev->to = this_to;
2085 if (otfg->GlyphClass == OTF_GlyphClass0)
2086 base = mark = g;
2087 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2088 mark = g;
2089 else
2090 base = g;
2093 else if (gpos_features)
2095 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2096 gpos_features) < 0)
2097 return to;
2098 features = otf->gpos->FeatureList.Feature;
2099 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2100 i++, otfg++)
2101 if (otfg->positioning_type & 0xF)
2103 int feature_idx = otfg->positioning_type >> 4;
2105 if (feature_idx)
2107 unsigned int tag = features[feature_idx - 1].FeatureTag;
2108 tag = PACK_OTF_TAG (tag);
2109 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2111 MFLTGlyph *g = in->glyphs + (from + j);
2112 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2117 return to;
2119 simple_copy:
2120 if (! out)
2121 return to;
2122 if (out->allocated < out->used + len)
2123 return -2;
2124 font->get_metrics (font, in, from, to);
2125 memcpy (out->glyphs + out->used, in->glyphs + from,
2126 sizeof (MFLTGlyph) * len);
2127 out->used += len;
2128 return to;
2131 static int
2132 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2133 MFLTGlyphString *in, int from, int to)
2135 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2138 #else /* not M17N_FLT_USE_NEW_FEATURE */
2140 static int
2141 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2142 int from, int to,
2143 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2145 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2146 FT_Face ft_face = flt_font_ft->ft_face;
2147 OTF *otf = flt_font_ft->otf;
2148 int len = to - from;
2149 int i, j, gidx;
2150 OTF_Glyph *otfg;
2151 char script[5], *langsys = NULL;
2152 char *gsub_features = NULL, *gpos_features = NULL;
2154 if (len == 0)
2155 return from;
2156 OTF_tag_name (spec->script, script);
2157 if (spec->langsys)
2159 langsys = alloca (5);
2160 OTF_tag_name (spec->langsys, langsys);
2162 for (i = 0; i < 2; i++)
2164 char *p;
2166 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2168 for (j = 0; spec->features[i][j]; j++);
2169 if (i == 0)
2170 p = gsub_features = alloca (6 * j);
2171 else
2172 p = gpos_features = alloca (6 * j);
2173 for (j = 0; spec->features[i][j]; j++)
2175 if (spec->features[i][j] == 0xFFFFFFFF)
2176 *p++ = '*', *p++ = ',';
2177 else
2179 OTF_tag_name (spec->features[i][j], p);
2180 p[4] = ',';
2181 p += 5;
2184 *--p = '\0';
2188 setup_otf_gstring (len);
2189 for (i = 0; i < len; i++)
2191 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2192 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2195 OTF_drive_gdef (otf, &otf_gstring);
2196 gidx = out->used;
2198 if (gsub_features)
2200 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2201 < 0)
2202 goto simple_copy;
2203 if (out->allocated < out->used + otf_gstring.used)
2204 return -2;
2205 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2207 MFLTGlyph *g;
2208 int min_from, max_to;
2209 int j;
2211 g = out->glyphs + out->used;
2212 *g = in->glyphs[from + otfg->f.index.from];
2213 if (g->code != otfg->glyph_id)
2215 g->c = 0;
2216 g->code = otfg->glyph_id;
2217 g->measured = 0;
2219 out->used++;
2220 min_from = g->from;
2221 max_to = g->to;
2222 if (otfg->f.index.from < otfg->f.index.to)
2224 /* OTFG substitutes multiple glyphs in IN. */
2225 for (j = from + otfg->f.index.from + 1;
2226 j <= from + otfg->f.index.to; j++)
2228 if (min_from > in->glyphs[j].from)
2229 min_from = in->glyphs[j].from;
2230 if (max_to < in->glyphs[j].to)
2231 max_to = in->glyphs[j].to;
2233 g->from = min_from;
2234 g->to = max_to;
2236 for (i++, otfg++; (i < otf_gstring.used
2237 && otfg->f.index.from == otfg[-1].f.index.from);
2238 i++, otfg++)
2240 g = out->glyphs + out->used;
2241 *g = in->glyphs[from + otfg->f.index.to];
2242 if (g->code != otfg->glyph_id)
2244 g->c = 0;
2245 g->code = otfg->glyph_id;
2246 g->measured = 0;
2248 out->used++;
2252 else
2254 if (out->allocated < out->used + len)
2255 return -2;
2256 for (i = 0; i < len; i++)
2257 out->glyphs[out->used++] = in->glyphs[from + i];
2260 if (gpos_features)
2262 MFLTGlyph *base = NULL, *mark = NULL, *g;
2263 int x_ppem, y_ppem, x_scale, y_scale;
2265 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2266 < 0)
2267 return to;
2269 x_ppem = ft_face->size->metrics.x_ppem;
2270 y_ppem = ft_face->size->metrics.y_ppem;
2271 x_scale = ft_face->size->metrics.x_scale;
2272 y_scale = ft_face->size->metrics.y_scale;
2274 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2275 i < otf_gstring.used; i++, otfg++, g++)
2277 MFLTGlyph *prev;
2279 if (! otfg->glyph_id)
2280 continue;
2281 switch (otfg->positioning_type)
2283 case 0:
2284 break;
2285 case 1: /* Single */
2286 case 2: /* Pair */
2288 int format = otfg->f.f1.format;
2290 if (format & OTF_XPlacement)
2291 adjustment[i].xoff
2292 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2293 if (format & OTF_XPlaDevice)
2294 adjustment[i].xoff
2295 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2296 if (format & OTF_YPlacement)
2297 adjustment[i].yoff
2298 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2299 if (format & OTF_YPlaDevice)
2300 adjustment[i].yoff
2301 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2302 if (format & OTF_XAdvance)
2303 adjustment[i].xadv
2304 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2305 if (format & OTF_XAdvDevice)
2306 adjustment[i].xadv
2307 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2308 if (format & OTF_YAdvance)
2309 adjustment[i].yadv
2310 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2311 if (format & OTF_YAdvDevice)
2312 adjustment[i].yadv
2313 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2314 adjustment[i].set = 1;
2316 break;
2317 case 3: /* Cursive */
2318 /* Not yet supported. */
2319 break;
2320 case 4: /* Mark-to-Base */
2321 case 5: /* Mark-to-Ligature */
2322 if (! base)
2323 break;
2324 prev = base;
2325 goto label_adjust_anchor;
2326 default: /* i.e. case 6 Mark-to-Mark */
2327 if (! mark)
2328 break;
2329 prev = mark;
2331 label_adjust_anchor:
2333 int base_x, base_y, mark_x, mark_y;
2334 int this_from, this_to;
2336 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2337 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2338 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2339 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2341 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2342 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2343 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2344 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2345 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2346 x_ppem, y_ppem, &mark_x, &mark_y);
2347 adjustment[i].xoff = (base_x - mark_x);
2348 adjustment[i].yoff = - (base_y - mark_y);
2349 adjustment[i].back = (g - prev);
2350 adjustment[i].xadv = 0;
2351 adjustment[i].advance_is_absolute = 1;
2352 adjustment[i].set = 1;
2353 this_from = g->from;
2354 this_to = g->to;
2355 for (j = 0; prev + j < g; j++)
2357 if (this_from > prev[j].from)
2358 this_from = prev[j].from;
2359 if (this_to < prev[j].to)
2360 this_to = prev[j].to;
2362 for (; prev <= g; prev++)
2364 prev->from = this_from;
2365 prev->to = this_to;
2369 if (otfg->GlyphClass == OTF_GlyphClass0)
2370 base = mark = g;
2371 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2372 mark = g;
2373 else
2374 base = g;
2377 return to;
2379 simple_copy:
2380 if (out->allocated < out->used + len)
2381 return -2;
2382 font->get_metrics (font, in, from, to);
2383 memcpy (out->glyphs + out->used, in->glyphs + from,
2384 sizeof (MFLTGlyph) * len);
2385 out->used += len;
2386 return to;
2389 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2391 static MFLTGlyphString gstring;
2393 static bool m17n_flt_initialized;
2395 static Lisp_Object
2396 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2397 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2399 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2400 ptrdiff_t i;
2401 struct MFLTFontFT flt_font_ft;
2402 MFLT *flt = NULL;
2403 bool with_variation_selector = 0;
2405 if (! m17n_flt_initialized)
2407 M17N_INIT ();
2408 #ifdef M17N_FLT_USE_NEW_FEATURE
2409 mflt_enable_new_feature = 1;
2410 mflt_try_otf = ftfont_try_otf;
2411 #endif /* M17N_FLT_USE_NEW_FEATURE */
2412 m17n_flt_initialized = 1;
2415 for (i = 0; i < len; i++)
2417 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2418 int c;
2420 if (NILP (g))
2421 break;
2422 c = LGLYPH_CHAR (g);
2423 if (CHAR_VARIATION_SELECTOR_P (c))
2424 with_variation_selector = 1;
2427 len = i;
2429 if (with_variation_selector)
2431 setup_otf_gstring (len);
2432 for (i = 0; i < len; i++)
2434 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2436 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2437 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2438 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2440 OTF_drive_cmap (otf, &otf_gstring);
2441 for (i = 0; i < otf_gstring.used; i++)
2443 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2444 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2445 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2447 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2448 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2449 LGSTRING_SET_GLYPH (lgstring, i, g0);
2451 if (len > otf_gstring.used)
2453 len = otf_gstring.used;
2454 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2458 if (INT_MAX / 2 < len)
2459 memory_full (SIZE_MAX);
2461 if (gstring.allocated == 0)
2463 gstring.glyph_size = sizeof (MFLTGlyph);
2464 gstring.glyphs = xnmalloc (len * 2, sizeof *gstring.glyphs);
2465 gstring.allocated = len * 2;
2467 else if (gstring.allocated < len * 2)
2469 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2,
2470 sizeof *gstring.glyphs);
2471 gstring.allocated = len * 2;
2473 memset (gstring.glyphs, 0, len * sizeof *gstring.glyphs);
2474 for (i = 0; i < len; i++)
2476 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2478 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2479 if (with_variation_selector)
2481 gstring.glyphs[i].code = LGLYPH_CODE (g);
2482 gstring.glyphs[i].encoded = 1;
2486 gstring.used = len;
2487 gstring.r2l = 0;
2490 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2492 if (NILP (family))
2493 flt_font_ft.flt_font.family = Mnil;
2494 else
2495 flt_font_ft.flt_font.family
2496 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2498 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2499 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2500 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2501 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2502 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2503 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2504 flt_font_ft.flt_font.internal = NULL;
2505 flt_font_ft.font = font;
2506 flt_font_ft.ft_face = ft_face;
2507 flt_font_ft.otf = otf;
2508 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2509 if (len > 1
2510 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2511 /* A little bit ad hoc. Perhaps, shaper must get script and
2512 language information, and select a proper flt for them
2513 here. */
2514 flt = mflt_get (msymbol ("combining"));
2515 for (i = 0; i < 3; i++)
2517 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2518 if (result != -2)
2519 break;
2520 if (INT_MAX / 2 < gstring.allocated)
2521 memory_full (SIZE_MAX);
2522 gstring.glyphs = xnrealloc (gstring.glyphs,
2523 gstring.allocated, 2 * sizeof (MFLTGlyph));
2524 gstring.allocated *= 2;
2526 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2527 return Qnil;
2528 for (i = 0; i < gstring.used; i++)
2530 MFLTGlyph *g = gstring.glyphs + i;
2532 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2533 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2536 for (i = 0; i < gstring.used; i++)
2538 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2539 MFLTGlyph *g = gstring.glyphs + i;
2541 if (NILP (lglyph))
2543 lglyph = LGLYPH_NEW ();
2544 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2546 LGLYPH_SET_FROM (lglyph, g->from);
2547 LGLYPH_SET_TO (lglyph, g->to);
2548 LGLYPH_SET_CHAR (lglyph, g->c);
2549 LGLYPH_SET_CODE (lglyph, g->code);
2550 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2551 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2552 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2553 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2554 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2555 if (g->adjusted)
2557 Lisp_Object vec = make_uninit_vector (3);
2559 ASET (vec, 0, make_number (g->xoff >> 6));
2560 ASET (vec, 1, make_number (g->yoff >> 6));
2561 ASET (vec, 2, make_number (g->xadv >> 6));
2562 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2565 return make_number (i);
2568 Lisp_Object
2569 ftfont_shape (Lisp_Object lgstring)
2571 struct font *font;
2572 struct ftfont_info *ftfont_info;
2573 OTF *otf;
2575 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2576 ftfont_info = (struct ftfont_info *) font;
2577 otf = ftfont_get_otf (ftfont_info);
2578 if (! otf)
2579 return make_number (0);
2580 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2581 &ftfont_info->matrix);
2584 #endif /* HAVE_M17N_FLT */
2586 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2588 static int
2589 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2591 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2592 OTF *otf = ftfont_get_otf (ftfont_info);
2594 if (! otf)
2595 return 0;
2596 return OTF_get_variation_glyphs (otf, c, variations);
2599 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2600 #endif /* HAVE_LIBOTF */
2602 Lisp_Object
2603 ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
2605 FcChar8 *str;
2607 #ifdef FC_FONTFORMAT
2608 if (pattern)
2610 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2611 return Qnil;
2612 if (strcmp ((char *) str, "TrueType") == 0)
2613 return intern ("truetype");
2614 if (strcmp ((char *) str, "Type 1") == 0)
2615 return intern ("type1");
2616 if (strcmp ((char *) str, "PCF") == 0)
2617 return intern ("pcf");
2618 if (strcmp ((char *) str, "BDF") == 0)
2619 return intern ("bdf");
2621 #endif /* FC_FONTFORMAT */
2622 if (STRINGP (filename))
2624 int len = SBYTES (filename);
2626 if (len >= 4)
2628 str = (FcChar8 *) (SDATA (filename) + len - 4);
2629 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2630 return intern ("truetype");
2631 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2632 return intern ("type1");
2633 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2634 return intern ("pcf");
2635 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2636 return intern ("bdf");
2639 return intern ("unknown");
2642 static const char *const ftfont_booleans [] = {
2643 ":antialias",
2644 ":hinting",
2645 ":verticallayout",
2646 ":autohint",
2647 ":globaladvance",
2648 ":outline",
2649 ":scalable",
2650 ":minspace",
2651 ":embolden",
2652 NULL,
2655 static const char *const ftfont_non_booleans [] = {
2656 ":family",
2657 ":familylang",
2658 ":style",
2659 ":stylelang",
2660 ":fullname",
2661 ":fullnamelang",
2662 ":slant",
2663 ":weight",
2664 ":size",
2665 ":width",
2666 ":aspect",
2667 ":pixelsize",
2668 ":spacing",
2669 ":foundry",
2670 ":hintstyle",
2671 ":file",
2672 ":index",
2673 ":ftface",
2674 ":rasterizer",
2675 ":scale",
2676 ":dpi",
2677 ":rgba",
2678 ":lcdfilter",
2679 ":charset",
2680 ":lang",
2681 ":fontversion",
2682 ":capability",
2683 NULL,
2686 static void
2687 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2689 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2693 void
2694 syms_of_ftfont (void)
2696 DEFSYM (Qfreetype, "freetype");
2697 DEFSYM (Qmonospace, "monospace");
2698 DEFSYM (Qsans_serif, "sans-serif");
2699 DEFSYM (Qserif, "serif");
2700 DEFSYM (Qmono, "mono");
2701 DEFSYM (Qsans, "sans");
2702 DEFSYM (Qsans__serif, "sans serif");
2704 staticpro (&freetype_font_cache);
2705 freetype_font_cache = list1 (Qt);
2707 staticpro (&ftfont_generic_family_list);
2708 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2709 Fcons (Qsans_serif, Qt),
2710 Fcons (Qsans, Qt));
2712 staticpro (&ft_face_cache);
2713 ft_face_cache = Qnil;
2715 ftfont_driver.type = Qfreetype;
2716 register_font_driver (&ftfont_driver, NULL);