gnus-art.el (gnus-article-browse-delete-temp-files): Never ask again a user about...
[emacs.git] / src / ftfont.c
blobf07ad6f33c758f02b2682dffeac3be61797cf32f
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2012 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_value (NULL, 0);
397 XSAVE_VALUE (val)->integer = 0;
398 XSAVE_VALUE (val)->pointer = cache_data;
399 cache = Fcons (Qnil, val);
400 Fputhash (key, cache, ft_face_cache);
402 else
404 val = XCDR (cache);
405 cache_data = XSAVE_VALUE (val)->pointer;
408 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
409 return cache;
411 if (cache_for == FTFONT_CACHE_FOR_FACE
412 ? ! cache_data->ft_face : ! cache_data->fc_charset)
414 char *filename = SSDATA (XCAR (key));
415 int idx = XINT (XCDR (key));
417 if (cache_for == FTFONT_CACHE_FOR_FACE)
419 if (! ft_library
420 && FT_Init_FreeType (&ft_library) != 0)
421 return Qnil;
422 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
423 != 0)
424 return Qnil;
426 else
428 FcPattern *pat = NULL;
429 FcFontSet *fontset = NULL;
430 FcObjectSet *objset = NULL;
431 FcCharSet *charset = NULL;
433 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
434 FC_INDEX, FcTypeInteger, idx, NULL);
435 if (! pat)
436 goto finish;
437 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
438 if (! objset)
439 goto finish;
440 fontset = FcFontList (NULL, pat, objset);
441 if (! fontset)
442 goto finish;
443 if (fontset && fontset->nfont > 0
444 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
445 &charset)
446 == FcResultMatch))
447 cache_data->fc_charset = FcCharSetCopy (charset);
448 else
449 cache_data->fc_charset = FcCharSetCreate ();
451 finish:
452 if (fontset)
453 FcFontSetDestroy (fontset);
454 if (objset)
455 FcObjectSetDestroy (objset);
456 if (pat)
457 FcPatternDestroy (pat);
460 return cache;
463 FcCharSet *
464 ftfont_get_fc_charset (Lisp_Object entity)
466 Lisp_Object val, cache;
467 struct ftfont_cache_data *cache_data;
469 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
470 val = XCDR (cache);
471 cache_data = XSAVE_VALUE (val)->pointer;
472 return cache_data->fc_charset;
475 #ifdef HAVE_LIBOTF
476 static OTF *
477 ftfont_get_otf (struct ftfont_info *ftfont_info)
479 OTF *otf;
481 if (ftfont_info->otf)
482 return ftfont_info->otf;
483 if (! ftfont_info->maybe_otf)
484 return NULL;
485 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
486 if (! otf || OTF_get_table (otf, "head") < 0)
488 if (otf)
489 OTF_close (otf);
490 ftfont_info->maybe_otf = 0;
491 return NULL;
493 ftfont_info->otf = otf;
494 return otf;
496 #endif /* HAVE_LIBOTF */
498 static Lisp_Object ftfont_get_cache (FRAME_PTR);
499 static Lisp_Object ftfont_list (Lisp_Object, Lisp_Object);
500 static Lisp_Object ftfont_match (Lisp_Object, Lisp_Object);
501 static Lisp_Object ftfont_list_family (Lisp_Object);
502 static Lisp_Object ftfont_open (FRAME_PTR, Lisp_Object, int);
503 static void ftfont_close (FRAME_PTR, struct font *);
504 static int ftfont_has_char (Lisp_Object, int);
505 static unsigned ftfont_encode_char (struct font *, int);
506 static int ftfont_text_extents (struct font *, unsigned *, int,
507 struct font_metrics *);
508 static int ftfont_get_bitmap (struct font *, unsigned,
509 struct font_bitmap *, int);
510 static int ftfont_anchor_point (struct font *, unsigned, int,
511 int *, int *);
512 #ifdef HAVE_LIBOTF
513 static Lisp_Object ftfont_otf_capability (struct font *);
514 # ifdef HAVE_M17N_FLT
515 static Lisp_Object ftfont_shape (Lisp_Object);
516 # endif
517 #endif
519 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
520 static int ftfont_variation_glyphs (struct font *, int c,
521 unsigned variations[256]);
522 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
524 struct font_driver ftfont_driver =
526 LISP_INITIALLY_ZERO, /* Qfreetype */
527 0, /* case insensitive */
528 ftfont_get_cache,
529 ftfont_list,
530 ftfont_match,
531 ftfont_list_family,
532 NULL, /* free_entity */
533 ftfont_open,
534 ftfont_close,
535 /* We can't draw a text without device dependent functions. */
536 NULL, /* prepare_face */
537 NULL, /* done_face */
538 ftfont_has_char,
539 ftfont_encode_char,
540 ftfont_text_extents,
541 /* We can't draw a text without device dependent functions. */
542 NULL, /* draw */
543 ftfont_get_bitmap,
544 NULL, /* free_bitmap */
545 NULL, /* get_outline */
546 NULL, /* free_outline */
547 ftfont_anchor_point,
548 #ifdef HAVE_LIBOTF
549 ftfont_otf_capability,
550 #else /* not HAVE_LIBOTF */
551 NULL,
552 #endif /* not HAVE_LIBOTF */
553 NULL, /* otf_drive */
554 NULL, /* start_for_frame */
555 NULL, /* end_for_frame */
556 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
557 ftfont_shape,
558 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
559 NULL,
560 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
561 NULL, /* check */
563 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
564 ftfont_variation_glyphs,
565 #else
566 NULL,
567 #endif
569 ftfont_filter_properties, /* filter_properties */
572 static Lisp_Object
573 ftfont_get_cache (FRAME_PTR f)
575 return freetype_font_cache;
578 static int
579 ftfont_get_charset (Lisp_Object registry)
581 char *str = SSDATA (SYMBOL_NAME (registry));
582 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
583 Lisp_Object regexp;
584 int i, j;
586 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
588 if (str[i] == '.')
589 re[j++] = '\\';
590 else if (str[i] == '*')
591 re[j++] = '.';
592 re[j] = str[i];
593 if (re[j] == '?')
594 re[j] = '.';
596 re[j] = '\0';
597 regexp = make_unibyte_string (re, j);
598 for (i = 0; fc_charset_table[i].name; i++)
599 if (fast_c_string_match_ignore_case
600 (regexp, fc_charset_table[i].name,
601 strlen (fc_charset_table[i].name)) >= 0)
602 break;
603 if (! fc_charset_table[i].name)
604 return -1;
605 if (! fc_charset_table[i].fc_charset)
607 FcCharSet *charset = FcCharSetCreate ();
608 int *uniquifier = fc_charset_table[i].uniquifier;
610 if (! charset)
611 return -1;
612 for (j = 0; uniquifier[j]; j++)
613 if (! FcCharSetAddChar (charset, uniquifier[j]))
615 FcCharSetDestroy (charset);
616 return -1;
618 fc_charset_table[i].fc_charset = charset;
620 return i;
623 struct OpenTypeSpec
625 Lisp_Object script;
626 unsigned int script_tag, langsys_tag;
627 int nfeatures[2];
628 unsigned int *features[2];
631 #define OTF_SYM_TAG(SYM, TAG) \
632 do { \
633 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
634 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
635 } while (0)
637 #define OTF_TAG_STR(TAG, P) \
638 do { \
639 (P)[0] = (char) (TAG >> 24); \
640 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
641 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
642 (P)[3] = (char) (TAG & 0xFF); \
643 (P)[4] = '\0'; \
644 } while (0)
646 #ifdef HAVE_LIBOTF
647 #define OTF_TAG_SYM(SYM, TAG) \
648 do { \
649 char str[5]; \
651 OTF_TAG_STR (TAG, str); \
652 (SYM) = font_intern_prop (str, 4, 1); \
653 } while (0)
654 #endif
657 static struct OpenTypeSpec *
658 ftfont_get_open_type_spec (Lisp_Object otf_spec)
660 struct OpenTypeSpec *spec = malloc (sizeof *spec);
661 Lisp_Object val;
662 int i, j;
663 bool negative;
665 if (! spec)
666 return NULL;
667 spec->script = XCAR (otf_spec);
668 if (! NILP (spec->script))
670 OTF_SYM_TAG (spec->script, spec->script_tag);
671 val = assq_no_quit (spec->script, Votf_script_alist);
672 if (CONSP (val) && SYMBOLP (XCDR (val)))
673 spec->script = XCDR (val);
674 else
675 spec->script = Qnil;
677 else
678 spec->script_tag = 0x44464C54; /* "DFLT" */
679 otf_spec = XCDR (otf_spec);
680 spec->langsys_tag = 0;
681 if (! NILP (otf_spec))
683 val = XCAR (otf_spec);
684 if (! NILP (val))
685 OTF_SYM_TAG (val, spec->langsys_tag);
686 otf_spec = XCDR (otf_spec);
688 spec->nfeatures[0] = spec->nfeatures[1] = 0;
689 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
691 Lisp_Object len;
693 val = XCAR (otf_spec);
694 if (NILP (val))
695 continue;
696 len = Flength (val);
697 spec->features[i] =
698 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
700 : malloc (XINT (len) * sizeof *spec->features[i]));
701 if (! spec->features[i])
703 if (i > 0 && spec->features[0])
704 free (spec->features[0]);
705 free (spec);
706 return NULL;
708 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
710 if (NILP (XCAR (val)))
711 negative = 1;
712 else
714 unsigned int tag;
716 OTF_SYM_TAG (XCAR (val), tag);
717 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
720 spec->nfeatures[i] = j;
722 return spec;
725 static FcPattern *
726 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
728 Lisp_Object tmp, extra;
729 FcPattern *pattern = NULL;
730 FcCharSet *charset = NULL;
731 FcLangSet *langset = NULL;
732 int n;
733 int dpi = -1;
734 int scalable = -1;
735 Lisp_Object script = Qnil;
736 Lisp_Object registry;
737 int fc_charset_idx;
739 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
740 && n < 100)
741 /* Fontconfig doesn't support reverse-italic/oblique. */
742 return NULL;
744 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
745 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
746 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
747 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
748 scalable = 1;
750 registry = AREF (spec, FONT_REGISTRY_INDEX);
751 if (NILP (registry)
752 || EQ (registry, Qascii_0)
753 || EQ (registry, Qiso10646_1)
754 || EQ (registry, Qunicode_bmp))
755 fc_charset_idx = -1;
756 else
758 FcChar8 *lang;
760 fc_charset_idx = ftfont_get_charset (registry);
761 if (fc_charset_idx < 0)
762 return NULL;
763 charset = fc_charset_table[fc_charset_idx].fc_charset;
764 *langname = fc_charset_table[fc_charset_idx].lang;
765 lang = (FcChar8 *) *langname;
766 if (lang)
768 langset = FcLangSetCreate ();
769 if (! langset)
770 goto err;
771 FcLangSetAdd (langset, lang);
775 otlayout[0] = '\0';
776 for (extra = AREF (spec, FONT_EXTRA_INDEX);
777 CONSP (extra); extra = XCDR (extra))
779 Lisp_Object key, val;
781 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
782 if (EQ (key, QCdpi))
784 if (INTEGERP (val))
785 dpi = XINT (val);
787 else if (EQ (key, QClang))
789 if (! langset)
790 langset = FcLangSetCreate ();
791 if (! langset)
792 goto err;
793 if (SYMBOLP (val))
795 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
796 goto err;
798 else
799 for (; CONSP (val); val = XCDR (val))
800 if (SYMBOLP (XCAR (val))
801 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
802 goto err;
804 else if (EQ (key, QCotf))
806 if (CONSP (val))
808 *otspec = ftfont_get_open_type_spec (val);
809 if (! *otspec)
810 return NULL;
811 strcat (otlayout, "otlayout:");
812 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
813 script = (*otspec)->script;
816 else if (EQ (key, QCscript))
817 script = val;
818 else if (EQ (key, QCscalable))
819 scalable = ! NILP (val);
822 if (! NILP (script) && ! charset)
824 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
826 if (CONSP (chars) && CONSP (CDR (chars)))
828 charset = FcCharSetCreate ();
829 if (! charset)
830 goto err;
831 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
832 if (CHARACTERP (XCAR (chars))
833 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
834 goto err;
838 pattern = FcPatternCreate ();
839 if (! pattern)
840 goto err;
841 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
842 if (! NILP (tmp)
843 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
844 goto err;
845 tmp = AREF (spec, FONT_FAMILY_INDEX);
846 if (! NILP (tmp)
847 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
848 goto err;
849 if (charset
850 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
851 goto err;
852 if (langset
853 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
854 goto err;
855 if (dpi >= 0
856 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
857 goto err;
858 if (scalable >= 0
859 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
860 goto err;
862 goto finish;
864 err:
865 /* We come here because of unexpected error in fontconfig API call
866 (usually insufficient memory). */
867 if (pattern)
869 FcPatternDestroy (pattern);
870 pattern = NULL;
872 if (*otspec)
874 if ((*otspec)->nfeatures[0] > 0)
875 free ((*otspec)->features[0]);
876 if ((*otspec)->nfeatures[1] > 0)
877 free ((*otspec)->features[1]);
878 free (*otspec);
879 *otspec = NULL;
882 finish:
883 if (langset) FcLangSetDestroy (langset);
884 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
885 return pattern;
888 static Lisp_Object
889 ftfont_list (Lisp_Object frame, Lisp_Object spec)
891 Lisp_Object val = Qnil, family, adstyle;
892 int i;
893 FcPattern *pattern;
894 FcFontSet *fontset = NULL;
895 FcObjectSet *objset = NULL;
896 FcCharSet *charset;
897 Lisp_Object chars = Qnil;
898 char otlayout[15]; /* For "otlayout:XXXX" */
899 struct OpenTypeSpec *otspec = NULL;
900 int spacing = -1;
901 const char *langname = NULL;
903 if (! fc_initialized)
905 FcInit ();
906 fc_initialized = 1;
909 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
910 if (! pattern)
911 return Qnil;
912 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
914 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
915 if (! NILP (val))
917 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
918 if (CONSP (val) && VECTORP (XCDR (val)))
919 chars = XCDR (val);
921 val = Qnil;
923 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
924 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
925 family = AREF (spec, FONT_FAMILY_INDEX);
926 if (! NILP (family))
928 Lisp_Object resolved;
930 resolved = ftfont_resolve_generic_family (family, pattern);
931 if (! NILP (resolved))
933 FcPatternDel (pattern, FC_FAMILY);
934 if (! FcPatternAddString (pattern, FC_FAMILY,
935 SYMBOL_FcChar8 (resolved)))
936 goto err;
939 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
940 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
941 adstyle = Qnil;
942 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
943 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
944 FC_STYLE, FC_FILE, FC_INDEX,
945 #ifdef FC_CAPABILITY
946 FC_CAPABILITY,
947 #endif /* FC_CAPABILITY */
948 #ifdef FC_FONTFORMAT
949 FC_FONTFORMAT,
950 #endif
951 NULL);
952 if (! objset)
953 goto err;
954 if (! NILP (chars))
955 FcObjectSetAdd (objset, FC_CHARSET);
957 fontset = FcFontList (NULL, pattern, objset);
958 if (! fontset || fontset->nfont == 0)
959 goto finish;
960 #if 0
961 /* Need fix because this finds any fonts. */
962 if (fontset->nfont == 0 && ! NILP (family))
964 /* Try matching with configuration. For instance, the
965 configuration may specify "Nimbus Mono L" as an alias of
966 "Courier". */
967 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
968 SYMBOL_FcChar8 (family), NULL);
969 FcChar8 *fam;
971 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
973 for (i = 0;
974 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
975 i++)
977 FcPatternDel (pattern, FC_FAMILY);
978 FcPatternAddString (pattern, FC_FAMILY, fam);
979 FcFontSetDestroy (fontset);
980 fontset = FcFontList (NULL, pattern, objset);
981 if (fontset && fontset->nfont > 0)
982 break;
986 #endif
987 for (i = 0; i < fontset->nfont; i++)
989 Lisp_Object entity;
991 if (spacing >= 0)
993 int this;
995 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
996 == FcResultMatch)
997 && spacing != this)
998 continue;
1001 #ifdef FC_CAPABILITY
1002 if (otlayout[0])
1004 FcChar8 *this;
1006 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
1007 != FcResultMatch
1008 || ! strstr ((char *) this, otlayout))
1009 continue;
1011 #endif /* FC_CAPABILITY */
1012 #ifdef HAVE_LIBOTF
1013 if (otspec)
1015 FcChar8 *file;
1016 OTF *otf;
1018 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1019 != FcResultMatch)
1020 continue;
1021 otf = OTF_open ((char *) file);
1022 if (! otf)
1023 continue;
1024 if (OTF_check_features (otf, 1,
1025 otspec->script_tag, otspec->langsys_tag,
1026 otspec->features[0],
1027 otspec->nfeatures[0]) != 1
1028 || OTF_check_features (otf, 0,
1029 otspec->script_tag, otspec->langsys_tag,
1030 otspec->features[1],
1031 otspec->nfeatures[1]) != 1)
1032 continue;
1034 #endif /* HAVE_LIBOTF */
1035 if (VECTORP (chars))
1037 ptrdiff_t j;
1039 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1040 != FcResultMatch)
1041 continue;
1042 for (j = 0; j < ASIZE (chars); j++)
1043 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1044 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1045 break;
1046 if (j == ASIZE (chars))
1047 continue;
1049 if (! NILP (adstyle) || langname)
1051 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1053 if (! NILP (adstyle)
1054 && (NILP (this_adstyle)
1055 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1056 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1057 continue;
1058 if (langname
1059 && ! NILP (this_adstyle)
1060 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1061 continue;
1063 entity = ftfont_pattern_entity (fontset->fonts[i],
1064 AREF (spec, FONT_EXTRA_INDEX));
1065 if (! NILP (entity))
1066 val = Fcons (entity, val);
1068 val = Fnreverse (val);
1069 goto finish;
1071 err:
1072 /* We come here because of unexpected error in fontconfig API call
1073 (usually insufficient memory). */
1074 val = Qnil;
1076 finish:
1077 FONT_ADD_LOG ("ftfont-list", spec, val);
1078 if (objset) FcObjectSetDestroy (objset);
1079 if (fontset) FcFontSetDestroy (fontset);
1080 if (pattern) FcPatternDestroy (pattern);
1081 return val;
1084 static Lisp_Object
1085 ftfont_match (Lisp_Object frame, Lisp_Object spec)
1087 Lisp_Object entity = Qnil;
1088 FcPattern *pattern, *match = NULL;
1089 FcResult result;
1090 char otlayout[15]; /* For "otlayout:XXXX" */
1091 struct OpenTypeSpec *otspec = NULL;
1092 const char *langname = NULL;
1094 if (! fc_initialized)
1096 FcInit ();
1097 fc_initialized = 1;
1100 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1101 if (! pattern)
1102 return Qnil;
1104 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1106 FcValue value;
1108 value.type = FcTypeDouble;
1109 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1110 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1112 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1114 FcDefaultSubstitute (pattern);
1115 match = FcFontMatch (NULL, pattern, &result);
1116 if (match)
1118 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1119 FcPatternDestroy (match);
1120 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1121 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1122 ftfont_generic_family_list))
1123 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1124 AREF (entity, FONT_FAMILY_INDEX))))
1125 entity = Qnil;
1128 FcPatternDestroy (pattern);
1130 FONT_ADD_LOG ("ftfont-match", spec, entity);
1131 return entity;
1134 static Lisp_Object
1135 ftfont_list_family (Lisp_Object frame)
1137 Lisp_Object list = Qnil;
1138 FcPattern *pattern = NULL;
1139 FcFontSet *fontset = NULL;
1140 FcObjectSet *objset = NULL;
1141 int i;
1143 if (! fc_initialized)
1145 FcInit ();
1146 fc_initialized = 1;
1149 pattern = FcPatternCreate ();
1150 if (! pattern)
1151 goto finish;
1152 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1153 if (! objset)
1154 goto finish;
1155 fontset = FcFontList (NULL, pattern, objset);
1156 if (! fontset)
1157 goto finish;
1159 for (i = 0; i < fontset->nfont; i++)
1161 FcPattern *pat = fontset->fonts[i];
1162 FcChar8 *str;
1164 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1165 list = Fcons (intern ((char *) str), list);
1168 finish:
1169 if (objset) FcObjectSetDestroy (objset);
1170 if (fontset) FcFontSetDestroy (fontset);
1171 if (pattern) FcPatternDestroy (pattern);
1173 return list;
1177 static Lisp_Object
1178 ftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
1180 struct ftfont_info *ftfont_info;
1181 struct font *font;
1182 struct ftfont_cache_data *cache_data;
1183 FT_Face ft_face;
1184 FT_Size ft_size;
1185 FT_UInt size;
1186 Lisp_Object val, filename, idx, cache, font_object;
1187 bool scalable;
1188 int spacing;
1189 char name[256];
1190 int i, len;
1191 int upEM;
1193 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1194 if (! CONSP (val))
1195 return Qnil;
1196 val = XCDR (val);
1197 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1198 if (NILP (cache))
1199 return Qnil;
1200 filename = XCAR (val);
1201 idx = XCDR (val);
1202 val = XCDR (cache);
1203 cache_data = XSAVE_VALUE (XCDR (cache))->pointer;
1204 ft_face = cache_data->ft_face;
1205 if (XSAVE_VALUE (val)->integer > 0)
1207 /* FT_Face in this cache is already used by the different size. */
1208 if (FT_New_Size (ft_face, &ft_size) != 0)
1209 return Qnil;
1210 if (FT_Activate_Size (ft_size) != 0)
1212 FT_Done_Size (ft_size);
1213 return Qnil;
1216 XSAVE_VALUE (val)->integer++;
1217 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1218 if (size == 0)
1219 size = pixel_size;
1220 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1222 if (XSAVE_VALUE (val)->integer == 0)
1223 FT_Done_Face (ft_face);
1224 return Qnil;
1227 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
1228 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
1229 len = font_unparse_xlfd (entity, size, name, 256);
1230 if (len > 0)
1231 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
1232 len = font_unparse_fcname (entity, size, name, 256);
1233 if (len > 0)
1234 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
1235 else
1236 ASET (font_object, FONT_FULLNAME_INDEX,
1237 AREF (font_object, FONT_NAME_INDEX));
1238 ASET (font_object, FONT_FILE_INDEX, filename);
1239 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
1240 font = XFONT_OBJECT (font_object);
1241 ftfont_info = (struct ftfont_info *) font;
1242 ftfont_info->ft_size = ft_face->size;
1243 ftfont_info->index = XINT (idx);
1244 #ifdef HAVE_LIBOTF
1245 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1246 ftfont_info->otf = NULL;
1247 #endif /* HAVE_LIBOTF */
1248 /* This means that there's no need of transformation. */
1249 ftfont_info->matrix.xx = 0;
1250 font->pixel_size = size;
1251 font->driver = &ftfont_driver;
1252 font->encoding_charset = font->repertory_charset = -1;
1254 upEM = ft_face->units_per_EM;
1255 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1256 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1257 if (scalable)
1259 font->ascent = ft_face->ascender * size / upEM;
1260 font->descent = - ft_face->descender * size / upEM;
1261 font->height = ft_face->height * size / upEM;
1263 else
1265 font->ascent = ft_face->size->metrics.ascender >> 6;
1266 font->descent = - ft_face->size->metrics.descender >> 6;
1267 font->height = ft_face->size->metrics.height >> 6;
1269 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1270 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1271 else
1272 spacing = FC_PROPORTIONAL;
1273 if (spacing != FC_PROPORTIONAL
1274 #ifdef FC_DUAL
1275 && spacing != FC_DUAL
1276 #endif /* FC_DUAL */
1278 font->min_width = font->average_width = font->space_width
1279 = (scalable ? ft_face->max_advance_width * size / upEM
1280 : ft_face->size->metrics.max_advance >> 6);
1281 else
1283 int n;
1285 font->min_width = font->average_width = font->space_width = 0;
1286 for (i = 32, n = 0; i < 127; i++)
1287 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1289 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1291 if (this_width > 0
1292 && (! font->min_width || font->min_width > this_width))
1293 font->min_width = this_width;
1294 if (i == 32)
1295 font->space_width = this_width;
1296 font->average_width += this_width;
1297 n++;
1299 if (n > 0)
1300 font->average_width /= n;
1303 font->baseline_offset = 0;
1304 font->relative_compose = 0;
1305 font->default_ascent = 0;
1306 font->vertical_centering = 0;
1307 if (scalable)
1309 font->underline_position = -ft_face->underline_position * size / upEM;
1310 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1312 else
1314 font->underline_position = -1;
1315 font->underline_thickness = 0;
1318 return font_object;
1321 static void
1322 ftfont_close (FRAME_PTR f, struct font *font)
1324 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1325 Lisp_Object val, cache;
1327 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1328 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1329 eassert (CONSP (cache));
1330 val = XCDR (cache);
1331 (XSAVE_VALUE (val)->integer)--;
1332 if (XSAVE_VALUE (val)->integer == 0)
1334 struct ftfont_cache_data *cache_data = XSAVE_VALUE (val)->pointer;
1336 FT_Done_Face (cache_data->ft_face);
1337 #ifdef HAVE_LIBOTF
1338 if (ftfont_info->otf)
1339 OTF_close (ftfont_info->otf);
1340 #endif
1341 cache_data->ft_face = NULL;
1343 else
1344 FT_Done_Size (ftfont_info->ft_size);
1347 static int
1348 ftfont_has_char (Lisp_Object font, int c)
1350 struct charset *cs = NULL;
1352 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1353 && charset_jisx0208 >= 0)
1354 cs = CHARSET_FROM_ID (charset_jisx0208);
1355 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1356 && charset_ksc5601 >= 0)
1357 cs = CHARSET_FROM_ID (charset_ksc5601);
1358 if (cs)
1359 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1361 if (FONT_ENTITY_P (font))
1363 FcCharSet *charset = ftfont_get_fc_charset (font);
1365 return (FcCharSetHasChar (charset, c) == FcTrue);
1367 else
1369 struct ftfont_info *ftfont_info;
1371 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1372 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1373 != 0);
1377 static unsigned
1378 ftfont_encode_char (struct font *font, int c)
1380 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1381 FT_Face ft_face = ftfont_info->ft_size->face;
1382 FT_ULong charcode = c;
1383 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1385 return (code > 0 ? code : FONT_INVALID_CODE);
1388 static int
1389 ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
1391 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1392 FT_Face ft_face = ftfont_info->ft_size->face;
1393 int width = 0;
1394 int i;
1395 bool first;
1397 if (ftfont_info->ft_size != ft_face->size)
1398 FT_Activate_Size (ftfont_info->ft_size);
1399 if (metrics)
1400 memset (metrics, 0, sizeof (struct font_metrics));
1401 for (i = 0, first = 1; i < nglyphs; i++)
1403 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1405 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1407 if (first)
1409 if (metrics)
1411 metrics->lbearing = m->horiBearingX >> 6;
1412 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1413 metrics->ascent = m->horiBearingY >> 6;
1414 metrics->descent = (m->height - m->horiBearingY) >> 6;
1416 first = 0;
1418 if (metrics)
1420 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1421 metrics->lbearing = width + (m->horiBearingX >> 6);
1422 if (metrics->rbearing
1423 < width + ((m->horiBearingX + m->width) >> 6))
1424 metrics->rbearing
1425 = width + ((m->horiBearingX + m->width) >> 6);
1426 if (metrics->ascent < (m->horiBearingY >> 6))
1427 metrics->ascent = m->horiBearingY >> 6;
1428 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1429 metrics->descent = (m->height - m->horiBearingY) >> 6;
1431 width += m->horiAdvance >> 6;
1433 else
1435 width += font->space_width;
1438 if (metrics)
1439 metrics->width = width;
1441 return width;
1444 static int
1445 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1447 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1448 FT_Face ft_face = ftfont_info->ft_size->face;
1449 FT_Int32 load_flags = FT_LOAD_RENDER;
1451 if (ftfont_info->ft_size != ft_face->size)
1452 FT_Activate_Size (ftfont_info->ft_size);
1453 if (bits_per_pixel == 1)
1455 #ifdef FT_LOAD_TARGET_MONO
1456 load_flags |= FT_LOAD_TARGET_MONO;
1457 #else
1458 load_flags |= FT_LOAD_MONOCHROME;
1459 #endif
1461 else if (bits_per_pixel != 8)
1462 /* We don't support such a rendering. */
1463 return -1;
1465 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1466 return -1;
1467 bitmap->bits_per_pixel
1468 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1469 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1470 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1471 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1472 : -1);
1473 if (bitmap->bits_per_pixel < 0)
1474 /* We don't support that kind of pixel mode. */
1475 return -1;
1476 bitmap->rows = ft_face->glyph->bitmap.rows;
1477 bitmap->width = ft_face->glyph->bitmap.width;
1478 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1479 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1480 bitmap->left = ft_face->glyph->bitmap_left;
1481 bitmap->top = ft_face->glyph->bitmap_top;
1482 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1483 bitmap->extra = NULL;
1485 return 0;
1488 static int
1489 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1490 int *x, int *y)
1492 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1493 FT_Face ft_face = ftfont_info->ft_size->face;
1495 if (ftfont_info->ft_size != ft_face->size)
1496 FT_Activate_Size (ftfont_info->ft_size);
1497 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1498 return -1;
1499 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1500 return -1;
1501 if (idx >= ft_face->glyph->outline.n_points)
1502 return -1;
1503 *x = ft_face->glyph->outline.points[idx].x;
1504 *y = ft_face->glyph->outline.points[idx].y;
1505 return 0;
1508 #ifdef HAVE_LIBOTF
1510 static Lisp_Object
1511 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1513 Lisp_Object scripts, langsyses, features, sym;
1514 int i, j, k, l;
1516 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1518 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1520 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1522 OTF_LangSys *otf_langsys;
1524 if (j >= 0)
1525 otf_langsys = otf_script->LangSys + j;
1526 else if (otf_script->DefaultLangSysOffset)
1527 otf_langsys = &otf_script->DefaultLangSys;
1528 else
1529 break;
1531 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1533 l = otf_langsys->FeatureIndex[k];
1534 if (l >= gsub_gpos->FeatureList.FeatureCount)
1535 continue;
1536 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1537 features = Fcons (sym, features);
1539 if (j >= 0)
1540 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1541 else
1542 sym = Qnil;
1543 langsyses = Fcons (Fcons (sym, features), langsyses);
1546 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1547 scripts = Fcons (Fcons (sym, langsyses), scripts);
1549 return scripts;
1554 static Lisp_Object
1555 ftfont_otf_capability (struct font *font)
1557 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1558 OTF *otf = ftfont_get_otf (ftfont_info);
1559 Lisp_Object gsub_gpos;
1561 if (! otf)
1562 return Qnil;
1563 gsub_gpos = Fcons (Qnil, Qnil);
1564 if (OTF_get_table (otf, "GSUB") == 0
1565 && otf->gsub->FeatureList.FeatureCount > 0)
1566 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1567 if (OTF_get_table (otf, "GPOS") == 0
1568 && otf->gpos->FeatureList.FeatureCount > 0)
1569 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1570 return gsub_gpos;
1573 #ifdef HAVE_M17N_FLT
1575 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1576 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1577 /* We can use the new feature of libotf and m17n-flt to handle the
1578 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1579 some Agian scripts. */
1580 #define M17N_FLT_USE_NEW_FEATURE
1581 #endif
1583 struct MFLTFontFT
1585 MFLTFont flt_font;
1586 struct font *font;
1587 FT_Face ft_face;
1588 OTF *otf;
1589 FT_Matrix *matrix;
1592 static int
1593 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1594 int from, int to)
1596 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1597 FT_Face ft_face = flt_font_ft->ft_face;
1598 MFLTGlyph *g;
1600 for (g = gstring->glyphs + from; from < to; g++, from++)
1601 if (! g->encoded)
1603 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1605 g->code = code > 0 ? code : FONT_INVALID_CODE;
1606 g->encoded = 1;
1608 return 0;
1611 /* Operators for 26.6 fixed fractional pixel format */
1613 #define FLOOR(x) ((x) & -64)
1614 #define CEIL(x) (((x)+63) & -64)
1615 #define ROUND(x) (((x)+32) & -64)
1617 static int
1618 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1619 int from, int to)
1621 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1622 FT_Face ft_face = flt_font_ft->ft_face;
1623 MFLTGlyph *g;
1625 for (g = gstring->glyphs + from; from < to; g++, from++)
1626 if (! g->measured)
1628 if (g->code != FONT_INVALID_CODE)
1630 FT_Glyph_Metrics *m;
1632 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1633 emacs_abort ();
1634 m = &ft_face->glyph->metrics;
1635 if (flt_font_ft->matrix)
1637 FT_Vector v[4];
1638 int i;
1640 v[0].x = v[1].x = m->horiBearingX;
1641 v[2].x = v[3].x = m->horiBearingX + m->width;
1642 v[0].y = v[2].y = m->horiBearingY;
1643 v[1].y = v[3].y = m->horiBearingY - m->height;
1644 for (i = 0; i < 4; i++)
1645 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1646 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1647 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1648 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1649 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1651 else
1653 g->lbearing = FLOOR (m->horiBearingX);
1654 g->rbearing = CEIL (m->horiBearingX + m->width);
1655 g->ascent = CEIL (m->horiBearingY);
1656 g->descent = - FLOOR (m->horiBearingY - m->height);
1658 g->xadv = ROUND (ft_face->glyph->advance.x);
1660 else
1662 g->lbearing = 0;
1663 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1664 g->ascent = flt_font_ft->font->ascent << 6;
1665 g->descent = flt_font_ft->font->descent << 6;
1667 g->yadv = 0;
1668 g->measured = 1;
1670 return 0;
1673 static int
1674 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1676 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1678 #define FEATURE_ANY(IDX) \
1679 (spec->features[IDX] \
1680 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1682 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1683 OTF *otf = flt_font_ft->otf;
1684 OTF_Tag *tags;
1685 int i, n;
1686 bool negative;
1688 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1689 /* Return true iff any of GSUB or GPOS support the script (and
1690 language). */
1691 return (otf
1692 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1693 NULL, 0) > 0
1694 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1695 NULL, 0) > 0));
1697 for (i = 0; i < 2; i++)
1698 if (! FEATURE_ANY (i))
1700 if (FEATURE_NONE (i))
1702 if (otf
1703 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1704 NULL, 0) > 0)
1705 return 0;
1706 continue;
1708 if (spec->features[i][0] == 0xFFFFFFFF)
1710 if (! otf
1711 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1712 NULL, 0) <= 0)
1713 continue;
1715 else if (! otf)
1716 return 0;
1717 for (n = 1; spec->features[i][n]; n++);
1718 tags = alloca (sizeof (OTF_Tag) * n);
1719 for (n = 0, negative = 0; spec->features[i][n]; n++)
1721 if (spec->features[i][n] == 0xFFFFFFFF)
1722 negative = 1;
1723 else if (negative)
1724 tags[n - 1] = spec->features[i][n] | 0x80000000;
1725 else
1726 tags[n] = spec->features[i][n];
1728 #ifdef M17N_FLT_USE_NEW_FEATURE
1729 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1730 tags, n - negative) != 1)
1731 return 0;
1732 #else /* not M17N_FLT_USE_NEW_FEATURE */
1733 if (n - negative > 0
1734 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1735 tags, n - negative) != 1)
1736 return 0;
1737 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1739 return 1;
1740 #undef FEATURE_NONE
1741 #undef FEATURE_ANY
1744 #define DEVICE_DELTA(table, size) \
1745 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1746 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1747 : 0)
1749 static void
1750 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1751 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1753 if (anchor->AnchorFormat == 2)
1755 FT_Outline *outline;
1756 int ap = anchor->f.f1.AnchorPoint;
1758 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1759 outline = &ft_face->glyph->outline;
1760 if (ap < outline->n_points)
1762 *x = outline->points[ap].x << 6;
1763 *y = outline->points[ap].y << 6;
1766 else if (anchor->AnchorFormat == 3)
1768 if (anchor->f.f2.XDeviceTable.offset
1769 && anchor->f.f2.XDeviceTable.DeltaValue)
1770 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1771 if (anchor->f.f2.YDeviceTable.offset
1772 && anchor->f.f2.YDeviceTable.DeltaValue)
1773 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1777 static OTF_GlyphString otf_gstring;
1779 static void
1780 setup_otf_gstring (int size)
1782 if (otf_gstring.size < size)
1784 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1785 size, sizeof (OTF_Glyph));
1786 otf_gstring.size = size;
1788 otf_gstring.used = size;
1789 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1792 #ifdef M17N_FLT_USE_NEW_FEATURE
1794 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1795 #define PACK_OTF_TAG(TAG) \
1796 ((((TAG) & 0x7F000000) >> 3) \
1797 | (((TAG) & 0x7F0000) >> 2) \
1798 | (((TAG) & 0x7F00) >> 1) \
1799 | ((TAG) & 0x7F))
1801 /* Assuming that FONT is an OpenType font, apply OpenType features
1802 specified in SPEC on glyphs between FROM and TO of IN, and record
1803 the lastly applied feature in each glyph of IN. If OUT is not
1804 NULL, append the resulting glyphs to OUT while storing glyph
1805 position adjustment information in ADJUSTMENT. */
1807 static int
1808 ftfont_drive_otf (MFLTFont *font,
1809 MFLTOtfSpec *spec,
1810 MFLTGlyphString *in,
1811 int from,
1812 int to,
1813 MFLTGlyphString *out,
1814 MFLTGlyphAdjustment *adjustment)
1816 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1817 FT_Face ft_face = flt_font_ft->ft_face;
1818 OTF *otf = flt_font_ft->otf;
1819 int len = to - from;
1820 int i, j, gidx;
1821 OTF_Glyph *otfg;
1822 char script[5], *langsys = NULL;
1823 char *gsub_features = NULL, *gpos_features = NULL;
1824 OTF_Feature *features;
1826 if (len == 0)
1827 return from;
1828 OTF_tag_name (spec->script, script);
1829 if (spec->langsys)
1831 langsys = alloca (5);
1832 OTF_tag_name (spec->langsys, langsys);
1834 for (i = 0; i < 2; i++)
1836 char *p;
1838 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1840 for (j = 0; spec->features[i][j]; j++);
1841 if (i == 0)
1842 p = gsub_features = alloca (6 * j);
1843 else
1844 p = gpos_features = alloca (6 * j);
1845 for (j = 0; spec->features[i][j]; j++)
1847 if (spec->features[i][j] == 0xFFFFFFFF)
1848 *p++ = '*', *p++ = ',';
1849 else
1851 OTF_tag_name (spec->features[i][j], p);
1852 p[4] = ',';
1853 p += 5;
1856 *--p = '\0';
1860 setup_otf_gstring (len);
1861 for (i = 0; i < len; i++)
1863 otf_gstring.glyphs[i].c = in->glyphs[from + i].c & 0x11FFFF;
1864 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1867 OTF_drive_gdef (otf, &otf_gstring);
1868 gidx = out ? out->used : from;
1870 if (gsub_features && out)
1872 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1873 gsub_features) < 0)
1874 goto simple_copy;
1875 if (out->allocated < out->used + otf_gstring.used)
1876 return -2;
1877 features = otf->gsub->FeatureList.Feature;
1878 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1880 MFLTGlyph *g;
1881 int min_from, max_to;
1882 int feature_idx = otfg->positioning_type >> 4;
1884 g = out->glyphs + out->used;
1885 *g = in->glyphs[from + otfg->f.index.from];
1886 if (g->code != otfg->glyph_id)
1888 g->c = 0;
1889 g->code = otfg->glyph_id;
1890 g->measured = 0;
1892 out->used++;
1893 min_from = g->from;
1894 max_to = g->to;
1895 if (otfg->f.index.from < otfg->f.index.to)
1897 /* OTFG substitutes multiple glyphs in IN. */
1898 for (j = from + otfg->f.index.from + 1;
1899 j <= from + otfg->f.index.to; j++)
1901 if (min_from > in->glyphs[j].from)
1902 min_from = in->glyphs[j].from;
1903 if (max_to < in->glyphs[j].to)
1904 max_to = in->glyphs[j].to;
1906 g->from = min_from;
1907 g->to = max_to;
1909 if (feature_idx)
1911 unsigned int tag = features[feature_idx - 1].FeatureTag;
1912 tag = PACK_OTF_TAG (tag);
1913 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1915 for (i++, otfg++; (i < otf_gstring.used
1916 && otfg->f.index.from == otfg[-1].f.index.from);
1917 i++, otfg++)
1919 g = out->glyphs + out->used;
1920 *g = in->glyphs[from + otfg->f.index.to];
1921 if (g->code != otfg->glyph_id)
1923 g->c = 0;
1924 g->code = otfg->glyph_id;
1925 g->measured = 0;
1927 feature_idx = otfg->positioning_type >> 4;
1928 if (feature_idx)
1930 unsigned int tag = features[feature_idx - 1].FeatureTag;
1931 tag = PACK_OTF_TAG (tag);
1932 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1934 out->used++;
1938 else if (gsub_features)
1940 /* Just for checking which features will be applied. */
1941 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1942 gsub_features) < 0)
1943 goto simple_copy;
1944 features = otf->gsub->FeatureList.Feature;
1945 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1946 otfg++)
1948 int feature_idx = otfg->positioning_type >> 4;
1950 if (feature_idx)
1952 unsigned int tag = features[feature_idx - 1].FeatureTag;
1953 tag = PACK_OTF_TAG (tag);
1954 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1956 MFLTGlyph *g = in->glyphs + (from + j);
1957 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1962 else if (out)
1964 if (out->allocated < out->used + len)
1965 return -2;
1966 for (i = 0; i < len; i++)
1967 out->glyphs[out->used++] = in->glyphs[from + i];
1970 if (gpos_features && out)
1972 MFLTGlyph *base = NULL, *mark = NULL, *g;
1973 int x_ppem, y_ppem, x_scale, y_scale;
1975 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1976 gpos_features) < 0)
1977 return to;
1978 features = otf->gpos->FeatureList.Feature;
1979 x_ppem = ft_face->size->metrics.x_ppem;
1980 y_ppem = ft_face->size->metrics.y_ppem;
1981 x_scale = ft_face->size->metrics.x_scale;
1982 y_scale = ft_face->size->metrics.y_scale;
1984 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1985 i < otf_gstring.used; i++, otfg++, g++)
1987 MFLTGlyph *prev;
1988 int feature_idx = otfg->positioning_type >> 4;
1990 if (feature_idx)
1992 unsigned int tag = features[feature_idx - 1].FeatureTag;
1993 tag = PACK_OTF_TAG (tag);
1994 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1997 if (! otfg->glyph_id)
1998 continue;
1999 switch (otfg->positioning_type & 0xF)
2001 case 0:
2002 break;
2003 case 1: /* Single */
2004 case 2: /* Pair */
2006 int format = otfg->f.f1.format;
2008 if (format & OTF_XPlacement)
2009 adjustment[i].xoff
2010 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2011 if (format & OTF_XPlaDevice)
2012 adjustment[i].xoff
2013 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2014 if (format & OTF_YPlacement)
2015 adjustment[i].yoff
2016 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2017 if (format & OTF_YPlaDevice)
2018 adjustment[i].yoff
2019 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2020 if (format & OTF_XAdvance)
2021 adjustment[i].xadv
2022 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2023 if (format & OTF_XAdvDevice)
2024 adjustment[i].xadv
2025 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2026 if (format & OTF_YAdvance)
2027 adjustment[i].yadv
2028 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2029 if (format & OTF_YAdvDevice)
2030 adjustment[i].yadv
2031 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2032 adjustment[i].set = 1;
2034 break;
2035 case 3: /* Cursive */
2036 /* Not yet supported. */
2037 break;
2038 case 4: /* Mark-to-Base */
2039 case 5: /* Mark-to-Ligature */
2040 if (! base)
2041 break;
2042 prev = base;
2043 goto label_adjust_anchor;
2044 default: /* i.e. case 6 Mark-to-Mark */
2045 if (! mark)
2046 break;
2047 prev = mark;
2049 label_adjust_anchor:
2051 int base_x, base_y, mark_x, mark_y;
2052 int this_from, this_to;
2054 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2055 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2056 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2057 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2059 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2060 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2061 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2062 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2063 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2064 x_ppem, y_ppem, &mark_x, &mark_y);
2065 adjustment[i].xoff = (base_x - mark_x);
2066 adjustment[i].yoff = - (base_y - mark_y);
2067 adjustment[i].back = (g - prev);
2068 adjustment[i].xadv = 0;
2069 adjustment[i].advance_is_absolute = 1;
2070 adjustment[i].set = 1;
2071 this_from = g->from;
2072 this_to = g->to;
2073 for (j = 0; prev + j < g; j++)
2075 if (this_from > prev[j].from)
2076 this_from = prev[j].from;
2077 if (this_to < prev[j].to)
2078 this_to = prev[j].to;
2080 for (; prev <= g; prev++)
2082 prev->from = this_from;
2083 prev->to = this_to;
2087 if (otfg->GlyphClass == OTF_GlyphClass0)
2088 base = mark = g;
2089 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2090 mark = g;
2091 else
2092 base = g;
2095 else if (gpos_features)
2097 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2098 gpos_features) < 0)
2099 return to;
2100 features = otf->gpos->FeatureList.Feature;
2101 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2102 i++, otfg++)
2103 if (otfg->positioning_type & 0xF)
2105 int feature_idx = otfg->positioning_type >> 4;
2107 if (feature_idx)
2109 unsigned int tag = features[feature_idx - 1].FeatureTag;
2110 tag = PACK_OTF_TAG (tag);
2111 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2113 MFLTGlyph *g = in->glyphs + (from + j);
2114 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2119 return to;
2121 simple_copy:
2122 if (! out)
2123 return to;
2124 if (out->allocated < out->used + len)
2125 return -2;
2126 font->get_metrics (font, in, from, to);
2127 memcpy (out->glyphs + out->used, in->glyphs + from,
2128 sizeof (MFLTGlyph) * len);
2129 out->used += len;
2130 return to;
2133 static int
2134 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2135 MFLTGlyphString *in, int from, int to)
2137 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2140 #else /* not M17N_FLT_USE_NEW_FEATURE */
2142 static int
2143 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2144 int from, int to,
2145 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2147 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2148 FT_Face ft_face = flt_font_ft->ft_face;
2149 OTF *otf = flt_font_ft->otf;
2150 int len = to - from;
2151 int i, j, gidx;
2152 OTF_Glyph *otfg;
2153 char script[5], *langsys = NULL;
2154 char *gsub_features = NULL, *gpos_features = NULL;
2156 if (len == 0)
2157 return from;
2158 OTF_tag_name (spec->script, script);
2159 if (spec->langsys)
2161 langsys = alloca (5);
2162 OTF_tag_name (spec->langsys, langsys);
2164 for (i = 0; i < 2; i++)
2166 char *p;
2168 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2170 for (j = 0; spec->features[i][j]; j++);
2171 if (i == 0)
2172 p = gsub_features = alloca (6 * j);
2173 else
2174 p = gpos_features = alloca (6 * j);
2175 for (j = 0; spec->features[i][j]; j++)
2177 if (spec->features[i][j] == 0xFFFFFFFF)
2178 *p++ = '*', *p++ = ',';
2179 else
2181 OTF_tag_name (spec->features[i][j], p);
2182 p[4] = ',';
2183 p += 5;
2186 *--p = '\0';
2190 setup_otf_gstring (len);
2191 for (i = 0; i < len; i++)
2193 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2194 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2197 OTF_drive_gdef (otf, &otf_gstring);
2198 gidx = out->used;
2200 if (gsub_features)
2202 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2203 < 0)
2204 goto simple_copy;
2205 if (out->allocated < out->used + otf_gstring.used)
2206 return -2;
2207 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2209 MFLTGlyph *g;
2210 int min_from, max_to;
2211 int j;
2213 g = out->glyphs + out->used;
2214 *g = in->glyphs[from + otfg->f.index.from];
2215 if (g->code != otfg->glyph_id)
2217 g->c = 0;
2218 g->code = otfg->glyph_id;
2219 g->measured = 0;
2221 out->used++;
2222 min_from = g->from;
2223 max_to = g->to;
2224 if (otfg->f.index.from < otfg->f.index.to)
2226 /* OTFG substitutes multiple glyphs in IN. */
2227 for (j = from + otfg->f.index.from + 1;
2228 j <= from + otfg->f.index.to; j++)
2230 if (min_from > in->glyphs[j].from)
2231 min_from = in->glyphs[j].from;
2232 if (max_to < in->glyphs[j].to)
2233 max_to = in->glyphs[j].to;
2235 g->from = min_from;
2236 g->to = max_to;
2238 for (i++, otfg++; (i < otf_gstring.used
2239 && otfg->f.index.from == otfg[-1].f.index.from);
2240 i++, otfg++)
2242 g = out->glyphs + out->used;
2243 *g = in->glyphs[from + otfg->f.index.to];
2244 if (g->code != otfg->glyph_id)
2246 g->c = 0;
2247 g->code = otfg->glyph_id;
2248 g->measured = 0;
2250 out->used++;
2254 else
2256 if (out->allocated < out->used + len)
2257 return -2;
2258 for (i = 0; i < len; i++)
2259 out->glyphs[out->used++] = in->glyphs[from + i];
2262 if (gpos_features)
2264 MFLTGlyph *base = NULL, *mark = NULL, *g;
2265 int x_ppem, y_ppem, x_scale, y_scale;
2267 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2268 < 0)
2269 return to;
2271 x_ppem = ft_face->size->metrics.x_ppem;
2272 y_ppem = ft_face->size->metrics.y_ppem;
2273 x_scale = ft_face->size->metrics.x_scale;
2274 y_scale = ft_face->size->metrics.y_scale;
2276 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2277 i < otf_gstring.used; i++, otfg++, g++)
2279 MFLTGlyph *prev;
2281 if (! otfg->glyph_id)
2282 continue;
2283 switch (otfg->positioning_type)
2285 case 0:
2286 break;
2287 case 1: /* Single */
2288 case 2: /* Pair */
2290 int format = otfg->f.f1.format;
2292 if (format & OTF_XPlacement)
2293 adjustment[i].xoff
2294 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2295 if (format & OTF_XPlaDevice)
2296 adjustment[i].xoff
2297 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2298 if (format & OTF_YPlacement)
2299 adjustment[i].yoff
2300 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2301 if (format & OTF_YPlaDevice)
2302 adjustment[i].yoff
2303 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2304 if (format & OTF_XAdvance)
2305 adjustment[i].xadv
2306 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2307 if (format & OTF_XAdvDevice)
2308 adjustment[i].xadv
2309 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2310 if (format & OTF_YAdvance)
2311 adjustment[i].yadv
2312 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2313 if (format & OTF_YAdvDevice)
2314 adjustment[i].yadv
2315 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2316 adjustment[i].set = 1;
2318 break;
2319 case 3: /* Cursive */
2320 /* Not yet supported. */
2321 break;
2322 case 4: /* Mark-to-Base */
2323 case 5: /* Mark-to-Ligature */
2324 if (! base)
2325 break;
2326 prev = base;
2327 goto label_adjust_anchor;
2328 default: /* i.e. case 6 Mark-to-Mark */
2329 if (! mark)
2330 break;
2331 prev = mark;
2333 label_adjust_anchor:
2335 int base_x, base_y, mark_x, mark_y;
2336 int this_from, this_to;
2338 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2339 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2340 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2341 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2343 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2344 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2345 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2346 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2347 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2348 x_ppem, y_ppem, &mark_x, &mark_y);
2349 adjustment[i].xoff = (base_x - mark_x);
2350 adjustment[i].yoff = - (base_y - mark_y);
2351 adjustment[i].back = (g - prev);
2352 adjustment[i].xadv = 0;
2353 adjustment[i].advance_is_absolute = 1;
2354 adjustment[i].set = 1;
2355 this_from = g->from;
2356 this_to = g->to;
2357 for (j = 0; prev + j < g; j++)
2359 if (this_from > prev[j].from)
2360 this_from = prev[j].from;
2361 if (this_to < prev[j].to)
2362 this_to = prev[j].to;
2364 for (; prev <= g; prev++)
2366 prev->from = this_from;
2367 prev->to = this_to;
2371 if (otfg->GlyphClass == OTF_GlyphClass0)
2372 base = mark = g;
2373 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2374 mark = g;
2375 else
2376 base = g;
2379 return to;
2381 simple_copy:
2382 if (out->allocated < out->used + len)
2383 return -2;
2384 font->get_metrics (font, in, from, to);
2385 memcpy (out->glyphs + out->used, in->glyphs + from,
2386 sizeof (MFLTGlyph) * len);
2387 out->used += len;
2388 return to;
2391 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2393 static MFLTGlyphString gstring;
2395 static bool m17n_flt_initialized;
2397 static Lisp_Object
2398 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2399 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2401 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2402 ptrdiff_t i;
2403 struct MFLTFontFT flt_font_ft;
2404 MFLT *flt = NULL;
2405 bool with_variation_selector = 0;
2407 if (! m17n_flt_initialized)
2409 M17N_INIT ();
2410 #ifdef M17N_FLT_USE_NEW_FEATURE
2411 mflt_enable_new_feature = 1;
2412 mflt_try_otf = ftfont_try_otf;
2413 #endif /* M17N_FLT_USE_NEW_FEATURE */
2414 m17n_flt_initialized = 1;
2417 for (i = 0; i < len; i++)
2419 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2420 int c;
2422 if (NILP (g))
2423 break;
2424 c = LGLYPH_CHAR (g);
2425 if (CHAR_VARIATION_SELECTOR_P (c))
2426 with_variation_selector = 1;
2429 len = i;
2430 lint_assume (len <= STRING_BYTES_BOUND);
2432 if (with_variation_selector)
2434 setup_otf_gstring (len);
2435 for (i = 0; i < len; i++)
2437 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2439 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2440 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2441 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2443 OTF_drive_cmap (otf, &otf_gstring);
2444 for (i = 0; i < otf_gstring.used; i++)
2446 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2447 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2448 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2450 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2451 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2452 LGSTRING_SET_GLYPH (lgstring, i, g0);
2454 if (len > otf_gstring.used)
2456 len = otf_gstring.used;
2457 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2461 if (INT_MAX / 2 < len)
2462 memory_full (SIZE_MAX);
2464 if (gstring.allocated == 0)
2466 gstring.glyph_size = sizeof (MFLTGlyph);
2467 gstring.glyphs = xnmalloc (len * 2, sizeof *gstring.glyphs);
2468 gstring.allocated = len * 2;
2470 else if (gstring.allocated < len * 2)
2472 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2,
2473 sizeof *gstring.glyphs);
2474 gstring.allocated = len * 2;
2476 memset (gstring.glyphs, 0, len * sizeof *gstring.glyphs);
2477 for (i = 0; i < len; i++)
2479 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2481 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2482 if (with_variation_selector)
2484 gstring.glyphs[i].code = LGLYPH_CODE (g);
2485 gstring.glyphs[i].encoded = 1;
2489 gstring.used = len;
2490 gstring.r2l = 0;
2493 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2495 if (NILP (family))
2496 flt_font_ft.flt_font.family = Mnil;
2497 else
2498 flt_font_ft.flt_font.family
2499 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2501 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2502 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2503 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2504 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2505 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2506 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2507 flt_font_ft.flt_font.internal = NULL;
2508 flt_font_ft.font = font;
2509 flt_font_ft.ft_face = ft_face;
2510 flt_font_ft.otf = otf;
2511 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2512 if (len > 1
2513 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2514 /* A little bit ad hoc. Perhaps, shaper must get script and
2515 language information, and select a proper flt for them
2516 here. */
2517 flt = mflt_get (msymbol ("combining"));
2518 for (i = 0; i < 3; i++)
2520 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2521 if (result != -2)
2522 break;
2523 if (INT_MAX / 2 < gstring.allocated)
2524 memory_full (SIZE_MAX);
2525 gstring.glyphs = xnrealloc (gstring.glyphs,
2526 gstring.allocated, 2 * sizeof (MFLTGlyph));
2527 gstring.allocated *= 2;
2529 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2530 return Qnil;
2531 for (i = 0; i < gstring.used; i++)
2533 MFLTGlyph *g = gstring.glyphs + i;
2535 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2536 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2539 for (i = 0; i < gstring.used; i++)
2541 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2542 MFLTGlyph *g = gstring.glyphs + i;
2544 if (NILP (lglyph))
2546 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2547 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2549 LGLYPH_SET_FROM (lglyph, g->from);
2550 LGLYPH_SET_TO (lglyph, g->to);
2551 LGLYPH_SET_CHAR (lglyph, g->c);
2552 LGLYPH_SET_CODE (lglyph, g->code);
2553 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2554 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2555 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2556 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2557 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2558 if (g->adjusted)
2560 Lisp_Object vec;
2562 vec = Fmake_vector (make_number (3), Qnil);
2563 ASET (vec, 0, make_number (g->xoff >> 6));
2564 ASET (vec, 1, make_number (g->yoff >> 6));
2565 ASET (vec, 2, make_number (g->xadv >> 6));
2566 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2569 return make_number (i);
2572 Lisp_Object
2573 ftfont_shape (Lisp_Object lgstring)
2575 struct font *font;
2576 struct ftfont_info *ftfont_info;
2577 OTF *otf;
2579 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2580 ftfont_info = (struct ftfont_info *) font;
2581 otf = ftfont_get_otf (ftfont_info);
2582 if (! otf)
2583 return make_number (0);
2584 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2585 &ftfont_info->matrix);
2588 #endif /* HAVE_M17N_FLT */
2590 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2592 static int
2593 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2595 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2596 OTF *otf = ftfont_get_otf (ftfont_info);
2598 if (! otf)
2599 return 0;
2600 return OTF_get_variation_glyphs (otf, c, variations);
2603 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2604 #endif /* HAVE_LIBOTF */
2606 Lisp_Object
2607 ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
2609 FcChar8 *str;
2611 #ifdef FC_FONTFORMAT
2612 if (pattern)
2614 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2615 return Qnil;
2616 if (strcmp ((char *) str, "TrueType") == 0)
2617 return intern ("truetype");
2618 if (strcmp ((char *) str, "Type 1") == 0)
2619 return intern ("type1");
2620 if (strcmp ((char *) str, "PCF") == 0)
2621 return intern ("pcf");
2622 if (strcmp ((char *) str, "BDF") == 0)
2623 return intern ("bdf");
2625 #endif /* FC_FONTFORMAT */
2626 if (STRINGP (filename))
2628 int len = SBYTES (filename);
2630 if (len >= 4)
2632 str = (FcChar8 *) (SDATA (filename) + len - 4);
2633 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2634 return intern ("truetype");
2635 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2636 return intern ("type1");
2637 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2638 return intern ("pcf");
2639 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2640 return intern ("bdf");
2643 return intern ("unknown");
2646 static const char *const ftfont_booleans [] = {
2647 ":antialias",
2648 ":hinting",
2649 ":verticallayout",
2650 ":autohint",
2651 ":globaladvance",
2652 ":outline",
2653 ":scalable",
2654 ":minspace",
2655 ":embolden",
2656 NULL,
2659 static const char *const ftfont_non_booleans [] = {
2660 ":family",
2661 ":familylang",
2662 ":style",
2663 ":stylelang",
2664 ":fullname",
2665 ":fullnamelang",
2666 ":slant",
2667 ":weight",
2668 ":size",
2669 ":width",
2670 ":aspect",
2671 ":pixelsize",
2672 ":spacing",
2673 ":foundry",
2674 ":hintstyle",
2675 ":file",
2676 ":index",
2677 ":ftface",
2678 ":rasterizer",
2679 ":scale",
2680 ":dpi",
2681 ":rgba",
2682 ":lcdfilter",
2683 ":charset",
2684 ":lang",
2685 ":fontversion",
2686 ":capability",
2687 NULL,
2690 static void
2691 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2693 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2697 void
2698 syms_of_ftfont (void)
2700 DEFSYM (Qfreetype, "freetype");
2701 DEFSYM (Qmonospace, "monospace");
2702 DEFSYM (Qsans_serif, "sans-serif");
2703 DEFSYM (Qserif, "serif");
2704 DEFSYM (Qmono, "mono");
2705 DEFSYM (Qsans, "sans");
2706 DEFSYM (Qsans__serif, "sans serif");
2708 staticpro (&freetype_font_cache);
2709 freetype_font_cache = Fcons (Qt, Qnil);
2711 staticpro (&ftfont_generic_family_list);
2712 ftfont_generic_family_list
2713 = Fcons (Fcons (Qmonospace, Qt),
2714 Fcons (Fcons (Qsans_serif, Qt),
2715 Fcons (Fcons (Qsans, Qt), Qnil)));
2717 staticpro (&ft_face_cache);
2718 ft_face_cache = Qnil;
2720 ftfont_driver.type = Qfreetype;
2721 register_font_driver (&ftfont_driver, NULL);