* lisp/window.el (with-displayed-buffer-window): New macro.
[emacs.git] / src / ftfont.c
blob7c5d01208d2425003ec21a33d1a2b779867f3368
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2014 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 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
92 static struct
94 /* registry name */
95 const char *name;
96 /* characters to distinguish the charset from the others */
97 int uniquifier[6];
98 /* additional constraint by language */
99 const char *lang;
100 /* set on demand */
101 FcCharSet *fc_charset;
102 } fc_charset_table[] =
103 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
104 { "iso8859-2", { 0x00A0, 0x010E }},
105 { "iso8859-3", { 0x00A0, 0x0108 }},
106 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
107 { "iso8859-5", { 0x00A0, 0x0401 }},
108 { "iso8859-6", { 0x00A0, 0x060C }},
109 { "iso8859-7", { 0x00A0, 0x0384 }},
110 { "iso8859-8", { 0x00A0, 0x05D0 }},
111 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
112 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
113 { "iso8859-11", { 0x00A0, 0x0E01 }},
114 { "iso8859-13", { 0x00A0, 0x201C }},
115 { "iso8859-14", { 0x00A0, 0x0174 }},
116 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
117 { "iso8859-16", { 0x00A0, 0x0218}},
118 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
119 { "big5-0", { 0xF6B1 }, "zh-tw" },
120 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
121 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
122 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
123 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
124 { "cns11643.1992-3", { 0x201A9 }},
125 { "cns11643.1992-4", { 0x20057 }},
126 { "cns11643.1992-5", { 0x20000 }},
127 { "cns11643.1992-6", { 0x20003 }},
128 { "cns11643.1992-7", { 0x20055 }},
129 { "gbk-0", { 0x4E06 }, "zh-cn"},
130 { "jisx0212.1990-0", { 0x4E44 }},
131 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
132 { "jisx0213.2000-2", { 0xFA49 }},
133 { "jisx0213.2004-1", { 0x20B9F }},
134 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
135 { "tis620.2529-1", { 0x0E01 }, "th"},
136 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
137 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
138 { "mulelao-1", { 0x0E81 }, "lo"},
139 { "unicode-sip", { 0x20000 }},
140 { NULL }
143 /* Dirty hack for handing ADSTYLE property.
145 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
146 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
147 "Oblique", "Italic", or any non-normal SWIDTH property names
148 (e.g. SemiCondensed) are appended. In addition, if there's no
149 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
150 "Regular" is used for FC_STYLE (see the function
151 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
153 Unfortunately this behavior is not documented, so the following
154 code may fail if FreeType changes the behavior in the future. */
156 static Lisp_Object
157 get_adstyle_property (FcPattern *p)
159 FcChar8 *fcstr;
160 char *str, *end;
161 Lisp_Object adstyle;
163 #ifdef FC_FONTFORMAT
164 if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
165 && xstrcasecmp ((char *) fcstr, "bdf") != 0
166 && xstrcasecmp ((char *) fcstr, "pcf") != 0)
167 /* Not a BDF nor PCF font. */
168 return Qnil;
169 #endif
170 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
171 return Qnil;
172 str = (char *) fcstr;
173 for (end = str; *end && *end != ' '; end++);
174 if (*end)
176 char *newstr = alloca (end - str + 1);
177 memcpy (newstr, str, end - str);
178 newstr[end - str] = '\0';
179 end = newstr + (end - str);
180 str = newstr;
182 if (xstrcasecmp (str, "Regular") == 0
183 || xstrcasecmp (str, "Bold") == 0
184 || xstrcasecmp (str, "Oblique") == 0
185 || xstrcasecmp (str, "Italic") == 0)
186 return Qnil;
187 adstyle = font_intern_prop (str, end - str, 1);
188 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
189 return Qnil;
190 return adstyle;
193 static Lisp_Object
194 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
196 Lisp_Object key, cache, entity;
197 FcChar8 *str;
198 char *file;
199 int idx;
200 int numeric;
201 double dbl;
202 FcBool b;
204 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
205 return Qnil;
206 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
207 return Qnil;
209 file = (char *) str;
210 key = Fcons (build_unibyte_string (file), make_number (idx));
211 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
212 entity = XCAR (cache);
213 if (! NILP (entity))
215 Lisp_Object val = font_make_entity ();
216 int i;
218 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
219 ASET (val, i, AREF (entity, i));
221 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
222 font_put_extra (val, QCfont_entity, key);
224 return val;
226 entity = font_make_entity ();
227 XSETCAR (cache, entity);
229 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
230 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
232 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
234 char *s = (char *) str;
235 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
237 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
239 char *s = (char *) str;
240 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
242 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
244 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
245 numeric = FC_WEIGHT_MEDIUM;
246 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
248 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
250 numeric += 100;
251 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
253 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
255 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
257 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
259 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
261 else
262 ASET (entity, FONT_SIZE_INDEX, make_number (0));
263 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
264 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
265 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
267 int dpi = dbl;
268 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
270 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
271 && b == FcTrue)
273 ASET (entity, FONT_SIZE_INDEX, make_number (0));
274 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
276 else
278 /* As this font is not scalable, perhaps this is a BDF or PCF
279 font. */
280 FT_Face ft_face;
282 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
283 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
284 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
286 BDF_PropertyRec rec;
288 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
289 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
290 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
291 FT_Done_Face (ft_face);
295 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
296 font_put_extra (entity, QCfont_entity, key);
297 return entity;
301 static Lisp_Object ftfont_generic_family_list;
303 static Lisp_Object
304 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
306 Lisp_Object slot;
307 FcPattern *match;
308 FcResult result;
309 FcLangSet *langset;
311 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
312 if (EQ (family, Qmono))
313 family = Qmonospace;
314 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
315 family = Qsans_serif;
316 slot = assq_no_quit (family, ftfont_generic_family_list);
317 if (! CONSP (slot))
318 return Qnil;
319 if (! EQ (XCDR (slot), Qt))
320 return XCDR (slot);
321 pattern = FcPatternDuplicate (pattern);
322 if (! pattern)
323 goto err;
324 FcPatternDel (pattern, FC_FOUNDRY);
325 FcPatternDel (pattern, FC_FAMILY);
326 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
327 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
329 /* This is to avoid the effect of locale. */
330 static const FcChar8 lang[] = "en";
331 langset = FcLangSetCreate ();
332 FcLangSetAdd (langset, lang);
333 FcPatternAddLangSet (pattern, FC_LANG, langset);
334 FcLangSetDestroy (langset);
336 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
337 FcDefaultSubstitute (pattern);
338 match = FcFontMatch (NULL, pattern, &result);
339 if (match)
341 FcChar8 *fam;
343 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
344 family = intern ((char *) fam);
346 else
347 family = Qnil;
348 XSETCDR (slot, family);
349 if (match) FcPatternDestroy (match);
350 err:
351 if (pattern) FcPatternDestroy (pattern);
352 return family;
355 struct ftfont_cache_data
357 FT_Face ft_face;
358 FcCharSet *fc_charset;
361 static Lisp_Object
362 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
364 Lisp_Object cache, val, entity;
365 struct ftfont_cache_data *cache_data;
367 if (FONT_ENTITY_P (key))
369 entity = key;
370 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
371 eassert (CONSP (val));
372 key = XCDR (val);
374 else
375 entity = Qnil;
377 if (NILP (ft_face_cache))
378 cache = Qnil;
379 else
380 cache = Fgethash (key, ft_face_cache, Qnil);
381 if (NILP (cache))
383 if (NILP (ft_face_cache))
385 Lisp_Object args[2];
387 args[0] = QCtest;
388 args[1] = Qequal;
389 ft_face_cache = Fmake_hash_table (2, args);
391 cache_data = xmalloc (sizeof *cache_data);
392 cache_data->ft_face = NULL;
393 cache_data->fc_charset = NULL;
394 val = make_save_ptr_int (cache_data, 0);
395 cache = Fcons (Qnil, val);
396 Fputhash (key, cache, ft_face_cache);
398 else
400 val = XCDR (cache);
401 cache_data = XSAVE_POINTER (val, 0);
404 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
405 return cache;
407 if (cache_for == FTFONT_CACHE_FOR_FACE
408 ? ! cache_data->ft_face : ! cache_data->fc_charset)
410 char *filename = SSDATA (XCAR (key));
411 int idx = XINT (XCDR (key));
413 if (cache_for == FTFONT_CACHE_FOR_FACE)
415 if (! ft_library
416 && FT_Init_FreeType (&ft_library) != 0)
417 return Qnil;
418 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
419 != 0)
420 return Qnil;
422 else
424 FcPattern *pat = NULL;
425 FcFontSet *fontset = NULL;
426 FcObjectSet *objset = NULL;
427 FcCharSet *charset = NULL;
429 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
430 FC_INDEX, FcTypeInteger, idx, NULL);
431 if (! pat)
432 goto finish;
433 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
434 if (! objset)
435 goto finish;
436 fontset = FcFontList (NULL, pat, objset);
437 if (! fontset)
438 goto finish;
439 if (fontset && fontset->nfont > 0
440 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
441 &charset)
442 == FcResultMatch))
443 cache_data->fc_charset = FcCharSetCopy (charset);
444 else
445 cache_data->fc_charset = FcCharSetCreate ();
447 finish:
448 if (fontset)
449 FcFontSetDestroy (fontset);
450 if (objset)
451 FcObjectSetDestroy (objset);
452 if (pat)
453 FcPatternDestroy (pat);
456 return cache;
459 FcCharSet *
460 ftfont_get_fc_charset (Lisp_Object entity)
462 Lisp_Object val, cache;
463 struct ftfont_cache_data *cache_data;
465 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
466 val = XCDR (cache);
467 cache_data = XSAVE_POINTER (val, 0);
468 return cache_data->fc_charset;
471 #ifdef HAVE_LIBOTF
472 static OTF *
473 ftfont_get_otf (struct ftfont_info *ftfont_info)
475 OTF *otf;
477 if (ftfont_info->otf)
478 return ftfont_info->otf;
479 if (! ftfont_info->maybe_otf)
480 return NULL;
481 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
482 if (! otf || OTF_get_table (otf, "head") < 0)
484 if (otf)
485 OTF_close (otf);
486 ftfont_info->maybe_otf = 0;
487 return NULL;
489 ftfont_info->otf = otf;
490 return otf;
492 #endif /* HAVE_LIBOTF */
494 static Lisp_Object ftfont_get_cache (struct frame *);
495 static Lisp_Object ftfont_list (struct frame *, Lisp_Object);
496 static Lisp_Object ftfont_match (struct frame *, Lisp_Object);
497 static Lisp_Object ftfont_list_family (struct frame *);
498 static Lisp_Object ftfont_open (struct frame *, Lisp_Object, int);
499 static void ftfont_close (struct font *);
500 static int ftfont_has_char (Lisp_Object, int);
501 static unsigned ftfont_encode_char (struct font *, int);
502 static int ftfont_text_extents (struct font *, unsigned *, int,
503 struct font_metrics *);
504 static int ftfont_get_bitmap (struct font *, unsigned,
505 struct font_bitmap *, int);
506 static int ftfont_anchor_point (struct font *, unsigned, int,
507 int *, int *);
508 #ifdef HAVE_LIBOTF
509 static Lisp_Object ftfont_otf_capability (struct font *);
510 # ifdef HAVE_M17N_FLT
511 static Lisp_Object ftfont_shape (Lisp_Object);
512 # endif
513 #endif
515 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
516 static int ftfont_variation_glyphs (struct font *, int c,
517 unsigned variations[256]);
518 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
520 struct font_driver ftfont_driver =
522 LISP_INITIALLY_ZERO, /* Qfreetype */
523 0, /* case insensitive */
524 ftfont_get_cache,
525 ftfont_list,
526 ftfont_match,
527 ftfont_list_family,
528 NULL, /* free_entity */
529 ftfont_open,
530 ftfont_close,
531 /* We can't draw a text without device dependent functions. */
532 NULL, /* prepare_face */
533 NULL, /* done_face */
534 ftfont_has_char,
535 ftfont_encode_char,
536 ftfont_text_extents,
537 /* We can't draw a text without device dependent functions. */
538 NULL, /* draw */
539 ftfont_get_bitmap,
540 NULL, /* free_bitmap */
541 ftfont_anchor_point,
542 #ifdef HAVE_LIBOTF
543 ftfont_otf_capability,
544 #else /* not HAVE_LIBOTF */
545 NULL,
546 #endif /* not HAVE_LIBOTF */
547 NULL, /* otf_drive */
548 NULL, /* start_for_frame */
549 NULL, /* end_for_frame */
550 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
551 ftfont_shape,
552 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
553 NULL,
554 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
555 NULL, /* check */
557 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
558 ftfont_variation_glyphs,
559 #else
560 NULL,
561 #endif
563 ftfont_filter_properties, /* filter_properties */
566 static Lisp_Object
567 ftfont_get_cache (struct frame *f)
569 return freetype_font_cache;
572 static int
573 ftfont_get_charset (Lisp_Object registry)
575 char *str = SSDATA (SYMBOL_NAME (registry));
576 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
577 Lisp_Object regexp;
578 int i, j;
580 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
582 if (str[i] == '.')
583 re[j++] = '\\';
584 else if (str[i] == '*')
585 re[j++] = '.';
586 re[j] = str[i];
587 if (re[j] == '?')
588 re[j] = '.';
590 re[j] = '\0';
591 regexp = make_unibyte_string (re, j);
592 for (i = 0; fc_charset_table[i].name; i++)
593 if (fast_c_string_match_ignore_case
594 (regexp, fc_charset_table[i].name,
595 strlen (fc_charset_table[i].name)) >= 0)
596 break;
597 if (! fc_charset_table[i].name)
598 return -1;
599 if (! fc_charset_table[i].fc_charset)
601 FcCharSet *charset = FcCharSetCreate ();
602 int *uniquifier = fc_charset_table[i].uniquifier;
604 if (! charset)
605 return -1;
606 for (j = 0; uniquifier[j]; j++)
607 if (! FcCharSetAddChar (charset, uniquifier[j]))
609 FcCharSetDestroy (charset);
610 return -1;
612 fc_charset_table[i].fc_charset = charset;
614 return i;
617 struct OpenTypeSpec
619 Lisp_Object script;
620 unsigned int script_tag, langsys_tag;
621 int nfeatures[2];
622 unsigned int *features[2];
625 #define OTF_SYM_TAG(SYM, TAG) \
626 do { \
627 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
628 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
629 } while (0)
631 #define OTF_TAG_STR(TAG, P) \
632 do { \
633 (P)[0] = (char) (TAG >> 24); \
634 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
635 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
636 (P)[3] = (char) (TAG & 0xFF); \
637 (P)[4] = '\0'; \
638 } while (0)
640 #ifdef HAVE_LIBOTF
641 #define OTF_TAG_SYM(SYM, TAG) \
642 do { \
643 char str[5]; \
645 OTF_TAG_STR (TAG, str); \
646 (SYM) = font_intern_prop (str, 4, 1); \
647 } while (0)
648 #endif
651 static struct OpenTypeSpec *
652 ftfont_get_open_type_spec (Lisp_Object otf_spec)
654 struct OpenTypeSpec *spec = malloc (sizeof *spec);
655 Lisp_Object val;
656 int i, j;
657 bool negative;
659 if (! spec)
660 return NULL;
661 spec->script = XCAR (otf_spec);
662 if (! NILP (spec->script))
664 OTF_SYM_TAG (spec->script, spec->script_tag);
665 val = assq_no_quit (spec->script, Votf_script_alist);
666 if (CONSP (val) && SYMBOLP (XCDR (val)))
667 spec->script = XCDR (val);
668 else
669 spec->script = Qnil;
671 else
672 spec->script_tag = 0x44464C54; /* "DFLT" */
673 otf_spec = XCDR (otf_spec);
674 spec->langsys_tag = 0;
675 if (! NILP (otf_spec))
677 val = XCAR (otf_spec);
678 if (! NILP (val))
679 OTF_SYM_TAG (val, spec->langsys_tag);
680 otf_spec = XCDR (otf_spec);
682 spec->nfeatures[0] = spec->nfeatures[1] = 0;
683 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
685 Lisp_Object len;
687 val = XCAR (otf_spec);
688 if (NILP (val))
689 continue;
690 len = Flength (val);
691 spec->features[i] =
692 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
694 : malloc (XINT (len) * sizeof *spec->features[i]));
695 if (! spec->features[i])
697 if (i > 0 && spec->features[0])
698 free (spec->features[0]);
699 free (spec);
700 return NULL;
702 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
704 if (NILP (XCAR (val)))
705 negative = 1;
706 else
708 unsigned int tag;
710 OTF_SYM_TAG (XCAR (val), tag);
711 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
714 spec->nfeatures[i] = j;
716 return spec;
719 static FcPattern *
720 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
722 Lisp_Object tmp, extra;
723 FcPattern *pattern = NULL;
724 FcCharSet *charset = NULL;
725 FcLangSet *langset = NULL;
726 int n;
727 int dpi = -1;
728 int scalable = -1;
729 Lisp_Object script = Qnil;
730 Lisp_Object registry;
731 int fc_charset_idx;
733 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
734 && n < 100)
735 /* Fontconfig doesn't support reverse-italic/oblique. */
736 return NULL;
738 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
739 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
740 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
741 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
742 scalable = 1;
744 registry = AREF (spec, FONT_REGISTRY_INDEX);
745 if (NILP (registry)
746 || EQ (registry, Qascii_0)
747 || EQ (registry, Qiso10646_1)
748 || EQ (registry, Qunicode_bmp))
749 fc_charset_idx = -1;
750 else
752 FcChar8 *lang;
754 fc_charset_idx = ftfont_get_charset (registry);
755 if (fc_charset_idx < 0)
756 return NULL;
757 charset = fc_charset_table[fc_charset_idx].fc_charset;
758 *langname = fc_charset_table[fc_charset_idx].lang;
759 lang = (FcChar8 *) *langname;
760 if (lang)
762 langset = FcLangSetCreate ();
763 if (! langset)
764 goto err;
765 FcLangSetAdd (langset, lang);
769 otlayout[0] = '\0';
770 for (extra = AREF (spec, FONT_EXTRA_INDEX);
771 CONSP (extra); extra = XCDR (extra))
773 Lisp_Object key, val;
775 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
776 if (EQ (key, QCdpi))
778 if (INTEGERP (val))
779 dpi = XINT (val);
781 else if (EQ (key, QClang))
783 if (! langset)
784 langset = FcLangSetCreate ();
785 if (! langset)
786 goto err;
787 if (SYMBOLP (val))
789 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
790 goto err;
792 else
793 for (; CONSP (val); val = XCDR (val))
794 if (SYMBOLP (XCAR (val))
795 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
796 goto err;
798 else if (EQ (key, QCotf))
800 if (CONSP (val))
802 *otspec = ftfont_get_open_type_spec (val);
803 if (! *otspec)
804 return NULL;
805 strcat (otlayout, "otlayout:");
806 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
807 script = (*otspec)->script;
810 else if (EQ (key, QCscript))
811 script = val;
812 else if (EQ (key, QCscalable))
813 scalable = ! NILP (val);
816 if (! NILP (script) && ! charset)
818 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
820 if (CONSP (chars) && CONSP (CDR (chars)))
822 charset = FcCharSetCreate ();
823 if (! charset)
824 goto err;
825 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
826 if (CHARACTERP (XCAR (chars))
827 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
828 goto err;
832 pattern = FcPatternCreate ();
833 if (! pattern)
834 goto err;
835 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
836 if (! NILP (tmp)
837 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
838 goto err;
839 tmp = AREF (spec, FONT_FAMILY_INDEX);
840 if (! NILP (tmp)
841 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
842 goto err;
843 if (charset
844 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
845 goto err;
846 if (langset
847 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
848 goto err;
849 if (dpi >= 0
850 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
851 goto err;
852 if (scalable >= 0
853 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
854 goto err;
856 goto finish;
858 err:
859 /* We come here because of unexpected error in fontconfig API call
860 (usually insufficient memory). */
861 if (pattern)
863 FcPatternDestroy (pattern);
864 pattern = NULL;
866 if (*otspec)
868 if ((*otspec)->nfeatures[0] > 0)
869 free ((*otspec)->features[0]);
870 if ((*otspec)->nfeatures[1] > 0)
871 free ((*otspec)->features[1]);
872 free (*otspec);
873 *otspec = NULL;
876 finish:
877 if (langset) FcLangSetDestroy (langset);
878 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
879 return pattern;
882 static Lisp_Object
883 ftfont_list (struct frame *f, Lisp_Object spec)
885 Lisp_Object val = Qnil, family, adstyle;
886 int i;
887 FcPattern *pattern;
888 FcFontSet *fontset = NULL;
889 FcObjectSet *objset = NULL;
890 FcCharSet *charset;
891 Lisp_Object chars = Qnil;
892 char otlayout[15]; /* For "otlayout:XXXX" */
893 struct OpenTypeSpec *otspec = NULL;
894 int spacing = -1;
895 const char *langname = NULL;
897 if (! fc_initialized)
899 FcInit ();
900 fc_initialized = 1;
903 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
904 if (! pattern)
905 return Qnil;
906 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
908 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
909 if (! NILP (val))
911 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
912 if (CONSP (val) && VECTORP (XCDR (val)))
913 chars = XCDR (val);
915 val = Qnil;
917 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
918 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
919 family = AREF (spec, FONT_FAMILY_INDEX);
920 if (! NILP (family))
922 Lisp_Object resolved;
924 resolved = ftfont_resolve_generic_family (family, pattern);
925 if (! NILP (resolved))
927 FcPatternDel (pattern, FC_FAMILY);
928 if (! FcPatternAddString (pattern, FC_FAMILY,
929 SYMBOL_FcChar8 (resolved)))
930 goto err;
933 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
934 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
935 adstyle = Qnil;
936 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
937 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
938 FC_STYLE, FC_FILE, FC_INDEX,
939 #ifdef FC_CAPABILITY
940 FC_CAPABILITY,
941 #endif /* FC_CAPABILITY */
942 #ifdef FC_FONTFORMAT
943 FC_FONTFORMAT,
944 #endif
945 NULL);
946 if (! objset)
947 goto err;
948 if (! NILP (chars))
949 FcObjectSetAdd (objset, FC_CHARSET);
951 fontset = FcFontList (NULL, pattern, objset);
952 if (! fontset || fontset->nfont == 0)
953 goto finish;
954 #if 0
955 /* Need fix because this finds any fonts. */
956 if (fontset->nfont == 0 && ! NILP (family))
958 /* Try matching with configuration. For instance, the
959 configuration may specify "Nimbus Mono L" as an alias of
960 "Courier". */
961 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
962 SYMBOL_FcChar8 (family), NULL);
963 FcChar8 *fam;
965 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
967 for (i = 0;
968 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
969 i++)
971 FcPatternDel (pattern, FC_FAMILY);
972 FcPatternAddString (pattern, FC_FAMILY, fam);
973 FcFontSetDestroy (fontset);
974 fontset = FcFontList (NULL, pattern, objset);
975 if (fontset && fontset->nfont > 0)
976 break;
980 #endif
981 for (i = 0; i < fontset->nfont; i++)
983 Lisp_Object entity;
985 if (spacing >= 0)
987 int this;
989 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
990 == FcResultMatch)
991 && spacing != this)
992 continue;
995 #ifdef FC_CAPABILITY
996 if (otlayout[0])
998 FcChar8 *this;
1000 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
1001 != FcResultMatch
1002 || ! strstr ((char *) this, otlayout))
1003 continue;
1005 #endif /* FC_CAPABILITY */
1006 #ifdef HAVE_LIBOTF
1007 if (otspec)
1009 FcChar8 *file;
1010 bool passed;
1011 OTF *otf;
1013 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1014 != FcResultMatch)
1015 continue;
1016 otf = OTF_open ((char *) file);
1017 if (! otf)
1018 continue;
1019 passed = (OTF_check_features (otf, 1, otspec->script_tag,
1020 otspec->langsys_tag,
1021 otspec->features[0],
1022 otspec->nfeatures[0]) == 1
1023 && OTF_check_features (otf, 0, otspec->script_tag,
1024 otspec->langsys_tag,
1025 otspec->features[1],
1026 otspec->nfeatures[1]) == 1);
1027 OTF_close (otf);
1028 if (!passed)
1029 continue;
1031 #endif /* HAVE_LIBOTF */
1032 if (VECTORP (chars))
1034 ptrdiff_t j;
1036 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1037 != FcResultMatch)
1038 continue;
1039 for (j = 0; j < ASIZE (chars); j++)
1040 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1041 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1042 break;
1043 if (j == ASIZE (chars))
1044 continue;
1046 if (! NILP (adstyle) || langname)
1048 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1050 if (! NILP (adstyle)
1051 && (NILP (this_adstyle)
1052 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1053 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1054 continue;
1055 if (langname
1056 && ! NILP (this_adstyle)
1057 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1058 continue;
1060 entity = ftfont_pattern_entity (fontset->fonts[i],
1061 AREF (spec, FONT_EXTRA_INDEX));
1062 if (! NILP (entity))
1063 val = Fcons (entity, val);
1065 val = Fnreverse (val);
1066 goto finish;
1068 err:
1069 /* We come here because of unexpected error in fontconfig API call
1070 (usually insufficient memory). */
1071 val = Qnil;
1073 finish:
1074 FONT_ADD_LOG ("ftfont-list", spec, val);
1075 if (objset) FcObjectSetDestroy (objset);
1076 if (fontset) FcFontSetDestroy (fontset);
1077 if (pattern) FcPatternDestroy (pattern);
1078 return val;
1081 static Lisp_Object
1082 ftfont_match (struct frame *f, Lisp_Object spec)
1084 Lisp_Object entity = Qnil;
1085 FcPattern *pattern, *match = NULL;
1086 FcResult result;
1087 char otlayout[15]; /* For "otlayout:XXXX" */
1088 struct OpenTypeSpec *otspec = NULL;
1089 const char *langname = NULL;
1091 if (! fc_initialized)
1093 FcInit ();
1094 fc_initialized = 1;
1097 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1098 if (! pattern)
1099 return Qnil;
1101 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1103 FcValue value;
1105 value.type = FcTypeDouble;
1106 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1107 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1109 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1111 FcDefaultSubstitute (pattern);
1112 match = FcFontMatch (NULL, pattern, &result);
1113 if (match)
1115 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1116 FcPatternDestroy (match);
1117 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1118 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1119 ftfont_generic_family_list))
1120 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1121 AREF (entity, FONT_FAMILY_INDEX))))
1122 entity = Qnil;
1125 FcPatternDestroy (pattern);
1127 FONT_ADD_LOG ("ftfont-match", spec, entity);
1128 return entity;
1131 static Lisp_Object
1132 ftfont_list_family (struct frame *f)
1134 Lisp_Object list = Qnil;
1135 FcPattern *pattern = NULL;
1136 FcFontSet *fontset = NULL;
1137 FcObjectSet *objset = NULL;
1138 int i;
1140 if (! fc_initialized)
1142 FcInit ();
1143 fc_initialized = 1;
1146 pattern = FcPatternCreate ();
1147 if (! pattern)
1148 goto finish;
1149 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1150 if (! objset)
1151 goto finish;
1152 fontset = FcFontList (NULL, pattern, objset);
1153 if (! fontset)
1154 goto finish;
1156 for (i = 0; i < fontset->nfont; i++)
1158 FcPattern *pat = fontset->fonts[i];
1159 FcChar8 *str;
1161 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1162 list = Fcons (intern ((char *) str), list);
1165 finish:
1166 if (objset) FcObjectSetDestroy (objset);
1167 if (fontset) FcFontSetDestroy (fontset);
1168 if (pattern) FcPatternDestroy (pattern);
1170 return list;
1174 static Lisp_Object
1175 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1177 struct ftfont_info *ftfont_info;
1178 struct font *font;
1179 struct ftfont_cache_data *cache_data;
1180 FT_Face ft_face;
1181 FT_Size ft_size;
1182 FT_UInt size;
1183 Lisp_Object val, filename, idx, cache, font_object;
1184 bool scalable;
1185 int spacing;
1186 char name[256];
1187 int i, len;
1188 int upEM;
1190 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1191 if (! CONSP (val))
1192 return Qnil;
1193 val = XCDR (val);
1194 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1195 if (NILP (cache))
1196 return Qnil;
1197 filename = XCAR (val);
1198 idx = XCDR (val);
1199 val = XCDR (cache);
1200 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1201 ft_face = cache_data->ft_face;
1202 if (XSAVE_INTEGER (val, 1) > 0)
1204 /* FT_Face in this cache is already used by the different size. */
1205 if (FT_New_Size (ft_face, &ft_size) != 0)
1206 return Qnil;
1207 if (FT_Activate_Size (ft_size) != 0)
1209 FT_Done_Size (ft_size);
1210 return Qnil;
1213 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1214 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1215 if (size == 0)
1216 size = pixel_size;
1217 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1219 if (XSAVE_INTEGER (val, 1) == 0)
1220 FT_Done_Face (ft_face);
1221 return Qnil;
1224 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
1225 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
1226 len = font_unparse_xlfd (entity, size, name, 256);
1227 if (len > 0)
1228 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
1229 len = font_unparse_fcname (entity, size, name, 256);
1230 if (len > 0)
1231 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
1232 else
1233 ASET (font_object, FONT_FULLNAME_INDEX,
1234 AREF (font_object, FONT_NAME_INDEX));
1235 ASET (font_object, FONT_FILE_INDEX, filename);
1236 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
1237 font = XFONT_OBJECT (font_object);
1238 ftfont_info = (struct ftfont_info *) font;
1239 ftfont_info->ft_size = ft_face->size;
1240 ftfont_info->index = XINT (idx);
1241 #ifdef HAVE_LIBOTF
1242 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1243 ftfont_info->otf = NULL;
1244 #endif /* HAVE_LIBOTF */
1245 /* This means that there's no need of transformation. */
1246 ftfont_info->matrix.xx = 0;
1247 font->pixel_size = size;
1248 font->driver = &ftfont_driver;
1249 font->encoding_charset = font->repertory_charset = -1;
1251 upEM = ft_face->units_per_EM;
1252 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1253 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1254 if (scalable)
1256 font->ascent = ft_face->ascender * size / upEM;
1257 font->descent = - ft_face->descender * size / upEM;
1258 font->height = ft_face->height * size / upEM;
1260 else
1262 font->ascent = ft_face->size->metrics.ascender >> 6;
1263 font->descent = - ft_face->size->metrics.descender >> 6;
1264 font->height = ft_face->size->metrics.height >> 6;
1266 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1267 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1268 else
1269 spacing = FC_PROPORTIONAL;
1270 if (spacing != FC_PROPORTIONAL
1271 #ifdef FC_DUAL
1272 && spacing != FC_DUAL
1273 #endif /* FC_DUAL */
1275 font->min_width = font->average_width = font->space_width
1276 = (scalable ? ft_face->max_advance_width * size / upEM
1277 : ft_face->size->metrics.max_advance >> 6);
1278 else
1280 int n;
1282 font->min_width = font->average_width = font->space_width = 0;
1283 for (i = 32, n = 0; i < 127; i++)
1284 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1286 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1288 if (this_width > 0
1289 && (! font->min_width || font->min_width > this_width))
1290 font->min_width = this_width;
1291 if (i == 32)
1292 font->space_width = this_width;
1293 font->average_width += this_width;
1294 n++;
1296 if (n > 0)
1297 font->average_width /= n;
1300 font->baseline_offset = 0;
1301 font->relative_compose = 0;
1302 font->default_ascent = 0;
1303 font->vertical_centering = 0;
1304 if (scalable)
1306 font->underline_position = -ft_face->underline_position * size / upEM;
1307 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1309 else
1311 font->underline_position = -1;
1312 font->underline_thickness = 0;
1315 return font_object;
1318 static void
1319 ftfont_close (struct font *font)
1321 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1322 Lisp_Object val, cache;
1324 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1325 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1326 eassert (CONSP (cache));
1327 val = XCDR (cache);
1328 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1329 if (XSAVE_INTEGER (val, 1) == 0)
1331 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1333 FT_Done_Face (cache_data->ft_face);
1334 #ifdef HAVE_LIBOTF
1335 if (ftfont_info->otf)
1336 OTF_close (ftfont_info->otf);
1337 #endif
1338 cache_data->ft_face = NULL;
1340 else
1341 FT_Done_Size (ftfont_info->ft_size);
1344 static int
1345 ftfont_has_char (Lisp_Object font, int c)
1347 struct charset *cs = NULL;
1349 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1350 && charset_jisx0208 >= 0)
1351 cs = CHARSET_FROM_ID (charset_jisx0208);
1352 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1353 && charset_ksc5601 >= 0)
1354 cs = CHARSET_FROM_ID (charset_ksc5601);
1355 if (cs)
1356 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1358 if (FONT_ENTITY_P (font))
1360 FcCharSet *charset = ftfont_get_fc_charset (font);
1362 return (FcCharSetHasChar (charset, c) == FcTrue);
1364 else
1366 struct ftfont_info *ftfont_info;
1368 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1369 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1370 != 0);
1374 static unsigned
1375 ftfont_encode_char (struct font *font, int c)
1377 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1378 FT_Face ft_face = ftfont_info->ft_size->face;
1379 FT_ULong charcode = c;
1380 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1382 return (code > 0 ? code : FONT_INVALID_CODE);
1385 static int
1386 ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
1388 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1389 FT_Face ft_face = ftfont_info->ft_size->face;
1390 int width = 0;
1391 int i;
1392 bool first;
1394 if (ftfont_info->ft_size != ft_face->size)
1395 FT_Activate_Size (ftfont_info->ft_size);
1396 if (metrics)
1397 memset (metrics, 0, sizeof (struct font_metrics));
1398 for (i = 0, first = 1; i < nglyphs; i++)
1400 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1402 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1404 if (first)
1406 if (metrics)
1408 metrics->lbearing = m->horiBearingX >> 6;
1409 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1410 metrics->ascent = m->horiBearingY >> 6;
1411 metrics->descent = (m->height - m->horiBearingY) >> 6;
1413 first = 0;
1415 if (metrics)
1417 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1418 metrics->lbearing = width + (m->horiBearingX >> 6);
1419 if (metrics->rbearing
1420 < width + ((m->horiBearingX + m->width) >> 6))
1421 metrics->rbearing
1422 = width + ((m->horiBearingX + m->width) >> 6);
1423 if (metrics->ascent < (m->horiBearingY >> 6))
1424 metrics->ascent = m->horiBearingY >> 6;
1425 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1426 metrics->descent = (m->height - m->horiBearingY) >> 6;
1428 width += m->horiAdvance >> 6;
1430 else
1432 width += font->space_width;
1435 if (metrics)
1436 metrics->width = width;
1438 return width;
1441 static int
1442 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1444 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1445 FT_Face ft_face = ftfont_info->ft_size->face;
1446 FT_Int32 load_flags = FT_LOAD_RENDER;
1448 if (ftfont_info->ft_size != ft_face->size)
1449 FT_Activate_Size (ftfont_info->ft_size);
1450 if (bits_per_pixel == 1)
1452 #ifdef FT_LOAD_TARGET_MONO
1453 load_flags |= FT_LOAD_TARGET_MONO;
1454 #else
1455 load_flags |= FT_LOAD_MONOCHROME;
1456 #endif
1458 else if (bits_per_pixel != 8)
1459 /* We don't support such a rendering. */
1460 return -1;
1462 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1463 return -1;
1464 bitmap->bits_per_pixel
1465 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1466 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1467 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1468 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1469 : -1);
1470 if (bitmap->bits_per_pixel < 0)
1471 /* We don't support that kind of pixel mode. */
1472 return -1;
1473 bitmap->rows = ft_face->glyph->bitmap.rows;
1474 bitmap->width = ft_face->glyph->bitmap.width;
1475 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1476 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1477 bitmap->left = ft_face->glyph->bitmap_left;
1478 bitmap->top = ft_face->glyph->bitmap_top;
1479 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1481 return 0;
1484 static int
1485 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1486 int *x, int *y)
1488 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1489 FT_Face ft_face = ftfont_info->ft_size->face;
1491 if (ftfont_info->ft_size != ft_face->size)
1492 FT_Activate_Size (ftfont_info->ft_size);
1493 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1494 return -1;
1495 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1496 return -1;
1497 if (idx >= ft_face->glyph->outline.n_points)
1498 return -1;
1499 *x = ft_face->glyph->outline.points[idx].x;
1500 *y = ft_face->glyph->outline.points[idx].y;
1501 return 0;
1504 #ifdef HAVE_LIBOTF
1506 static Lisp_Object
1507 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1509 Lisp_Object scripts, langsyses, features, sym;
1510 int i, j, k, l;
1512 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1514 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1516 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1518 OTF_LangSys *otf_langsys;
1520 if (j >= 0)
1521 otf_langsys = otf_script->LangSys + j;
1522 else if (otf_script->DefaultLangSysOffset)
1523 otf_langsys = &otf_script->DefaultLangSys;
1524 else
1525 break;
1527 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1529 l = otf_langsys->FeatureIndex[k];
1530 if (l >= gsub_gpos->FeatureList.FeatureCount)
1531 continue;
1532 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1533 features = Fcons (sym, features);
1535 if (j >= 0)
1536 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1537 else
1538 sym = Qnil;
1539 langsyses = Fcons (Fcons (sym, features), langsyses);
1542 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1543 scripts = Fcons (Fcons (sym, langsyses), scripts);
1545 return scripts;
1550 static Lisp_Object
1551 ftfont_otf_capability (struct font *font)
1553 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1554 OTF *otf = ftfont_get_otf (ftfont_info);
1555 Lisp_Object gsub_gpos;
1557 if (! otf)
1558 return Qnil;
1559 gsub_gpos = Fcons (Qnil, Qnil);
1560 if (OTF_get_table (otf, "GSUB") == 0
1561 && otf->gsub->FeatureList.FeatureCount > 0)
1562 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1563 if (OTF_get_table (otf, "GPOS") == 0
1564 && otf->gpos->FeatureList.FeatureCount > 0)
1565 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1566 return gsub_gpos;
1569 #ifdef HAVE_M17N_FLT
1571 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1572 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1573 /* We can use the new feature of libotf and m17n-flt to handle the
1574 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1575 some Agian scripts. */
1576 #define M17N_FLT_USE_NEW_FEATURE
1577 #endif
1579 struct MFLTFontFT
1581 MFLTFont flt_font;
1582 struct font *font;
1583 FT_Face ft_face;
1584 OTF *otf;
1585 FT_Matrix *matrix;
1588 static int
1589 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1590 int from, int to)
1592 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1593 FT_Face ft_face = flt_font_ft->ft_face;
1594 MFLTGlyph *g;
1596 for (g = gstring->glyphs + from; from < to; g++, from++)
1597 if (! g->encoded)
1599 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1601 g->code = code > 0 ? code : FONT_INVALID_CODE;
1602 g->encoded = 1;
1604 return 0;
1607 /* Operators for 26.6 fixed fractional pixel format */
1609 #define FLOOR(x) ((x) & -64)
1610 #define CEIL(x) (((x)+63) & -64)
1611 #define ROUND(x) (((x)+32) & -64)
1613 static int
1614 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1615 int from, int to)
1617 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1618 FT_Face ft_face = flt_font_ft->ft_face;
1619 MFLTGlyph *g;
1621 for (g = gstring->glyphs + from; from < to; g++, from++)
1622 if (! g->measured)
1624 if (g->code != FONT_INVALID_CODE)
1626 FT_Glyph_Metrics *m;
1628 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1629 emacs_abort ();
1630 m = &ft_face->glyph->metrics;
1631 if (flt_font_ft->matrix)
1633 FT_Vector v[4];
1634 int i;
1636 v[0].x = v[1].x = m->horiBearingX;
1637 v[2].x = v[3].x = m->horiBearingX + m->width;
1638 v[0].y = v[2].y = m->horiBearingY;
1639 v[1].y = v[3].y = m->horiBearingY - m->height;
1640 for (i = 0; i < 4; i++)
1641 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1642 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1643 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1644 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1645 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1647 else
1649 g->lbearing = FLOOR (m->horiBearingX);
1650 g->rbearing = CEIL (m->horiBearingX + m->width);
1651 g->ascent = CEIL (m->horiBearingY);
1652 g->descent = - FLOOR (m->horiBearingY - m->height);
1654 g->xadv = ROUND (ft_face->glyph->advance.x);
1656 else
1658 g->lbearing = 0;
1659 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1660 g->ascent = flt_font_ft->font->ascent << 6;
1661 g->descent = flt_font_ft->font->descent << 6;
1663 g->yadv = 0;
1664 g->measured = 1;
1666 return 0;
1669 static int
1670 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1672 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1674 #define FEATURE_ANY(IDX) \
1675 (spec->features[IDX] \
1676 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1678 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1679 OTF *otf = flt_font_ft->otf;
1680 OTF_Tag *tags;
1681 int i, n;
1682 bool negative;
1684 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1685 /* Return true iff any of GSUB or GPOS support the script (and
1686 language). */
1687 return (otf
1688 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1689 NULL, 0) > 0
1690 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1691 NULL, 0) > 0));
1693 for (i = 0; i < 2; i++)
1694 if (! FEATURE_ANY (i))
1696 if (FEATURE_NONE (i))
1698 if (otf
1699 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1700 NULL, 0) > 0)
1701 return 0;
1702 continue;
1704 if (spec->features[i][0] == 0xFFFFFFFF)
1706 if (! otf
1707 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1708 NULL, 0) <= 0)
1709 continue;
1711 else if (! otf)
1712 return 0;
1713 for (n = 1; spec->features[i][n]; n++);
1714 tags = alloca (sizeof (OTF_Tag) * n);
1715 for (n = 0, negative = 0; spec->features[i][n]; n++)
1717 if (spec->features[i][n] == 0xFFFFFFFF)
1718 negative = 1;
1719 else if (negative)
1720 tags[n - 1] = spec->features[i][n] | 0x80000000;
1721 else
1722 tags[n] = spec->features[i][n];
1724 #ifdef M17N_FLT_USE_NEW_FEATURE
1725 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1726 tags, n - negative) != 1)
1727 return 0;
1728 #else /* not M17N_FLT_USE_NEW_FEATURE */
1729 if (n - negative > 0
1730 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1731 tags, n - negative) != 1)
1732 return 0;
1733 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1735 return 1;
1736 #undef FEATURE_NONE
1737 #undef FEATURE_ANY
1740 #define DEVICE_DELTA(table, size) \
1741 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1742 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1743 : 0)
1745 static void
1746 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1747 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1749 if (anchor->AnchorFormat == 2)
1751 FT_Outline *outline;
1752 int ap = anchor->f.f1.AnchorPoint;
1754 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1755 outline = &ft_face->glyph->outline;
1756 if (ap < outline->n_points)
1758 *x = outline->points[ap].x << 6;
1759 *y = outline->points[ap].y << 6;
1762 else if (anchor->AnchorFormat == 3)
1764 if (anchor->f.f2.XDeviceTable.offset
1765 && anchor->f.f2.XDeviceTable.DeltaValue)
1766 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1767 if (anchor->f.f2.YDeviceTable.offset
1768 && anchor->f.f2.YDeviceTable.DeltaValue)
1769 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1773 static OTF_GlyphString otf_gstring;
1775 static void
1776 setup_otf_gstring (int size)
1778 if (otf_gstring.size < size)
1780 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1781 size, sizeof (OTF_Glyph));
1782 otf_gstring.size = size;
1784 otf_gstring.used = size;
1785 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1788 #ifdef M17N_FLT_USE_NEW_FEATURE
1790 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1791 #define PACK_OTF_TAG(TAG) \
1792 ((((TAG) & 0x7F000000) >> 3) \
1793 | (((TAG) & 0x7F0000) >> 2) \
1794 | (((TAG) & 0x7F00) >> 1) \
1795 | ((TAG) & 0x7F))
1797 /* Assuming that FONT is an OpenType font, apply OpenType features
1798 specified in SPEC on glyphs between FROM and TO of IN, and record
1799 the lastly applied feature in each glyph of IN. If OUT is not
1800 NULL, append the resulting glyphs to OUT while storing glyph
1801 position adjustment information in ADJUSTMENT. */
1803 static int
1804 ftfont_drive_otf (MFLTFont *font,
1805 MFLTOtfSpec *spec,
1806 MFLTGlyphString *in,
1807 int from,
1808 int to,
1809 MFLTGlyphString *out,
1810 MFLTGlyphAdjustment *adjustment)
1812 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1813 FT_Face ft_face = flt_font_ft->ft_face;
1814 OTF *otf = flt_font_ft->otf;
1815 int len = to - from;
1816 int i, j, gidx;
1817 OTF_Glyph *otfg;
1818 char script[5], *langsys = NULL;
1819 char *gsub_features = NULL, *gpos_features = NULL;
1820 OTF_Feature *features;
1822 if (len == 0)
1823 return from;
1824 OTF_tag_name (spec->script, script);
1825 if (spec->langsys)
1827 langsys = alloca (5);
1828 OTF_tag_name (spec->langsys, langsys);
1830 for (i = 0; i < 2; i++)
1832 char *p;
1834 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1836 for (j = 0; spec->features[i][j]; j++);
1837 if (i == 0)
1838 p = gsub_features = alloca (6 * j);
1839 else
1840 p = gpos_features = alloca (6 * j);
1841 for (j = 0; spec->features[i][j]; j++)
1843 if (spec->features[i][j] == 0xFFFFFFFF)
1844 *p++ = '*', *p++ = ',';
1845 else
1847 OTF_tag_name (spec->features[i][j], p);
1848 p[4] = ',';
1849 p += 5;
1852 *--p = '\0';
1856 setup_otf_gstring (len);
1857 for (i = 0; i < len; i++)
1859 otf_gstring.glyphs[i].c = in->glyphs[from + i].c & 0x11FFFF;
1860 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1863 OTF_drive_gdef (otf, &otf_gstring);
1864 gidx = out ? out->used : from;
1866 if (gsub_features && out)
1868 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1869 gsub_features) < 0)
1870 goto simple_copy;
1871 if (out->allocated < out->used + otf_gstring.used)
1872 return -2;
1873 features = otf->gsub->FeatureList.Feature;
1874 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1876 MFLTGlyph *g;
1877 int min_from, max_to;
1878 int feature_idx = otfg->positioning_type >> 4;
1880 g = out->glyphs + out->used;
1881 *g = in->glyphs[from + otfg->f.index.from];
1882 if (g->code != otfg->glyph_id)
1884 g->c = 0;
1885 g->code = otfg->glyph_id;
1886 g->measured = 0;
1888 out->used++;
1889 min_from = g->from;
1890 max_to = g->to;
1891 if (otfg->f.index.from < otfg->f.index.to)
1893 /* OTFG substitutes multiple glyphs in IN. */
1894 for (j = from + otfg->f.index.from + 1;
1895 j <= from + otfg->f.index.to; j++)
1897 if (min_from > in->glyphs[j].from)
1898 min_from = in->glyphs[j].from;
1899 if (max_to < in->glyphs[j].to)
1900 max_to = in->glyphs[j].to;
1902 g->from = min_from;
1903 g->to = max_to;
1905 if (feature_idx)
1907 unsigned int tag = features[feature_idx - 1].FeatureTag;
1908 tag = PACK_OTF_TAG (tag);
1909 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1911 for (i++, otfg++; (i < otf_gstring.used
1912 && otfg->f.index.from == otfg[-1].f.index.from);
1913 i++, otfg++)
1915 g = out->glyphs + out->used;
1916 *g = in->glyphs[from + otfg->f.index.to];
1917 if (g->code != otfg->glyph_id)
1919 g->c = 0;
1920 g->code = otfg->glyph_id;
1921 g->measured = 0;
1923 feature_idx = otfg->positioning_type >> 4;
1924 if (feature_idx)
1926 unsigned int tag = features[feature_idx - 1].FeatureTag;
1927 tag = PACK_OTF_TAG (tag);
1928 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1930 out->used++;
1934 else if (gsub_features)
1936 /* Just for checking which features will be applied. */
1937 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1938 gsub_features) < 0)
1939 goto simple_copy;
1940 features = otf->gsub->FeatureList.Feature;
1941 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1942 otfg++)
1944 int feature_idx = otfg->positioning_type >> 4;
1946 if (feature_idx)
1948 unsigned int tag = features[feature_idx - 1].FeatureTag;
1949 tag = PACK_OTF_TAG (tag);
1950 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1952 MFLTGlyph *g = in->glyphs + (from + j);
1953 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1958 else if (out)
1960 if (out->allocated < out->used + len)
1961 return -2;
1962 for (i = 0; i < len; i++)
1963 out->glyphs[out->used++] = in->glyphs[from + i];
1966 if (gpos_features && out)
1968 MFLTGlyph *base = NULL, *mark = NULL, *g;
1969 int x_ppem, y_ppem, x_scale, y_scale;
1971 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1972 gpos_features) < 0)
1973 return to;
1974 features = otf->gpos->FeatureList.Feature;
1975 x_ppem = ft_face->size->metrics.x_ppem;
1976 y_ppem = ft_face->size->metrics.y_ppem;
1977 x_scale = ft_face->size->metrics.x_scale;
1978 y_scale = ft_face->size->metrics.y_scale;
1980 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1981 i < otf_gstring.used; i++, otfg++, g++)
1983 MFLTGlyph *prev;
1984 int feature_idx = otfg->positioning_type >> 4;
1986 if (feature_idx)
1988 unsigned int tag = features[feature_idx - 1].FeatureTag;
1989 tag = PACK_OTF_TAG (tag);
1990 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1993 if (! otfg->glyph_id)
1994 continue;
1995 switch (otfg->positioning_type & 0xF)
1997 case 0:
1998 break;
1999 case 1: /* Single */
2000 case 2: /* Pair */
2002 int format = otfg->f.f1.format;
2004 if (format & OTF_XPlacement)
2005 adjustment[i].xoff
2006 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2007 if (format & OTF_XPlaDevice)
2008 adjustment[i].xoff
2009 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2010 if (format & OTF_YPlacement)
2011 adjustment[i].yoff
2012 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2013 if (format & OTF_YPlaDevice)
2014 adjustment[i].yoff
2015 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2016 if (format & OTF_XAdvance)
2017 adjustment[i].xadv
2018 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2019 if (format & OTF_XAdvDevice)
2020 adjustment[i].xadv
2021 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2022 if (format & OTF_YAdvance)
2023 adjustment[i].yadv
2024 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2025 if (format & OTF_YAdvDevice)
2026 adjustment[i].yadv
2027 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2028 adjustment[i].set = 1;
2030 break;
2031 case 3: /* Cursive */
2032 /* Not yet supported. */
2033 break;
2034 case 4: /* Mark-to-Base */
2035 case 5: /* Mark-to-Ligature */
2036 if (! base)
2037 break;
2038 prev = base;
2039 goto label_adjust_anchor;
2040 default: /* i.e. case 6 Mark-to-Mark */
2041 if (! mark)
2042 break;
2043 prev = mark;
2045 label_adjust_anchor:
2047 int base_x, base_y, mark_x, mark_y;
2048 int this_from, this_to;
2050 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2051 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2052 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2053 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2055 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2056 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2057 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2058 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2059 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2060 x_ppem, y_ppem, &mark_x, &mark_y);
2061 adjustment[i].xoff = (base_x - mark_x);
2062 adjustment[i].yoff = - (base_y - mark_y);
2063 adjustment[i].back = (g - prev);
2064 adjustment[i].xadv = 0;
2065 adjustment[i].advance_is_absolute = 1;
2066 adjustment[i].set = 1;
2067 this_from = g->from;
2068 this_to = g->to;
2069 for (j = 0; prev + j < g; j++)
2071 if (this_from > prev[j].from)
2072 this_from = prev[j].from;
2073 if (this_to < prev[j].to)
2074 this_to = prev[j].to;
2076 for (; prev <= g; prev++)
2078 prev->from = this_from;
2079 prev->to = this_to;
2083 if (otfg->GlyphClass == OTF_GlyphClass0)
2084 base = mark = g;
2085 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2086 mark = g;
2087 else
2088 base = g;
2091 else if (gpos_features)
2093 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2094 gpos_features) < 0)
2095 return to;
2096 features = otf->gpos->FeatureList.Feature;
2097 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2098 i++, otfg++)
2099 if (otfg->positioning_type & 0xF)
2101 int feature_idx = otfg->positioning_type >> 4;
2103 if (feature_idx)
2105 unsigned int tag = features[feature_idx - 1].FeatureTag;
2106 tag = PACK_OTF_TAG (tag);
2107 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2109 MFLTGlyph *g = in->glyphs + (from + j);
2110 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2115 return to;
2117 simple_copy:
2118 if (! out)
2119 return to;
2120 if (out->allocated < out->used + len)
2121 return -2;
2122 font->get_metrics (font, in, from, to);
2123 memcpy (out->glyphs + out->used, in->glyphs + from,
2124 sizeof (MFLTGlyph) * len);
2125 out->used += len;
2126 return to;
2129 static int
2130 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2131 MFLTGlyphString *in, int from, int to)
2133 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2136 #else /* not M17N_FLT_USE_NEW_FEATURE */
2138 static int
2139 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2140 int from, int to,
2141 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2143 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2144 FT_Face ft_face = flt_font_ft->ft_face;
2145 OTF *otf = flt_font_ft->otf;
2146 int len = to - from;
2147 int i, j, gidx;
2148 OTF_Glyph *otfg;
2149 char script[5], *langsys = NULL;
2150 char *gsub_features = NULL, *gpos_features = NULL;
2152 if (len == 0)
2153 return from;
2154 OTF_tag_name (spec->script, script);
2155 if (spec->langsys)
2157 langsys = alloca (5);
2158 OTF_tag_name (spec->langsys, langsys);
2160 for (i = 0; i < 2; i++)
2162 char *p;
2164 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2166 for (j = 0; spec->features[i][j]; j++);
2167 if (i == 0)
2168 p = gsub_features = alloca (6 * j);
2169 else
2170 p = gpos_features = alloca (6 * j);
2171 for (j = 0; spec->features[i][j]; j++)
2173 if (spec->features[i][j] == 0xFFFFFFFF)
2174 *p++ = '*', *p++ = ',';
2175 else
2177 OTF_tag_name (spec->features[i][j], p);
2178 p[4] = ',';
2179 p += 5;
2182 *--p = '\0';
2186 setup_otf_gstring (len);
2187 for (i = 0; i < len; i++)
2189 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2190 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2193 OTF_drive_gdef (otf, &otf_gstring);
2194 gidx = out->used;
2196 if (gsub_features)
2198 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2199 < 0)
2200 goto simple_copy;
2201 if (out->allocated < out->used + otf_gstring.used)
2202 return -2;
2203 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2205 MFLTGlyph *g;
2206 int min_from, max_to;
2207 int j;
2209 g = out->glyphs + out->used;
2210 *g = in->glyphs[from + otfg->f.index.from];
2211 if (g->code != otfg->glyph_id)
2213 g->c = 0;
2214 g->code = otfg->glyph_id;
2215 g->measured = 0;
2217 out->used++;
2218 min_from = g->from;
2219 max_to = g->to;
2220 if (otfg->f.index.from < otfg->f.index.to)
2222 /* OTFG substitutes multiple glyphs in IN. */
2223 for (j = from + otfg->f.index.from + 1;
2224 j <= from + otfg->f.index.to; j++)
2226 if (min_from > in->glyphs[j].from)
2227 min_from = in->glyphs[j].from;
2228 if (max_to < in->glyphs[j].to)
2229 max_to = in->glyphs[j].to;
2231 g->from = min_from;
2232 g->to = max_to;
2234 for (i++, otfg++; (i < otf_gstring.used
2235 && otfg->f.index.from == otfg[-1].f.index.from);
2236 i++, otfg++)
2238 g = out->glyphs + out->used;
2239 *g = in->glyphs[from + otfg->f.index.to];
2240 if (g->code != otfg->glyph_id)
2242 g->c = 0;
2243 g->code = otfg->glyph_id;
2244 g->measured = 0;
2246 out->used++;
2250 else
2252 if (out->allocated < out->used + len)
2253 return -2;
2254 for (i = 0; i < len; i++)
2255 out->glyphs[out->used++] = in->glyphs[from + i];
2258 if (gpos_features)
2260 MFLTGlyph *base = NULL, *mark = NULL, *g;
2261 int x_ppem, y_ppem, x_scale, y_scale;
2263 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2264 < 0)
2265 return to;
2267 x_ppem = ft_face->size->metrics.x_ppem;
2268 y_ppem = ft_face->size->metrics.y_ppem;
2269 x_scale = ft_face->size->metrics.x_scale;
2270 y_scale = ft_face->size->metrics.y_scale;
2272 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2273 i < otf_gstring.used; i++, otfg++, g++)
2275 MFLTGlyph *prev;
2277 if (! otfg->glyph_id)
2278 continue;
2279 switch (otfg->positioning_type)
2281 case 0:
2282 break;
2283 case 1: /* Single */
2284 case 2: /* Pair */
2286 int format = otfg->f.f1.format;
2288 if (format & OTF_XPlacement)
2289 adjustment[i].xoff
2290 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2291 if (format & OTF_XPlaDevice)
2292 adjustment[i].xoff
2293 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2294 if (format & OTF_YPlacement)
2295 adjustment[i].yoff
2296 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2297 if (format & OTF_YPlaDevice)
2298 adjustment[i].yoff
2299 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2300 if (format & OTF_XAdvance)
2301 adjustment[i].xadv
2302 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2303 if (format & OTF_XAdvDevice)
2304 adjustment[i].xadv
2305 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2306 if (format & OTF_YAdvance)
2307 adjustment[i].yadv
2308 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2309 if (format & OTF_YAdvDevice)
2310 adjustment[i].yadv
2311 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2312 adjustment[i].set = 1;
2314 break;
2315 case 3: /* Cursive */
2316 /* Not yet supported. */
2317 break;
2318 case 4: /* Mark-to-Base */
2319 case 5: /* Mark-to-Ligature */
2320 if (! base)
2321 break;
2322 prev = base;
2323 goto label_adjust_anchor;
2324 default: /* i.e. case 6 Mark-to-Mark */
2325 if (! mark)
2326 break;
2327 prev = mark;
2329 label_adjust_anchor:
2331 int base_x, base_y, mark_x, mark_y;
2332 int this_from, this_to;
2334 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2335 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2336 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2337 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2339 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2340 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2341 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2342 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2343 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2344 x_ppem, y_ppem, &mark_x, &mark_y);
2345 adjustment[i].xoff = (base_x - mark_x);
2346 adjustment[i].yoff = - (base_y - mark_y);
2347 adjustment[i].back = (g - prev);
2348 adjustment[i].xadv = 0;
2349 adjustment[i].advance_is_absolute = 1;
2350 adjustment[i].set = 1;
2351 this_from = g->from;
2352 this_to = g->to;
2353 for (j = 0; prev + j < g; j++)
2355 if (this_from > prev[j].from)
2356 this_from = prev[j].from;
2357 if (this_to < prev[j].to)
2358 this_to = prev[j].to;
2360 for (; prev <= g; prev++)
2362 prev->from = this_from;
2363 prev->to = this_to;
2367 if (otfg->GlyphClass == OTF_GlyphClass0)
2368 base = mark = g;
2369 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2370 mark = g;
2371 else
2372 base = g;
2375 return to;
2377 simple_copy:
2378 if (out->allocated < out->used + len)
2379 return -2;
2380 font->get_metrics (font, in, from, to);
2381 memcpy (out->glyphs + out->used, in->glyphs + from,
2382 sizeof (MFLTGlyph) * len);
2383 out->used += len;
2384 return to;
2387 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2389 static MFLTGlyphString gstring;
2391 static bool m17n_flt_initialized;
2393 static Lisp_Object
2394 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2395 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2397 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2398 ptrdiff_t i;
2399 struct MFLTFontFT flt_font_ft;
2400 MFLT *flt = NULL;
2401 bool with_variation_selector = 0;
2403 if (! m17n_flt_initialized)
2405 M17N_INIT ();
2406 #ifdef M17N_FLT_USE_NEW_FEATURE
2407 mflt_enable_new_feature = 1;
2408 mflt_try_otf = ftfont_try_otf;
2409 #endif /* M17N_FLT_USE_NEW_FEATURE */
2410 m17n_flt_initialized = 1;
2413 for (i = 0; i < len; i++)
2415 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2416 int c;
2418 if (NILP (g))
2419 break;
2420 c = LGLYPH_CHAR (g);
2421 if (CHAR_VARIATION_SELECTOR_P (c))
2422 with_variation_selector = 1;
2425 len = i;
2427 if (with_variation_selector)
2429 setup_otf_gstring (len);
2430 for (i = 0; i < len; i++)
2432 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2434 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2435 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2436 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2438 OTF_drive_cmap (otf, &otf_gstring);
2439 for (i = 0; i < otf_gstring.used; i++)
2441 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2442 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2443 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2445 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2446 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2447 LGSTRING_SET_GLYPH (lgstring, i, g0);
2449 if (len > otf_gstring.used)
2451 len = otf_gstring.used;
2452 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2456 if (INT_MAX / 2 < len)
2457 memory_full (SIZE_MAX);
2459 if (gstring.allocated == 0)
2461 gstring.glyph_size = sizeof (MFLTGlyph);
2462 gstring.glyphs = xnmalloc (len * 2, sizeof *gstring.glyphs);
2463 gstring.allocated = len * 2;
2465 else if (gstring.allocated < len * 2)
2467 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2,
2468 sizeof *gstring.glyphs);
2469 gstring.allocated = len * 2;
2471 memset (gstring.glyphs, 0, len * sizeof *gstring.glyphs);
2472 for (i = 0; i < len; i++)
2474 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2476 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2477 if (with_variation_selector)
2479 gstring.glyphs[i].code = LGLYPH_CODE (g);
2480 gstring.glyphs[i].encoded = 1;
2484 gstring.used = len;
2485 gstring.r2l = 0;
2488 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2490 if (NILP (family))
2491 flt_font_ft.flt_font.family = Mnil;
2492 else
2493 flt_font_ft.flt_font.family
2494 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2496 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2497 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2498 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2499 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2500 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2501 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2502 flt_font_ft.flt_font.internal = NULL;
2503 flt_font_ft.font = font;
2504 flt_font_ft.ft_face = ft_face;
2505 flt_font_ft.otf = otf;
2506 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2507 if (len > 1
2508 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2509 /* A little bit ad hoc. Perhaps, shaper must get script and
2510 language information, and select a proper flt for them
2511 here. */
2512 flt = mflt_get (msymbol ("combining"));
2513 for (i = 0; i < 3; i++)
2515 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2516 if (result != -2)
2517 break;
2518 if (INT_MAX / 2 < gstring.allocated)
2519 memory_full (SIZE_MAX);
2520 gstring.glyphs = xnrealloc (gstring.glyphs,
2521 gstring.allocated, 2 * sizeof (MFLTGlyph));
2522 gstring.allocated *= 2;
2524 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2525 return Qnil;
2526 for (i = 0; i < gstring.used; i++)
2528 MFLTGlyph *g = gstring.glyphs + i;
2530 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2531 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2534 for (i = 0; i < gstring.used; i++)
2536 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2537 MFLTGlyph *g = gstring.glyphs + i;
2539 if (NILP (lglyph))
2541 lglyph = LGLYPH_NEW ();
2542 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2544 LGLYPH_SET_FROM (lglyph, g->from);
2545 LGLYPH_SET_TO (lglyph, g->to);
2546 LGLYPH_SET_CHAR (lglyph, g->c);
2547 LGLYPH_SET_CODE (lglyph, g->code);
2548 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2549 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2550 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2551 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2552 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2553 if (g->adjusted)
2555 Lisp_Object vec = make_uninit_vector (3);
2557 ASET (vec, 0, make_number (g->xoff >> 6));
2558 ASET (vec, 1, make_number (g->yoff >> 6));
2559 ASET (vec, 2, make_number (g->xadv >> 6));
2560 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2563 return make_number (i);
2566 Lisp_Object
2567 ftfont_shape (Lisp_Object lgstring)
2569 struct font *font;
2570 struct ftfont_info *ftfont_info;
2571 OTF *otf;
2573 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2574 ftfont_info = (struct ftfont_info *) font;
2575 otf = ftfont_get_otf (ftfont_info);
2576 if (! otf)
2577 return make_number (0);
2578 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2579 &ftfont_info->matrix);
2582 #endif /* HAVE_M17N_FLT */
2584 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2586 static int
2587 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2589 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2590 OTF *otf = ftfont_get_otf (ftfont_info);
2592 if (! otf)
2593 return 0;
2594 return OTF_get_variation_glyphs (otf, c, variations);
2597 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2598 #endif /* HAVE_LIBOTF */
2600 Lisp_Object
2601 ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
2603 FcChar8 *str;
2605 #ifdef FC_FONTFORMAT
2606 if (pattern)
2608 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2609 return Qnil;
2610 if (strcmp ((char *) str, "TrueType") == 0)
2611 return intern ("truetype");
2612 if (strcmp ((char *) str, "Type 1") == 0)
2613 return intern ("type1");
2614 if (strcmp ((char *) str, "PCF") == 0)
2615 return intern ("pcf");
2616 if (strcmp ((char *) str, "BDF") == 0)
2617 return intern ("bdf");
2619 #endif /* FC_FONTFORMAT */
2620 if (STRINGP (filename))
2622 int len = SBYTES (filename);
2624 if (len >= 4)
2626 str = (FcChar8 *) (SDATA (filename) + len - 4);
2627 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2628 return intern ("truetype");
2629 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2630 return intern ("type1");
2631 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2632 return intern ("pcf");
2633 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2634 return intern ("bdf");
2637 return intern ("unknown");
2640 static const char *const ftfont_booleans [] = {
2641 ":antialias",
2642 ":hinting",
2643 ":verticallayout",
2644 ":autohint",
2645 ":globaladvance",
2646 ":outline",
2647 ":scalable",
2648 ":minspace",
2649 ":embolden",
2650 NULL,
2653 static const char *const ftfont_non_booleans [] = {
2654 ":family",
2655 ":familylang",
2656 ":style",
2657 ":stylelang",
2658 ":fullname",
2659 ":fullnamelang",
2660 ":slant",
2661 ":weight",
2662 ":size",
2663 ":width",
2664 ":aspect",
2665 ":pixelsize",
2666 ":spacing",
2667 ":foundry",
2668 ":hintstyle",
2669 ":file",
2670 ":index",
2671 ":ftface",
2672 ":rasterizer",
2673 ":scale",
2674 ":dpi",
2675 ":rgba",
2676 ":lcdfilter",
2677 ":charset",
2678 ":lang",
2679 ":fontversion",
2680 ":capability",
2681 NULL,
2684 static void
2685 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2687 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2691 void
2692 syms_of_ftfont (void)
2694 DEFSYM (Qfreetype, "freetype");
2695 DEFSYM (Qmonospace, "monospace");
2696 DEFSYM (Qsans_serif, "sans-serif");
2697 DEFSYM (Qserif, "serif");
2698 DEFSYM (Qmono, "mono");
2699 DEFSYM (Qsans, "sans");
2700 DEFSYM (Qsans__serif, "sans serif");
2702 staticpro (&freetype_font_cache);
2703 freetype_font_cache = list1 (Qt);
2705 staticpro (&ftfont_generic_family_list);
2706 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2707 Fcons (Qsans_serif, Qt),
2708 Fcons (Qsans, Qt));
2710 staticpro (&ft_face_cache);
2711 ft_face_cache = Qnil;
2713 ftfont_driver.type = Qfreetype;
2714 register_font_driver (&ftfont_driver, NULL);