* gtkutil.h: Tiny cleanups.
[emacs.git] / src / ftfont.c
blob131a27f76e014a403ccda3f2615d975471268e2a
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 <setjmp.h>
26 #include <fontconfig/fontconfig.h>
27 #include <fontconfig/fcfreetype.h>
29 #include "lisp.h"
30 #include "dispextern.h"
31 #include "frame.h"
32 #include "blockinput.h"
33 #include "character.h"
34 #include "charset.h"
35 #include "coding.h"
36 #include "composite.h"
37 #include "fontset.h"
38 #include "font.h"
39 #include "ftfont.h"
41 /* Symbolic type of this font-driver. */
42 static Lisp_Object Qfreetype;
44 /* Fontconfig's generic families and their aliases. */
45 static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
47 /* Flag to tell if FcInit is already called or not. */
48 static int fc_initialized;
50 /* Handle to a FreeType library instance. */
51 static FT_Library ft_library;
53 /* Cache for FreeType fonts. */
54 static Lisp_Object freetype_font_cache;
56 /* Cache for FT_Face and FcCharSet. */
57 static Lisp_Object ft_face_cache;
59 /* The actual structure for FreeType font that can be casted to struct
60 font. */
62 struct ftfont_info
64 struct font font;
65 #ifdef HAVE_LIBOTF
66 /* The following four members must be here in this order to be
67 compatible with struct xftfont_info (in xftfont.c). */
68 int maybe_otf; /* Flag to tell if this may be OTF or not. */
69 OTF *otf;
70 #endif /* HAVE_LIBOTF */
71 FT_Size ft_size;
72 int index;
73 FT_Matrix matrix;
76 enum ftfont_cache_for
78 FTFONT_CACHE_FOR_FACE,
79 FTFONT_CACHE_FOR_CHARSET,
80 FTFONT_CACHE_FOR_ENTITY
83 static Lisp_Object ftfont_pattern_entity (FcPattern *, Lisp_Object);
85 static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
86 FcPattern *);
87 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
88 enum ftfont_cache_for);
90 static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
92 Lisp_Object ftfont_font_format (FcPattern *, Lisp_Object);
94 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
96 static struct
98 /* registry name */
99 const char *name;
100 /* characters to distinguish the charset from the others */
101 int uniquifier[6];
102 /* additional constraint by language */
103 const char *lang;
104 /* set on demand */
105 FcCharSet *fc_charset;
106 } fc_charset_table[] =
107 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
108 { "iso8859-2", { 0x00A0, 0x010E }},
109 { "iso8859-3", { 0x00A0, 0x0108 }},
110 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
111 { "iso8859-5", { 0x00A0, 0x0401 }},
112 { "iso8859-6", { 0x00A0, 0x060C }},
113 { "iso8859-7", { 0x00A0, 0x0384 }},
114 { "iso8859-8", { 0x00A0, 0x05D0 }},
115 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
116 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
117 { "iso8859-11", { 0x00A0, 0x0E01 }},
118 { "iso8859-13", { 0x00A0, 0x201C }},
119 { "iso8859-14", { 0x00A0, 0x0174 }},
120 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
121 { "iso8859-16", { 0x00A0, 0x0218}},
122 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
123 { "big5-0", { 0xF6B1 }, "zh-tw" },
124 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
125 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
126 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
127 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
128 { "cns11643.1992-3", { 0x201A9 }},
129 { "cns11643.1992-4", { 0x20057 }},
130 { "cns11643.1992-5", { 0x20000 }},
131 { "cns11643.1992-6", { 0x20003 }},
132 { "cns11643.1992-7", { 0x20055 }},
133 { "gbk-0", { 0x4E06 }, "zh-cn"},
134 { "jisx0212.1990-0", { 0x4E44 }},
135 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
136 { "jisx0213.2000-2", { 0xFA49 }},
137 { "jisx0213.2004-1", { 0x20B9F }},
138 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
139 { "tis620.2529-1", { 0x0E01 }, "th"},
140 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
141 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
142 { "mulelao-1", { 0x0E81 }, "lo"},
143 { "unicode-sip", { 0x20000 }},
144 { NULL }
147 /* Dirty hack for handing ADSTYLE property.
149 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
150 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
151 "Oblique", "Italic", or any non-normal SWIDTH property names
152 (e.g. SemiCondensed) are appended. In addition, if there's no
153 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
154 "Regular" is used for FC_STYLE (see the function
155 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
157 Unfortunately this behavior is not documented, so the following
158 code may fail if FreeType changes the behavior in the future. */
160 static Lisp_Object
161 get_adstyle_property (FcPattern *p)
163 FcChar8 *fcstr;
164 char *str, *end;
165 Lisp_Object adstyle;
167 #ifdef FC_FONTFORMAT
168 if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
169 && xstrcasecmp ((char *) fcstr, "bdf") != 0
170 && xstrcasecmp ((char *) fcstr, "pcf") != 0)
171 /* Not a BDF nor PCF font. */
172 return Qnil;
173 #endif
174 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
175 return Qnil;
176 str = (char *) fcstr;
177 for (end = str; *end && *end != ' '; end++);
178 if (*end)
180 char *newstr = alloca (end - str + 1);
181 memcpy (newstr, str, end - str);
182 newstr[end - str] = '\0';
183 end = newstr + (end - str);
184 str = newstr;
186 if (xstrcasecmp (str, "Regular") == 0
187 || xstrcasecmp (str, "Bold") == 0
188 || xstrcasecmp (str, "Oblique") == 0
189 || xstrcasecmp (str, "Italic") == 0)
190 return Qnil;
191 adstyle = font_intern_prop (str, end - str, 1);
192 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
193 return Qnil;
194 return adstyle;
197 static Lisp_Object
198 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
200 Lisp_Object key, cache, entity;
201 FcChar8 *str;
202 char *file;
203 int idx;
204 int numeric;
205 double dbl;
206 FcBool b;
208 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
209 return Qnil;
210 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
211 return Qnil;
213 file = (char *) str;
214 key = Fcons (make_unibyte_string (file, strlen (file)), make_number (idx));
215 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
216 entity = XCAR (cache);
217 if (! NILP (entity))
219 Lisp_Object val = font_make_entity ();
220 int i;
222 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
223 ASET (val, i, AREF (entity, i));
225 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
226 font_put_extra (val, QCfont_entity, key);
228 return val;
230 entity = font_make_entity ();
231 XSETCAR (cache, entity);
233 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
234 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
236 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
238 char *s = (char *) str;
239 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
241 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
243 char *s = (char *) str;
244 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
246 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
248 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
249 numeric = FC_WEIGHT_MEDIUM;
250 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
252 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
254 numeric += 100;
255 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
257 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
259 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
261 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
263 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
265 else
266 ASET (entity, FONT_SIZE_INDEX, make_number (0));
267 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
268 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
269 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
271 int dpi = dbl;
272 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
274 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
275 && b == FcTrue)
277 ASET (entity, FONT_SIZE_INDEX, make_number (0));
278 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
280 else
282 /* As this font is not scalable, perhaps this is a BDF or PCF
283 font. */
284 FT_Face ft_face;
286 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
287 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
288 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
290 BDF_PropertyRec rec;
292 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
293 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
294 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
295 FT_Done_Face (ft_face);
299 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
300 font_put_extra (entity, QCfont_entity, key);
301 return entity;
305 static Lisp_Object ftfont_generic_family_list;
307 static Lisp_Object
308 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
310 Lisp_Object slot;
311 FcPattern *match;
312 FcResult result;
313 FcLangSet *langset;
315 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
316 if (EQ (family, Qmono))
317 family = Qmonospace;
318 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
319 family = Qsans_serif;
320 slot = assq_no_quit (family, ftfont_generic_family_list);
321 if (! CONSP (slot))
322 return Qnil;
323 if (! EQ (XCDR (slot), Qt))
324 return XCDR (slot);
325 pattern = FcPatternDuplicate (pattern);
326 if (! pattern)
327 goto err;
328 FcPatternDel (pattern, FC_FOUNDRY);
329 FcPatternDel (pattern, FC_FAMILY);
330 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
331 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
333 /* This is to avoid the effect of locale. */
334 static const FcChar8 lang[] = "en";
335 langset = FcLangSetCreate ();
336 FcLangSetAdd (langset, lang);
337 FcPatternAddLangSet (pattern, FC_LANG, langset);
338 FcLangSetDestroy (langset);
340 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
341 FcDefaultSubstitute (pattern);
342 match = FcFontMatch (NULL, pattern, &result);
343 if (match)
345 FcChar8 *fam;
347 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
348 family = intern ((char *) fam);
350 else
351 family = Qnil;
352 XSETCDR (slot, family);
353 if (match) FcPatternDestroy (match);
354 err:
355 if (pattern) FcPatternDestroy (pattern);
356 return family;
359 struct ftfont_cache_data
361 FT_Face ft_face;
362 FcCharSet *fc_charset;
365 static Lisp_Object
366 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
368 Lisp_Object cache, val, entity;
369 struct ftfont_cache_data *cache_data;
371 if (FONT_ENTITY_P (key))
373 entity = key;
374 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
375 eassert (CONSP (val));
376 key = XCDR (val);
378 else
379 entity = Qnil;
381 if (NILP (ft_face_cache))
382 cache = Qnil;
383 else
384 cache = Fgethash (key, ft_face_cache, Qnil);
385 if (NILP (cache))
387 if (NILP (ft_face_cache))
389 Lisp_Object args[2];
391 args[0] = QCtest;
392 args[1] = Qequal;
393 ft_face_cache = Fmake_hash_table (2, args);
395 cache_data = xmalloc (sizeof *cache_data);
396 cache_data->ft_face = NULL;
397 cache_data->fc_charset = NULL;
398 val = make_save_value (NULL, 0);
399 XSAVE_VALUE (val)->integer = 0;
400 XSAVE_VALUE (val)->pointer = cache_data;
401 cache = Fcons (Qnil, val);
402 Fputhash (key, cache, ft_face_cache);
404 else
406 val = XCDR (cache);
407 cache_data = XSAVE_VALUE (val)->pointer;
410 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
411 return cache;
413 if (cache_for == FTFONT_CACHE_FOR_FACE
414 ? ! cache_data->ft_face : ! cache_data->fc_charset)
416 char *filename = SSDATA (XCAR (key));
417 int idx = XINT (XCDR (key));
419 if (cache_for == FTFONT_CACHE_FOR_FACE)
421 if (! ft_library
422 && FT_Init_FreeType (&ft_library) != 0)
423 return Qnil;
424 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
425 != 0)
426 return Qnil;
428 else
430 FcPattern *pat = NULL;
431 FcFontSet *fontset = NULL;
432 FcObjectSet *objset = NULL;
433 FcCharSet *charset = NULL;
435 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
436 FC_INDEX, FcTypeInteger, idx, NULL);
437 if (! pat)
438 goto finish;
439 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
440 if (! objset)
441 goto finish;
442 fontset = FcFontList (NULL, pat, objset);
443 if (! fontset)
444 goto finish;
445 if (fontset && fontset->nfont > 0
446 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
447 &charset)
448 == FcResultMatch))
449 cache_data->fc_charset = FcCharSetCopy (charset);
450 else
451 cache_data->fc_charset = FcCharSetCreate ();
453 finish:
454 if (fontset)
455 FcFontSetDestroy (fontset);
456 if (objset)
457 FcObjectSetDestroy (objset);
458 if (pat)
459 FcPatternDestroy (pat);
462 return cache;
465 FcCharSet *
466 ftfont_get_fc_charset (Lisp_Object entity)
468 Lisp_Object val, cache;
469 struct ftfont_cache_data *cache_data;
471 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
472 val = XCDR (cache);
473 cache_data = XSAVE_VALUE (val)->pointer;
474 return cache_data->fc_charset;
477 #ifdef HAVE_LIBOTF
478 static OTF *
479 ftfont_get_otf (struct ftfont_info *ftfont_info)
481 OTF *otf;
483 if (ftfont_info->otf)
484 return ftfont_info->otf;
485 if (! ftfont_info->maybe_otf)
486 return NULL;
487 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
488 if (! otf || OTF_get_table (otf, "head") < 0)
490 if (otf)
491 OTF_close (otf);
492 ftfont_info->maybe_otf = 0;
493 return NULL;
495 ftfont_info->otf = otf;
496 return otf;
498 #endif /* HAVE_LIBOTF */
500 static Lisp_Object ftfont_get_cache (FRAME_PTR);
501 static Lisp_Object ftfont_list (Lisp_Object, Lisp_Object);
502 static Lisp_Object ftfont_match (Lisp_Object, Lisp_Object);
503 static Lisp_Object ftfont_list_family (Lisp_Object);
504 static Lisp_Object ftfont_open (FRAME_PTR, Lisp_Object, int);
505 static void ftfont_close (FRAME_PTR, struct font *);
506 static int ftfont_has_char (Lisp_Object, int);
507 static unsigned ftfont_encode_char (struct font *, int);
508 static int ftfont_text_extents (struct font *, unsigned *, int,
509 struct font_metrics *);
510 static int ftfont_get_bitmap (struct font *, unsigned,
511 struct font_bitmap *, int);
512 static int ftfont_anchor_point (struct font *, unsigned, int,
513 int *, int *);
514 #ifdef HAVE_LIBOTF
515 static Lisp_Object ftfont_otf_capability (struct font *);
516 # ifdef HAVE_M17N_FLT
517 static Lisp_Object ftfont_shape (Lisp_Object);
518 # endif
519 #endif
521 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
522 static int ftfont_variation_glyphs (struct font *, int c,
523 unsigned variations[256]);
524 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
526 struct font_driver ftfont_driver =
528 LISP_INITIALLY_ZERO, /* Qfreetype */
529 0, /* case insensitive */
530 ftfont_get_cache,
531 ftfont_list,
532 ftfont_match,
533 ftfont_list_family,
534 NULL, /* free_entity */
535 ftfont_open,
536 ftfont_close,
537 /* We can't draw a text without device dependent functions. */
538 NULL, /* prepare_face */
539 NULL, /* done_face */
540 ftfont_has_char,
541 ftfont_encode_char,
542 ftfont_text_extents,
543 /* We can't draw a text without device dependent functions. */
544 NULL, /* draw */
545 ftfont_get_bitmap,
546 NULL, /* get_bitmap */
547 NULL, /* free_bitmap */
548 NULL, /* get_outline */
549 ftfont_anchor_point,
550 #ifdef HAVE_LIBOTF
551 ftfont_otf_capability,
552 #else /* not HAVE_LIBOTF */
553 NULL,
554 #endif /* not HAVE_LIBOTF */
555 NULL, /* otf_drive */
556 NULL, /* start_for_frame */
557 NULL, /* end_for_frame */
558 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
559 ftfont_shape,
560 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
561 NULL,
562 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
563 NULL, /* check */
565 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
566 ftfont_variation_glyphs,
567 #else
568 NULL,
569 #endif
571 ftfont_filter_properties, /* filter_properties */
574 static Lisp_Object
575 ftfont_get_cache (FRAME_PTR f)
577 return freetype_font_cache;
580 static int
581 ftfont_get_charset (Lisp_Object registry)
583 char *str = SSDATA (SYMBOL_NAME (registry));
584 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
585 Lisp_Object regexp;
586 int i, j;
588 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
590 if (str[i] == '.')
591 re[j++] = '\\';
592 else if (str[i] == '*')
593 re[j++] = '.';
594 re[j] = str[i];
595 if (re[j] == '?')
596 re[j] = '.';
598 re[j] = '\0';
599 regexp = make_unibyte_string (re, j);
600 for (i = 0; fc_charset_table[i].name; i++)
601 if (fast_c_string_match_ignore_case
602 (regexp, fc_charset_table[i].name,
603 strlen (fc_charset_table[i].name)) >= 0)
604 break;
605 if (! fc_charset_table[i].name)
606 return -1;
607 if (! fc_charset_table[i].fc_charset)
609 FcCharSet *charset = FcCharSetCreate ();
610 int *uniquifier = fc_charset_table[i].uniquifier;
612 if (! charset)
613 return -1;
614 for (j = 0; uniquifier[j]; j++)
615 if (! FcCharSetAddChar (charset, uniquifier[j]))
617 FcCharSetDestroy (charset);
618 return -1;
620 fc_charset_table[i].fc_charset = charset;
622 return i;
625 struct OpenTypeSpec
627 Lisp_Object script;
628 unsigned int script_tag, langsys_tag;
629 int nfeatures[2];
630 unsigned int *features[2];
633 #define OTF_SYM_TAG(SYM, TAG) \
634 do { \
635 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
636 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
637 } while (0)
639 #define OTF_TAG_STR(TAG, P) \
640 do { \
641 (P)[0] = (char) (TAG >> 24); \
642 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
643 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
644 (P)[3] = (char) (TAG & 0xFF); \
645 (P)[4] = '\0'; \
646 } while (0)
648 #ifdef HAVE_LIBOTF
649 #define OTF_TAG_SYM(SYM, TAG) \
650 do { \
651 char str[5]; \
653 OTF_TAG_STR (TAG, str); \
654 (SYM) = font_intern_prop (str, 4, 1); \
655 } while (0)
656 #endif
659 static struct OpenTypeSpec *
660 ftfont_get_open_type_spec (Lisp_Object otf_spec)
662 struct OpenTypeSpec *spec = malloc (sizeof *spec);
663 Lisp_Object val;
664 int i, j, negative;
666 if (! spec)
667 return NULL;
668 spec->script = XCAR (otf_spec);
669 if (! NILP (spec->script))
671 OTF_SYM_TAG (spec->script, spec->script_tag);
672 val = assq_no_quit (spec->script, Votf_script_alist);
673 if (CONSP (val) && SYMBOLP (XCDR (val)))
674 spec->script = XCDR (val);
675 else
676 spec->script = Qnil;
678 else
679 spec->script_tag = 0x44464C54; /* "DFLT" */
680 otf_spec = XCDR (otf_spec);
681 spec->langsys_tag = 0;
682 if (! NILP (otf_spec))
684 val = XCAR (otf_spec);
685 if (! NILP (val))
686 OTF_SYM_TAG (val, spec->langsys_tag);
687 otf_spec = XCDR (otf_spec);
689 spec->nfeatures[0] = spec->nfeatures[1] = 0;
690 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
692 Lisp_Object len;
694 val = XCAR (otf_spec);
695 if (NILP (val))
696 continue;
697 len = Flength (val);
698 spec->features[i] =
699 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
701 : malloc (XINT (len) * sizeof *spec->features[i]));
702 if (! spec->features[i])
704 if (i > 0 && spec->features[0])
705 free (spec->features[0]);
706 free (spec);
707 return NULL;
709 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
711 if (NILP (XCAR (val)))
712 negative = 1;
713 else
715 unsigned int tag;
717 OTF_SYM_TAG (XCAR (val), tag);
718 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
721 spec->nfeatures[i] = j;
723 return spec;
726 static FcPattern *
727 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
729 Lisp_Object tmp, extra;
730 FcPattern *pattern = NULL;
731 FcCharSet *charset = NULL;
732 FcLangSet *langset = NULL;
733 int n;
734 int dpi = -1;
735 int scalable = -1;
736 Lisp_Object script = Qnil;
737 Lisp_Object registry;
738 int fc_charset_idx;
740 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
741 && n < 100)
742 /* Fontconfig doesn't support reverse-italic/oblique. */
743 return NULL;
745 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
746 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
747 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
748 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
749 scalable = 1;
751 registry = AREF (spec, FONT_REGISTRY_INDEX);
752 if (NILP (registry)
753 || EQ (registry, Qascii_0)
754 || EQ (registry, Qiso10646_1)
755 || EQ (registry, Qunicode_bmp))
756 fc_charset_idx = -1;
757 else
759 FcChar8 *lang;
761 fc_charset_idx = ftfont_get_charset (registry);
762 if (fc_charset_idx < 0)
763 return NULL;
764 charset = fc_charset_table[fc_charset_idx].fc_charset;
765 *langname = fc_charset_table[fc_charset_idx].lang;
766 lang = (FcChar8 *) *langname;
767 if (lang)
769 langset = FcLangSetCreate ();
770 if (! langset)
771 goto err;
772 FcLangSetAdd (langset, lang);
776 otlayout[0] = '\0';
777 for (extra = AREF (spec, FONT_EXTRA_INDEX);
778 CONSP (extra); extra = XCDR (extra))
780 Lisp_Object key, val;
782 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
783 if (EQ (key, QCdpi))
785 if (INTEGERP (val))
786 dpi = XINT (val);
788 else if (EQ (key, QClang))
790 if (! langset)
791 langset = FcLangSetCreate ();
792 if (! langset)
793 goto err;
794 if (SYMBOLP (val))
796 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
797 goto err;
799 else
800 for (; CONSP (val); val = XCDR (val))
801 if (SYMBOLP (XCAR (val))
802 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
803 goto err;
805 else if (EQ (key, QCotf))
807 if (CONSP (val))
809 *otspec = ftfont_get_open_type_spec (val);
810 if (! *otspec)
811 return NULL;
812 strcat (otlayout, "otlayout:");
813 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
814 script = (*otspec)->script;
817 else if (EQ (key, QCscript))
818 script = val;
819 else if (EQ (key, QCscalable))
820 scalable = ! NILP (val);
823 if (! NILP (script) && ! charset)
825 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
827 if (CONSP (chars) && CONSP (CDR (chars)))
829 charset = FcCharSetCreate ();
830 if (! charset)
831 goto err;
832 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
833 if (CHARACTERP (XCAR (chars))
834 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
835 goto err;
839 pattern = FcPatternCreate ();
840 if (! pattern)
841 goto err;
842 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
843 if (! NILP (tmp)
844 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
845 goto err;
846 tmp = AREF (spec, FONT_FAMILY_INDEX);
847 if (! NILP (tmp)
848 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
849 goto err;
850 if (charset
851 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
852 goto err;
853 if (langset
854 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
855 goto err;
856 if (dpi >= 0
857 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
858 goto err;
859 if (scalable >= 0
860 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
861 goto err;
863 goto finish;
865 err:
866 /* We come here because of unexpected error in fontconfig API call
867 (usually insufficient memory). */
868 if (pattern)
870 FcPatternDestroy (pattern);
871 pattern = NULL;
873 if (*otspec)
875 if ((*otspec)->nfeatures[0] > 0)
876 free ((*otspec)->features[0]);
877 if ((*otspec)->nfeatures[1] > 0)
878 free ((*otspec)->features[1]);
879 free (*otspec);
880 *otspec = NULL;
883 finish:
884 if (langset) FcLangSetDestroy (langset);
885 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
886 return pattern;
889 static Lisp_Object
890 ftfont_list (Lisp_Object frame, Lisp_Object spec)
892 Lisp_Object val = Qnil, family, adstyle;
893 int i;
894 FcPattern *pattern;
895 FcFontSet *fontset = NULL;
896 FcObjectSet *objset = NULL;
897 FcCharSet *charset;
898 Lisp_Object chars = Qnil;
899 char otlayout[15]; /* For "otlayout:XXXX" */
900 struct OpenTypeSpec *otspec = NULL;
901 int spacing = -1;
902 const char *langname = NULL;
904 if (! fc_initialized)
906 FcInit ();
907 fc_initialized = 1;
910 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
911 if (! pattern)
912 return Qnil;
913 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
915 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
916 if (! NILP (val))
918 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
919 if (CONSP (val) && VECTORP (XCDR (val)))
920 chars = XCDR (val);
922 val = Qnil;
924 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
925 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
926 family = AREF (spec, FONT_FAMILY_INDEX);
927 if (! NILP (family))
929 Lisp_Object resolved;
931 resolved = ftfont_resolve_generic_family (family, pattern);
932 if (! NILP (resolved))
934 FcPatternDel (pattern, FC_FAMILY);
935 if (! FcPatternAddString (pattern, FC_FAMILY,
936 SYMBOL_FcChar8 (resolved)))
937 goto err;
940 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
941 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
942 adstyle = Qnil;
943 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
944 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
945 FC_STYLE, FC_FILE, FC_INDEX,
946 #ifdef FC_CAPABILITY
947 FC_CAPABILITY,
948 #endif /* FC_CAPABILITY */
949 #ifdef FC_FONTFORMAT
950 FC_FONTFORMAT,
951 #endif
952 NULL);
953 if (! objset)
954 goto err;
955 if (! NILP (chars))
956 FcObjectSetAdd (objset, FC_CHARSET);
958 fontset = FcFontList (NULL, pattern, objset);
959 if (! fontset || fontset->nfont == 0)
960 goto finish;
961 #if 0
962 /* Need fix because this finds any fonts. */
963 if (fontset->nfont == 0 && ! NILP (family))
965 /* Try matching with configuration. For instance, the
966 configuration may specify "Nimbus Mono L" as an alias of
967 "Courier". */
968 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
969 SYMBOL_FcChar8 (family), NULL);
970 FcChar8 *fam;
972 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
974 for (i = 0;
975 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
976 i++)
978 FcPatternDel (pattern, FC_FAMILY);
979 FcPatternAddString (pattern, FC_FAMILY, fam);
980 FcFontSetDestroy (fontset);
981 fontset = FcFontList (NULL, pattern, objset);
982 if (fontset && fontset->nfont > 0)
983 break;
987 #endif
988 for (i = 0; i < fontset->nfont; i++)
990 Lisp_Object entity;
992 if (spacing >= 0)
994 int this;
996 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
997 == FcResultMatch)
998 && spacing != this)
999 continue;
1002 #ifdef FC_CAPABILITY
1003 if (otlayout[0])
1005 FcChar8 *this;
1007 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
1008 != FcResultMatch
1009 || ! strstr ((char *) this, otlayout))
1010 continue;
1012 #endif /* FC_CAPABILITY */
1013 #ifdef HAVE_LIBOTF
1014 if (otspec)
1016 FcChar8 *file;
1017 OTF *otf;
1019 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1020 != FcResultMatch)
1021 continue;
1022 otf = OTF_open ((char *) file);
1023 if (! otf)
1024 continue;
1025 if (OTF_check_features (otf, 1,
1026 otspec->script_tag, otspec->langsys_tag,
1027 otspec->features[0],
1028 otspec->nfeatures[0]) != 1
1029 || OTF_check_features (otf, 0,
1030 otspec->script_tag, otspec->langsys_tag,
1031 otspec->features[1],
1032 otspec->nfeatures[1]) != 1)
1033 continue;
1035 #endif /* HAVE_LIBOTF */
1036 if (VECTORP (chars))
1038 ptrdiff_t j;
1040 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1041 != FcResultMatch)
1042 continue;
1043 for (j = 0; j < ASIZE (chars); j++)
1044 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1045 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1046 break;
1047 if (j == ASIZE (chars))
1048 continue;
1050 if (! NILP (adstyle) || langname)
1052 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1054 if (! NILP (adstyle)
1055 && (NILP (this_adstyle)
1056 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1057 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1058 continue;
1059 if (langname
1060 && ! NILP (this_adstyle)
1061 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1062 continue;
1064 entity = ftfont_pattern_entity (fontset->fonts[i],
1065 AREF (spec, FONT_EXTRA_INDEX));
1066 if (! NILP (entity))
1067 val = Fcons (entity, val);
1069 val = Fnreverse (val);
1070 goto finish;
1072 err:
1073 /* We come here because of unexpected error in fontconfig API call
1074 (usually insufficient memory). */
1075 val = Qnil;
1077 finish:
1078 FONT_ADD_LOG ("ftfont-list", spec, val);
1079 if (objset) FcObjectSetDestroy (objset);
1080 if (fontset) FcFontSetDestroy (fontset);
1081 if (pattern) FcPatternDestroy (pattern);
1082 return val;
1085 static Lisp_Object
1086 ftfont_match (Lisp_Object frame, Lisp_Object spec)
1088 Lisp_Object entity = Qnil;
1089 FcPattern *pattern, *match = NULL;
1090 FcResult result;
1091 char otlayout[15]; /* For "otlayout:XXXX" */
1092 struct OpenTypeSpec *otspec = NULL;
1093 const char *langname = NULL;
1095 if (! fc_initialized)
1097 FcInit ();
1098 fc_initialized = 1;
1101 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1102 if (! pattern)
1103 return Qnil;
1105 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1107 FcValue value;
1109 value.type = FcTypeDouble;
1110 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1111 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1113 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1115 FcDefaultSubstitute (pattern);
1116 match = FcFontMatch (NULL, pattern, &result);
1117 if (match)
1119 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1120 FcPatternDestroy (match);
1121 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1122 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1123 ftfont_generic_family_list))
1124 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1125 AREF (entity, FONT_FAMILY_INDEX))))
1126 entity = Qnil;
1129 FcPatternDestroy (pattern);
1131 FONT_ADD_LOG ("ftfont-match", spec, entity);
1132 return entity;
1135 static Lisp_Object
1136 ftfont_list_family (Lisp_Object frame)
1138 Lisp_Object list = Qnil;
1139 FcPattern *pattern = NULL;
1140 FcFontSet *fontset = NULL;
1141 FcObjectSet *objset = NULL;
1142 int i;
1144 if (! fc_initialized)
1146 FcInit ();
1147 fc_initialized = 1;
1150 pattern = FcPatternCreate ();
1151 if (! pattern)
1152 goto finish;
1153 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1154 if (! objset)
1155 goto finish;
1156 fontset = FcFontList (NULL, pattern, objset);
1157 if (! fontset)
1158 goto finish;
1160 for (i = 0; i < fontset->nfont; i++)
1162 FcPattern *pat = fontset->fonts[i];
1163 FcChar8 *str;
1165 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1166 list = Fcons (intern ((char *) str), list);
1169 finish:
1170 if (objset) FcObjectSetDestroy (objset);
1171 if (fontset) FcFontSetDestroy (fontset);
1172 if (pattern) FcPatternDestroy (pattern);
1174 return list;
1178 static Lisp_Object
1179 ftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
1181 struct ftfont_info *ftfont_info;
1182 struct font *font;
1183 struct ftfont_cache_data *cache_data;
1184 FT_Face ft_face;
1185 FT_Size ft_size;
1186 FT_UInt size;
1187 Lisp_Object val, filename, idx, cache, font_object;
1188 int scalable;
1189 int spacing;
1190 char name[256];
1191 int i, len;
1192 int upEM;
1194 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1195 if (! CONSP (val))
1196 return Qnil;
1197 val = XCDR (val);
1198 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1199 if (NILP (cache))
1200 return Qnil;
1201 filename = XCAR (val);
1202 idx = XCDR (val);
1203 val = XCDR (cache);
1204 cache_data = XSAVE_VALUE (XCDR (cache))->pointer;
1205 ft_face = cache_data->ft_face;
1206 if (XSAVE_VALUE (val)->integer > 0)
1208 /* FT_Face in this cache is already used by the different size. */
1209 if (FT_New_Size (ft_face, &ft_size) != 0)
1210 return Qnil;
1211 if (FT_Activate_Size (ft_size) != 0)
1213 FT_Done_Size (ft_size);
1214 return Qnil;
1217 XSAVE_VALUE (val)->integer++;
1218 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1219 if (size == 0)
1220 size = pixel_size;
1221 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1223 if (XSAVE_VALUE (val)->integer == 0)
1224 FT_Done_Face (ft_face);
1225 return Qnil;
1228 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
1229 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
1230 len = font_unparse_xlfd (entity, size, name, 256);
1231 if (len > 0)
1232 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
1233 len = font_unparse_fcname (entity, size, name, 256);
1234 if (len > 0)
1235 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
1236 else
1237 ASET (font_object, FONT_FULLNAME_INDEX,
1238 AREF (font_object, FONT_NAME_INDEX));
1239 ASET (font_object, FONT_FILE_INDEX, filename);
1240 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
1241 font = XFONT_OBJECT (font_object);
1242 ftfont_info = (struct ftfont_info *) font;
1243 ftfont_info->ft_size = ft_face->size;
1244 ftfont_info->index = XINT (idx);
1245 #ifdef HAVE_LIBOTF
1246 ftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
1247 ftfont_info->otf = NULL;
1248 #endif /* HAVE_LIBOTF */
1249 /* This means that there's no need of transformation. */
1250 ftfont_info->matrix.xx = 0;
1251 font->pixel_size = size;
1252 font->driver = &ftfont_driver;
1253 font->encoding_charset = font->repertory_charset = -1;
1255 upEM = ft_face->units_per_EM;
1256 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1257 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1258 if (scalable)
1260 font->ascent = ft_face->ascender * size / upEM;
1261 font->descent = - ft_face->descender * size / upEM;
1262 font->height = ft_face->height * size / upEM;
1264 else
1266 font->ascent = ft_face->size->metrics.ascender >> 6;
1267 font->descent = - ft_face->size->metrics.descender >> 6;
1268 font->height = ft_face->size->metrics.height >> 6;
1270 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1271 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1272 else
1273 spacing = FC_PROPORTIONAL;
1274 if (spacing != FC_PROPORTIONAL
1275 #ifdef FC_DUAL
1276 && spacing != FC_DUAL
1277 #endif /* FC_DUAL */
1279 font->min_width = font->average_width = font->space_width
1280 = (scalable ? ft_face->max_advance_width * size / upEM
1281 : ft_face->size->metrics.max_advance >> 6);
1282 else
1284 int n;
1286 font->min_width = font->average_width = font->space_width = 0;
1287 for (i = 32, n = 0; i < 127; i++)
1288 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1290 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1292 if (this_width > 0
1293 && (! font->min_width || font->min_width > this_width))
1294 font->min_width = this_width;
1295 if (i == 32)
1296 font->space_width = this_width;
1297 font->average_width += this_width;
1298 n++;
1300 if (n > 0)
1301 font->average_width /= n;
1304 font->baseline_offset = 0;
1305 font->relative_compose = 0;
1306 font->default_ascent = 0;
1307 font->vertical_centering = 0;
1308 if (scalable)
1310 font->underline_position = -ft_face->underline_position * size / upEM;
1311 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1313 else
1315 font->underline_position = -1;
1316 font->underline_thickness = 0;
1319 return font_object;
1322 static void
1323 ftfont_close (FRAME_PTR f, struct font *font)
1325 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1326 Lisp_Object val, cache;
1328 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1329 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1330 eassert (CONSP (cache));
1331 val = XCDR (cache);
1332 (XSAVE_VALUE (val)->integer)--;
1333 if (XSAVE_VALUE (val)->integer == 0)
1335 struct ftfont_cache_data *cache_data = XSAVE_VALUE (val)->pointer;
1337 FT_Done_Face (cache_data->ft_face);
1338 #ifdef HAVE_LIBOTF
1339 if (ftfont_info->otf)
1340 OTF_close (ftfont_info->otf);
1341 #endif
1342 cache_data->ft_face = NULL;
1344 else
1345 FT_Done_Size (ftfont_info->ft_size);
1348 static int
1349 ftfont_has_char (Lisp_Object font, int c)
1351 struct charset *cs = NULL;
1353 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1354 && charset_jisx0208 >= 0)
1355 cs = CHARSET_FROM_ID (charset_jisx0208);
1356 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1357 && charset_ksc5601 >= 0)
1358 cs = CHARSET_FROM_ID (charset_ksc5601);
1359 if (cs)
1360 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1362 if (FONT_ENTITY_P (font))
1364 FcCharSet *charset = ftfont_get_fc_charset (font);
1366 return (FcCharSetHasChar (charset, c) == FcTrue);
1368 else
1370 struct ftfont_info *ftfont_info;
1372 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1373 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1374 != 0);
1378 static unsigned
1379 ftfont_encode_char (struct font *font, int c)
1381 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1382 FT_Face ft_face = ftfont_info->ft_size->face;
1383 FT_ULong charcode = c;
1384 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1386 return (code > 0 ? code : FONT_INVALID_CODE);
1389 static int
1390 ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
1392 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1393 FT_Face ft_face = ftfont_info->ft_size->face;
1394 int width = 0;
1395 int i, 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 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, negative;
1687 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1688 /* Return 1 iff any of GSUB or GPOS support the script (and language). */
1689 return (otf
1690 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1691 NULL, 0) > 0
1692 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1693 NULL, 0) > 0));
1695 for (i = 0; i < 2; i++)
1696 if (! FEATURE_ANY (i))
1698 if (FEATURE_NONE (i))
1700 if (otf
1701 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1702 NULL, 0) > 0)
1703 return 0;
1704 continue;
1706 if (spec->features[i][0] == 0xFFFFFFFF)
1708 if (! otf
1709 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1710 NULL, 0) <= 0)
1711 continue;
1713 else if (! otf)
1714 return 0;
1715 for (n = 1; spec->features[i][n]; n++);
1716 tags = alloca (sizeof (OTF_Tag) * n);
1717 for (n = 0, negative = 0; spec->features[i][n]; n++)
1719 if (spec->features[i][n] == 0xFFFFFFFF)
1720 negative = 1;
1721 else if (negative)
1722 tags[n - 1] = spec->features[i][n] | 0x80000000;
1723 else
1724 tags[n] = spec->features[i][n];
1726 #ifdef M17N_FLT_USE_NEW_FEATURE
1727 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1728 tags, n - negative) != 1)
1729 return 0;
1730 #else /* not M17N_FLT_USE_NEW_FEATURE */
1731 if (n - negative > 0
1732 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1733 tags, n - negative) != 1)
1734 return 0;
1735 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1737 return 1;
1738 #undef FEATURE_NONE
1739 #undef FEATURE_ANY
1742 #define DEVICE_DELTA(table, size) \
1743 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1744 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1745 : 0)
1747 static void
1748 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1749 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1751 if (anchor->AnchorFormat == 2)
1753 FT_Outline *outline;
1754 int ap = anchor->f.f1.AnchorPoint;
1756 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1757 outline = &ft_face->glyph->outline;
1758 if (ap < outline->n_points)
1760 *x = outline->points[ap].x << 6;
1761 *y = outline->points[ap].y << 6;
1764 else if (anchor->AnchorFormat == 3)
1766 if (anchor->f.f2.XDeviceTable.offset
1767 && anchor->f.f2.XDeviceTable.DeltaValue)
1768 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1769 if (anchor->f.f2.YDeviceTable.offset
1770 && anchor->f.f2.YDeviceTable.DeltaValue)
1771 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1775 static OTF_GlyphString otf_gstring;
1777 static void
1778 setup_otf_gstring (int size)
1780 if (otf_gstring.size < size)
1782 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1783 size, sizeof (OTF_Glyph));
1784 otf_gstring.size = size;
1786 otf_gstring.used = size;
1787 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1790 #ifdef M17N_FLT_USE_NEW_FEATURE
1792 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1793 #define PACK_OTF_TAG(TAG) \
1794 ((((TAG) & 0x7F000000) >> 3) \
1795 | (((TAG) & 0x7F0000) >> 2) \
1796 | (((TAG) & 0x7F00) >> 1) \
1797 | ((TAG) & 0x7F))
1799 /* Assuming that FONT is an OpenType font, apply OpenType features
1800 specified in SPEC on glyphs between FROM and TO of IN, and record
1801 the lastly applied feature in each glyph of IN. If OUT is not
1802 NULL, append the resulting glyphs to OUT while storing glyph
1803 position adjustment information in ADJUSTMENT. */
1805 static int
1806 ftfont_drive_otf (MFLTFont *font,
1807 MFLTOtfSpec *spec,
1808 MFLTGlyphString *in,
1809 int from,
1810 int to,
1811 MFLTGlyphString *out,
1812 MFLTGlyphAdjustment *adjustment)
1814 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1815 FT_Face ft_face = flt_font_ft->ft_face;
1816 OTF *otf = flt_font_ft->otf;
1817 int len = to - from;
1818 int i, j, gidx;
1819 OTF_Glyph *otfg;
1820 char script[5], *langsys = NULL;
1821 char *gsub_features = NULL, *gpos_features = NULL;
1822 OTF_Feature *features;
1824 if (len == 0)
1825 return from;
1826 OTF_tag_name (spec->script, script);
1827 if (spec->langsys)
1829 langsys = alloca (5);
1830 OTF_tag_name (spec->langsys, langsys);
1832 for (i = 0; i < 2; i++)
1834 char *p;
1836 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1838 for (j = 0; spec->features[i][j]; j++);
1839 if (i == 0)
1840 p = gsub_features = alloca (6 * j);
1841 else
1842 p = gpos_features = alloca (6 * j);
1843 for (j = 0; spec->features[i][j]; j++)
1845 if (spec->features[i][j] == 0xFFFFFFFF)
1846 *p++ = '*', *p++ = ',';
1847 else
1849 OTF_tag_name (spec->features[i][j], p);
1850 p[4] = ',';
1851 p += 5;
1854 *--p = '\0';
1858 setup_otf_gstring (len);
1859 for (i = 0; i < len; i++)
1861 otf_gstring.glyphs[i].c = in->glyphs[from + i].c & 0x11FFFF;
1862 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1865 OTF_drive_gdef (otf, &otf_gstring);
1866 gidx = out ? out->used : from;
1868 if (gsub_features && out)
1870 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1871 gsub_features) < 0)
1872 goto simple_copy;
1873 if (out->allocated < out->used + otf_gstring.used)
1874 return -2;
1875 features = otf->gsub->FeatureList.Feature;
1876 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1878 MFLTGlyph *g;
1879 int min_from, max_to;
1880 int feature_idx = otfg->positioning_type >> 4;
1882 g = out->glyphs + out->used;
1883 *g = in->glyphs[from + otfg->f.index.from];
1884 if (g->code != otfg->glyph_id)
1886 g->c = 0;
1887 g->code = otfg->glyph_id;
1888 g->measured = 0;
1890 out->used++;
1891 min_from = g->from;
1892 max_to = g->to;
1893 if (otfg->f.index.from < otfg->f.index.to)
1895 /* OTFG substitutes multiple glyphs in IN. */
1896 for (j = from + otfg->f.index.from + 1;
1897 j <= from + otfg->f.index.to; j++)
1899 if (min_from > in->glyphs[j].from)
1900 min_from = in->glyphs[j].from;
1901 if (max_to < in->glyphs[j].to)
1902 max_to = in->glyphs[j].to;
1904 g->from = min_from;
1905 g->to = max_to;
1907 if (feature_idx)
1909 unsigned int tag = features[feature_idx - 1].FeatureTag;
1910 tag = PACK_OTF_TAG (tag);
1911 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1913 for (i++, otfg++; (i < otf_gstring.used
1914 && otfg->f.index.from == otfg[-1].f.index.from);
1915 i++, otfg++)
1917 g = out->glyphs + out->used;
1918 *g = in->glyphs[from + otfg->f.index.to];
1919 if (g->code != otfg->glyph_id)
1921 g->c = 0;
1922 g->code = otfg->glyph_id;
1923 g->measured = 0;
1925 feature_idx = otfg->positioning_type >> 4;
1926 if (feature_idx)
1928 unsigned int tag = features[feature_idx - 1].FeatureTag;
1929 tag = PACK_OTF_TAG (tag);
1930 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1932 out->used++;
1936 else if (gsub_features)
1938 /* Just for checking which features will be applied. */
1939 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1940 gsub_features) < 0)
1941 goto simple_copy;
1942 features = otf->gsub->FeatureList.Feature;
1943 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1944 otfg++)
1946 int feature_idx = otfg->positioning_type >> 4;
1948 if (feature_idx)
1950 unsigned int tag = features[feature_idx - 1].FeatureTag;
1951 tag = PACK_OTF_TAG (tag);
1952 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1954 MFLTGlyph *g = in->glyphs + (from + j);
1955 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1960 else if (out)
1962 if (out->allocated < out->used + len)
1963 return -2;
1964 for (i = 0; i < len; i++)
1965 out->glyphs[out->used++] = in->glyphs[from + i];
1968 if (gpos_features && out)
1970 MFLTGlyph *base = NULL, *mark = NULL, *g;
1971 int x_ppem, y_ppem, x_scale, y_scale;
1973 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1974 gpos_features) < 0)
1975 return to;
1976 features = otf->gpos->FeatureList.Feature;
1977 x_ppem = ft_face->size->metrics.x_ppem;
1978 y_ppem = ft_face->size->metrics.y_ppem;
1979 x_scale = ft_face->size->metrics.x_scale;
1980 y_scale = ft_face->size->metrics.y_scale;
1982 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1983 i < otf_gstring.used; i++, otfg++, g++)
1985 MFLTGlyph *prev;
1986 int feature_idx = otfg->positioning_type >> 4;
1988 if (feature_idx)
1990 unsigned int tag = features[feature_idx - 1].FeatureTag;
1991 tag = PACK_OTF_TAG (tag);
1992 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1995 if (! otfg->glyph_id)
1996 continue;
1997 switch (otfg->positioning_type & 0xF)
1999 case 0:
2000 break;
2001 case 1: /* Single */
2002 case 2: /* Pair */
2004 int format = otfg->f.f1.format;
2006 if (format & OTF_XPlacement)
2007 adjustment[i].xoff
2008 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2009 if (format & OTF_XPlaDevice)
2010 adjustment[i].xoff
2011 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2012 if (format & OTF_YPlacement)
2013 adjustment[i].yoff
2014 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2015 if (format & OTF_YPlaDevice)
2016 adjustment[i].yoff
2017 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2018 if (format & OTF_XAdvance)
2019 adjustment[i].xadv
2020 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2021 if (format & OTF_XAdvDevice)
2022 adjustment[i].xadv
2023 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2024 if (format & OTF_YAdvance)
2025 adjustment[i].yadv
2026 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2027 if (format & OTF_YAdvDevice)
2028 adjustment[i].yadv
2029 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2030 adjustment[i].set = 1;
2032 break;
2033 case 3: /* Cursive */
2034 /* Not yet supported. */
2035 break;
2036 case 4: /* Mark-to-Base */
2037 case 5: /* Mark-to-Ligature */
2038 if (! base)
2039 break;
2040 prev = base;
2041 goto label_adjust_anchor;
2042 default: /* i.e. case 6 Mark-to-Mark */
2043 if (! mark)
2044 break;
2045 prev = mark;
2047 label_adjust_anchor:
2049 int base_x, base_y, mark_x, mark_y;
2050 int this_from, this_to;
2052 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2053 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2054 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2055 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2057 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2058 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2059 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2060 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2061 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2062 x_ppem, y_ppem, &mark_x, &mark_y);
2063 adjustment[i].xoff = (base_x - mark_x);
2064 adjustment[i].yoff = - (base_y - mark_y);
2065 adjustment[i].back = (g - prev);
2066 adjustment[i].xadv = 0;
2067 adjustment[i].advance_is_absolute = 1;
2068 adjustment[i].set = 1;
2069 this_from = g->from;
2070 this_to = g->to;
2071 for (j = 0; prev + j < g; j++)
2073 if (this_from > prev[j].from)
2074 this_from = prev[j].from;
2075 if (this_to < prev[j].to)
2076 this_to = prev[j].to;
2078 for (; prev <= g; prev++)
2080 prev->from = this_from;
2081 prev->to = this_to;
2085 if (otfg->GlyphClass == OTF_GlyphClass0)
2086 base = mark = g;
2087 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2088 mark = g;
2089 else
2090 base = g;
2093 else if (gpos_features)
2095 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2096 gpos_features) < 0)
2097 return to;
2098 features = otf->gpos->FeatureList.Feature;
2099 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2100 i++, otfg++)
2101 if (otfg->positioning_type & 0xF)
2103 int feature_idx = otfg->positioning_type >> 4;
2105 if (feature_idx)
2107 unsigned int tag = features[feature_idx - 1].FeatureTag;
2108 tag = PACK_OTF_TAG (tag);
2109 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2111 MFLTGlyph *g = in->glyphs + (from + j);
2112 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2117 return to;
2119 simple_copy:
2120 if (! out)
2121 return to;
2122 if (out->allocated < out->used + len)
2123 return -2;
2124 font->get_metrics (font, in, from, to);
2125 memcpy (out->glyphs + out->used, in->glyphs + from,
2126 sizeof (MFLTGlyph) * len);
2127 out->used += len;
2128 return to;
2131 static int
2132 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2133 MFLTGlyphString *in, int from, int to)
2135 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2138 #else /* not M17N_FLT_USE_NEW_FEATURE */
2140 static int
2141 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2142 int from, int to,
2143 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2145 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2146 FT_Face ft_face = flt_font_ft->ft_face;
2147 OTF *otf = flt_font_ft->otf;
2148 int len = to - from;
2149 int i, j, gidx;
2150 OTF_Glyph *otfg;
2151 char script[5], *langsys = NULL;
2152 char *gsub_features = NULL, *gpos_features = NULL;
2154 if (len == 0)
2155 return from;
2156 OTF_tag_name (spec->script, script);
2157 if (spec->langsys)
2159 langsys = alloca (5);
2160 OTF_tag_name (spec->langsys, langsys);
2162 for (i = 0; i < 2; i++)
2164 char *p;
2166 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2168 for (j = 0; spec->features[i][j]; j++);
2169 if (i == 0)
2170 p = gsub_features = alloca (6 * j);
2171 else
2172 p = gpos_features = alloca (6 * j);
2173 for (j = 0; spec->features[i][j]; j++)
2175 if (spec->features[i][j] == 0xFFFFFFFF)
2176 *p++ = '*', *p++ = ',';
2177 else
2179 OTF_tag_name (spec->features[i][j], p);
2180 p[4] = ',';
2181 p += 5;
2184 *--p = '\0';
2188 setup_otf_gstring (len);
2189 for (i = 0; i < len; i++)
2191 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2192 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2195 OTF_drive_gdef (otf, &otf_gstring);
2196 gidx = out->used;
2198 if (gsub_features)
2200 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2201 < 0)
2202 goto simple_copy;
2203 if (out->allocated < out->used + otf_gstring.used)
2204 return -2;
2205 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2207 MFLTGlyph *g;
2208 int min_from, max_to;
2209 int j;
2211 g = out->glyphs + out->used;
2212 *g = in->glyphs[from + otfg->f.index.from];
2213 if (g->code != otfg->glyph_id)
2215 g->c = 0;
2216 g->code = otfg->glyph_id;
2217 g->measured = 0;
2219 out->used++;
2220 min_from = g->from;
2221 max_to = g->to;
2222 if (otfg->f.index.from < otfg->f.index.to)
2224 /* OTFG substitutes multiple glyphs in IN. */
2225 for (j = from + otfg->f.index.from + 1;
2226 j <= from + otfg->f.index.to; j++)
2228 if (min_from > in->glyphs[j].from)
2229 min_from = in->glyphs[j].from;
2230 if (max_to < in->glyphs[j].to)
2231 max_to = in->glyphs[j].to;
2233 g->from = min_from;
2234 g->to = max_to;
2236 for (i++, otfg++; (i < otf_gstring.used
2237 && otfg->f.index.from == otfg[-1].f.index.from);
2238 i++, otfg++)
2240 g = out->glyphs + out->used;
2241 *g = in->glyphs[from + otfg->f.index.to];
2242 if (g->code != otfg->glyph_id)
2244 g->c = 0;
2245 g->code = otfg->glyph_id;
2246 g->measured = 0;
2248 out->used++;
2252 else
2254 if (out->allocated < out->used + len)
2255 return -2;
2256 for (i = 0; i < len; i++)
2257 out->glyphs[out->used++] = in->glyphs[from + i];
2260 if (gpos_features)
2262 MFLTGlyph *base = NULL, *mark = NULL, *g;
2263 int x_ppem, y_ppem, x_scale, y_scale;
2265 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2266 < 0)
2267 return to;
2269 x_ppem = ft_face->size->metrics.x_ppem;
2270 y_ppem = ft_face->size->metrics.y_ppem;
2271 x_scale = ft_face->size->metrics.x_scale;
2272 y_scale = ft_face->size->metrics.y_scale;
2274 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2275 i < otf_gstring.used; i++, otfg++, g++)
2277 MFLTGlyph *prev;
2279 if (! otfg->glyph_id)
2280 continue;
2281 switch (otfg->positioning_type)
2283 case 0:
2284 break;
2285 case 1: /* Single */
2286 case 2: /* Pair */
2288 int format = otfg->f.f1.format;
2290 if (format & OTF_XPlacement)
2291 adjustment[i].xoff
2292 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2293 if (format & OTF_XPlaDevice)
2294 adjustment[i].xoff
2295 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2296 if (format & OTF_YPlacement)
2297 adjustment[i].yoff
2298 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2299 if (format & OTF_YPlaDevice)
2300 adjustment[i].yoff
2301 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2302 if (format & OTF_XAdvance)
2303 adjustment[i].xadv
2304 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2305 if (format & OTF_XAdvDevice)
2306 adjustment[i].xadv
2307 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2308 if (format & OTF_YAdvance)
2309 adjustment[i].yadv
2310 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2311 if (format & OTF_YAdvDevice)
2312 adjustment[i].yadv
2313 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2314 adjustment[i].set = 1;
2316 break;
2317 case 3: /* Cursive */
2318 /* Not yet supported. */
2319 break;
2320 case 4: /* Mark-to-Base */
2321 case 5: /* Mark-to-Ligature */
2322 if (! base)
2323 break;
2324 prev = base;
2325 goto label_adjust_anchor;
2326 default: /* i.e. case 6 Mark-to-Mark */
2327 if (! mark)
2328 break;
2329 prev = mark;
2331 label_adjust_anchor:
2333 int base_x, base_y, mark_x, mark_y;
2334 int this_from, this_to;
2336 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2337 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2338 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2339 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2341 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2342 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2343 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2344 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2345 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2346 x_ppem, y_ppem, &mark_x, &mark_y);
2347 adjustment[i].xoff = (base_x - mark_x);
2348 adjustment[i].yoff = - (base_y - mark_y);
2349 adjustment[i].back = (g - prev);
2350 adjustment[i].xadv = 0;
2351 adjustment[i].advance_is_absolute = 1;
2352 adjustment[i].set = 1;
2353 this_from = g->from;
2354 this_to = g->to;
2355 for (j = 0; prev + j < g; j++)
2357 if (this_from > prev[j].from)
2358 this_from = prev[j].from;
2359 if (this_to < prev[j].to)
2360 this_to = prev[j].to;
2362 for (; prev <= g; prev++)
2364 prev->from = this_from;
2365 prev->to = this_to;
2369 if (otfg->GlyphClass == OTF_GlyphClass0)
2370 base = mark = g;
2371 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2372 mark = g;
2373 else
2374 base = g;
2377 return to;
2379 simple_copy:
2380 if (out->allocated < out->used + len)
2381 return -2;
2382 font->get_metrics (font, in, from, to);
2383 memcpy (out->glyphs + out->used, in->glyphs + from,
2384 sizeof (MFLTGlyph) * len);
2385 out->used += len;
2386 return to;
2389 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2391 static MFLTGlyphString gstring;
2393 static int m17n_flt_initialized;
2395 static Lisp_Object
2396 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2397 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2399 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2400 ptrdiff_t i;
2401 struct MFLTFontFT flt_font_ft;
2402 MFLT *flt = NULL;
2403 int with_variation_selector = 0;
2405 if (! m17n_flt_initialized)
2407 M17N_INIT ();
2408 #ifdef M17N_FLT_USE_NEW_FEATURE
2409 mflt_enable_new_feature = 1;
2410 mflt_try_otf = ftfont_try_otf;
2411 #endif /* M17N_FLT_USE_NEW_FEATURE */
2412 m17n_flt_initialized = 1;
2415 for (i = 0; i < len; i++)
2417 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2418 int c;
2420 if (NILP (g))
2421 break;
2422 c = LGLYPH_CHAR (g);
2423 if (CHAR_VARIATION_SELECTOR_P (c))
2424 with_variation_selector++;
2427 len = i;
2428 lint_assume (len <= STRING_BYTES_BOUND);
2430 if (with_variation_selector)
2432 setup_otf_gstring (len);
2433 for (i = 0; i < len; i++)
2435 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2437 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2438 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2439 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2441 OTF_drive_cmap (otf, &otf_gstring);
2442 for (i = 0; i < otf_gstring.used; i++)
2444 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2445 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2446 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2448 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2449 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2450 LGSTRING_SET_GLYPH (lgstring, i, g0);
2452 if (len > otf_gstring.used)
2454 len = otf_gstring.used;
2455 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2459 if (INT_MAX / 2 < len)
2460 memory_full (SIZE_MAX);
2462 if (gstring.allocated == 0)
2464 gstring.glyph_size = sizeof (MFLTGlyph);
2465 gstring.glyphs = xnmalloc (len * 2, sizeof *gstring.glyphs);
2466 gstring.allocated = len * 2;
2468 else if (gstring.allocated < len * 2)
2470 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2,
2471 sizeof *gstring.glyphs);
2472 gstring.allocated = len * 2;
2474 memset (gstring.glyphs, 0, len * sizeof *gstring.glyphs);
2475 for (i = 0; i < len; i++)
2477 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2479 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2480 if (with_variation_selector)
2482 gstring.glyphs[i].code = LGLYPH_CODE (g);
2483 gstring.glyphs[i].encoded = 1;
2487 gstring.used = len;
2488 gstring.r2l = 0;
2491 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2493 if (NILP (family))
2494 flt_font_ft.flt_font.family = Mnil;
2495 else
2496 flt_font_ft.flt_font.family
2497 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2499 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2500 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2501 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2502 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2503 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2504 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2505 flt_font_ft.flt_font.internal = NULL;
2506 flt_font_ft.font = font;
2507 flt_font_ft.ft_face = ft_face;
2508 flt_font_ft.otf = otf;
2509 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2510 if (len > 1
2511 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2512 /* A little bit ad hoc. Perhaps, shaper must get script and
2513 language information, and select a proper flt for them
2514 here. */
2515 flt = mflt_get (msymbol ("combining"));
2516 for (i = 0; i < 3; i++)
2518 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2519 if (result != -2)
2520 break;
2521 if (INT_MAX / 2 < gstring.allocated)
2522 memory_full (SIZE_MAX);
2523 gstring.glyphs = xnrealloc (gstring.glyphs,
2524 gstring.allocated, 2 * sizeof (MFLTGlyph));
2525 gstring.allocated *= 2;
2527 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2528 return Qnil;
2529 for (i = 0; i < gstring.used; i++)
2531 MFLTGlyph *g = gstring.glyphs + i;
2533 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2534 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2537 for (i = 0; i < gstring.used; i++)
2539 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2540 MFLTGlyph *g = gstring.glyphs + i;
2542 if (NILP (lglyph))
2544 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2545 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2547 LGLYPH_SET_FROM (lglyph, g->from);
2548 LGLYPH_SET_TO (lglyph, g->to);
2549 LGLYPH_SET_CHAR (lglyph, g->c);
2550 LGLYPH_SET_CODE (lglyph, g->code);
2551 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2552 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2553 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2554 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2555 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2556 if (g->adjusted)
2558 Lisp_Object vec;
2560 vec = Fmake_vector (make_number (3), Qnil);
2561 ASET (vec, 0, make_number (g->xoff >> 6));
2562 ASET (vec, 1, make_number (g->yoff >> 6));
2563 ASET (vec, 2, make_number (g->xadv >> 6));
2564 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2567 return make_number (i);
2570 Lisp_Object
2571 ftfont_shape (Lisp_Object lgstring)
2573 struct font *font;
2574 struct ftfont_info *ftfont_info;
2575 OTF *otf;
2577 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2578 ftfont_info = (struct ftfont_info *) font;
2579 otf = ftfont_get_otf (ftfont_info);
2580 if (! otf)
2581 return make_number (0);
2582 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2583 &ftfont_info->matrix);
2586 #endif /* HAVE_M17N_FLT */
2588 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2590 static int
2591 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2593 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2594 OTF *otf = ftfont_get_otf (ftfont_info);
2596 if (! otf)
2597 return 0;
2598 return OTF_get_variation_glyphs (otf, c, variations);
2601 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2602 #endif /* HAVE_LIBOTF */
2604 Lisp_Object
2605 ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
2607 FcChar8 *str;
2609 #ifdef FC_FONTFORMAT
2610 if (pattern)
2612 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2613 return Qnil;
2614 if (strcmp ((char *) str, "TrueType") == 0)
2615 return intern ("truetype");
2616 if (strcmp ((char *) str, "Type 1") == 0)
2617 return intern ("type1");
2618 if (strcmp ((char *) str, "PCF") == 0)
2619 return intern ("pcf");
2620 if (strcmp ((char *) str, "BDF") == 0)
2621 return intern ("bdf");
2623 #endif /* FC_FONTFORMAT */
2624 if (STRINGP (filename))
2626 int len = SBYTES (filename);
2628 if (len >= 4)
2630 str = (FcChar8 *) (SDATA (filename) + len - 4);
2631 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2632 return intern ("truetype");
2633 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2634 return intern ("type1");
2635 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2636 return intern ("pcf");
2637 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2638 return intern ("bdf");
2641 return intern ("unknown");
2644 static const char *const ftfont_booleans [] = {
2645 ":antialias",
2646 ":hinting",
2647 ":verticallayout",
2648 ":autohint",
2649 ":globaladvance",
2650 ":outline",
2651 ":scalable",
2652 ":minspace",
2653 ":embolden",
2654 NULL,
2657 static const char *const ftfont_non_booleans [] = {
2658 ":family",
2659 ":familylang",
2660 ":style",
2661 ":stylelang",
2662 ":fullname",
2663 ":fullnamelang",
2664 ":slant",
2665 ":weight",
2666 ":size",
2667 ":width",
2668 ":aspect",
2669 ":pixelsize",
2670 ":spacing",
2671 ":foundry",
2672 ":hintstyle",
2673 ":file",
2674 ":index",
2675 ":ftface",
2676 ":rasterizer",
2677 ":scale",
2678 ":dpi",
2679 ":rgba",
2680 ":lcdfilter",
2681 ":charset",
2682 ":lang",
2683 ":fontversion",
2684 ":capability",
2685 NULL,
2688 static void
2689 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2691 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2695 void
2696 syms_of_ftfont (void)
2698 DEFSYM (Qfreetype, "freetype");
2699 DEFSYM (Qmonospace, "monospace");
2700 DEFSYM (Qsans_serif, "sans-serif");
2701 DEFSYM (Qserif, "serif");
2702 DEFSYM (Qmono, "mono");
2703 DEFSYM (Qsans, "sans");
2704 DEFSYM (Qsans__serif, "sans serif");
2706 staticpro (&freetype_font_cache);
2707 freetype_font_cache = Fcons (Qt, Qnil);
2709 staticpro (&ftfont_generic_family_list);
2710 ftfont_generic_family_list
2711 = Fcons (Fcons (Qmonospace, Qt),
2712 Fcons (Fcons (Qsans_serif, Qt),
2713 Fcons (Fcons (Qsans, Qt), Qnil)));
2715 staticpro (&ft_face_cache);
2716 ft_face_cache = Qnil;
2718 ftfont_driver.type = Qfreetype;
2719 register_font_driver (&ftfont_driver, NULL);