Handle deferred `event-kind' property when using unread-command-events.
[emacs.git] / src / ftfont.c
blob6a7c09407b4cb1150af13ef19f13525d50804b27
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 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 P_ ((FcPattern *, Lisp_Object));
85 static Lisp_Object ftfont_resolve_generic_family P_ ((Lisp_Object,
86 FcPattern *));
87 static Lisp_Object ftfont_lookup_cache P_ ((Lisp_Object,
88 enum ftfont_cache_for));
90 static void ftfont_filter_properties P_ ((Lisp_Object font, Lisp_Object alist));
92 Lisp_Object ftfont_font_format P_ ((FcPattern *, Lisp_Object));
94 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
96 static struct
98 /* registry name */
99 char *name;
100 /* characters to distinguish the charset from the others */
101 int uniquifier[6];
102 /* additional constraint by language */
103 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 extern Lisp_Object Qc, Qm, Qp, Qd;
149 /* Dirty hack for handing ADSTYLE property.
151 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
152 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
153 "Oblique", "Italic", or any non-normal SWIDTH property names
154 (e.g. SemiCondensed) are appended. In addition, if there's no
155 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
156 "Regular" is used for FC_STYLE (see the function
157 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
159 Unfortunately this behavior is not documented, so the following
160 code may fail if FreeType changes the behavior in the future. */
162 static Lisp_Object
163 get_adstyle_property (FcPattern *p)
165 unsigned char *str, *end;
166 Lisp_Object adstyle;
168 if (FcPatternGetString (p, FC_STYLE, 0, (FcChar8 **) &str) != FcResultMatch)
169 return Qnil;
170 for (end = str; *end && *end != ' '; end++);
171 if (*end)
173 char *p = alloca (end - str + 1);
174 memcpy (p, str, end - str);
175 p[end - str] = '\0';
176 end = p + (end - str);
177 str = p;
179 if (xstrcasecmp (str, "Regular") == 0
180 || xstrcasecmp (str, "Bold") == 0
181 || xstrcasecmp (str, "Oblique") == 0
182 || xstrcasecmp (str, "Italic") == 0)
183 return Qnil;
184 adstyle = font_intern_prop (str, end - str, 1);
185 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
186 return Qnil;
187 return adstyle;
190 static Lisp_Object
191 ftfont_pattern_entity (p, extra)
192 FcPattern *p;
193 Lisp_Object extra;
195 Lisp_Object key, cache, entity;
196 unsigned char *file, *str;
197 int index;
198 int numeric;
199 double dbl;
200 FcBool b;
202 if (FcPatternGetString (p, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch)
203 return Qnil;
204 if (FcPatternGetInteger (p, FC_INDEX, 0, &index) != FcResultMatch)
205 return Qnil;
207 key = Fcons (make_unibyte_string ((char *) file, strlen ((char *) file)),
208 make_number (index));
209 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
210 entity = XCAR (cache);
211 if (! NILP (entity))
213 Lisp_Object val = font_make_entity ();
214 int i;
216 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
217 ASET (val, i, AREF (entity, i));
218 return val;
220 entity = font_make_entity ();
221 XSETCAR (cache, entity);
223 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
224 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
226 if (FcPatternGetString (p, FC_FOUNDRY, 0, (FcChar8 **) &str) == FcResultMatch)
227 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (str, strlen (str), 1));
228 if (FcPatternGetString (p, FC_FAMILY, 0, (FcChar8 **) &str) == FcResultMatch)
229 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (str, strlen (str), 1));
230 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
232 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
233 numeric = FC_WEIGHT_MEDIUM;
234 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
236 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
238 numeric += 100;
239 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
241 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
243 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
245 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
247 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
249 else
250 ASET (entity, FONT_SIZE_INDEX, make_number (0));
251 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
252 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
253 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
255 int dpi = dbl;
256 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
258 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
259 && b == FcTrue)
261 ASET (entity, FONT_SIZE_INDEX, make_number (0));
262 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
264 else
266 /* As this font is not scalable, parhaps this is a BDF or PCF
267 font. */
268 FT_Face ft_face;
270 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
271 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
272 && FT_New_Face (ft_library, file, index, &ft_face) == 0)
274 BDF_PropertyRec rec;
276 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
277 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
278 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
279 FT_Done_Face (ft_face);
283 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
284 font_put_extra (entity, QCfont_entity, key);
285 return entity;
289 static Lisp_Object ftfont_generic_family_list;
291 static Lisp_Object
292 ftfont_resolve_generic_family (family, pattern)
293 Lisp_Object family;
294 FcPattern *pattern;
296 Lisp_Object slot;
297 FcPattern *match;
298 FcResult result;
299 FcLangSet *langset;
301 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
302 if (EQ (family, Qmono))
303 family = Qmonospace;
304 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
305 family = Qsans_serif;
306 slot = assq_no_quit (family, ftfont_generic_family_list);
307 if (! CONSP (slot))
308 return Qnil;
309 if (! EQ (XCDR (slot), Qt))
310 return XCDR (slot);
311 pattern = FcPatternDuplicate (pattern);
312 if (! pattern)
313 goto err;
314 FcPatternDel (pattern, FC_FOUNDRY);
315 FcPatternDel (pattern, FC_FAMILY);
316 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
317 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
319 /* This is to avoid the effect of locale. */
320 langset = FcLangSetCreate ();
321 FcLangSetAdd (langset, "en");
322 FcPatternAddLangSet (pattern, FC_LANG, langset);
323 FcLangSetDestroy (langset);
325 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
326 FcDefaultSubstitute (pattern);
327 match = FcFontMatch (NULL, pattern, &result);
328 if (match)
330 FcChar8 *fam;
332 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
333 family = intern ((char *) fam);
335 else
336 family = Qnil;
337 XSETCDR (slot, family);
338 if (match) FcPatternDestroy (match);
339 err:
340 if (pattern) FcPatternDestroy (pattern);
341 return family;
344 struct ftfont_cache_data
346 FT_Face ft_face;
347 FcCharSet *fc_charset;
350 static Lisp_Object
351 ftfont_lookup_cache (key, cache_for)
352 Lisp_Object key;
353 enum ftfont_cache_for cache_for;
355 Lisp_Object cache, val, entity;
356 struct ftfont_cache_data *cache_data;
358 if (FONT_ENTITY_P (key))
360 entity = key;
361 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
362 xassert (CONSP (val));
363 key = XCDR (val);
365 else
366 entity = Qnil;
368 if (NILP (ft_face_cache))
369 cache = Qnil;
370 else
371 cache = Fgethash (key, ft_face_cache, Qnil);
372 if (NILP (cache))
374 if (NILP (ft_face_cache))
376 Lisp_Object args[2];
378 args[0] = QCtest;
379 args[1] = Qequal;
380 ft_face_cache = Fmake_hash_table (2, args);
382 cache_data = xmalloc (sizeof (struct ftfont_cache_data));
383 cache_data->ft_face = NULL;
384 cache_data->fc_charset = NULL;
385 val = make_save_value (NULL, 0);
386 XSAVE_VALUE (val)->integer = 0;
387 XSAVE_VALUE (val)->pointer = cache_data;
388 cache = Fcons (Qnil, val);
389 Fputhash (key, cache, ft_face_cache);
391 else
393 val = XCDR (cache);
394 cache_data = XSAVE_VALUE (val)->pointer;
397 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
398 return cache;
400 if (cache_for == FTFONT_CACHE_FOR_FACE
401 ? ! cache_data->ft_face : ! cache_data->fc_charset)
403 char *filename = (char *) SDATA (XCAR (key));
404 int index = XINT (XCDR (key));
406 if (cache_for == FTFONT_CACHE_FOR_FACE)
408 if (! ft_library
409 && FT_Init_FreeType (&ft_library) != 0)
410 return Qnil;
411 if (FT_New_Face (ft_library, filename, index, &cache_data->ft_face)
412 != 0)
413 return Qnil;
415 else
417 FcPattern *pat = NULL;
418 FcFontSet *fontset = NULL;
419 FcObjectSet *objset = NULL;
420 FcCharSet *charset = NULL;
422 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
423 FC_INDEX, FcTypeInteger, index, NULL);
424 if (! pat)
425 goto finish;
426 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
427 if (! objset)
428 goto finish;
429 fontset = FcFontList (NULL, pat, objset);
430 if (! fontset)
431 goto finish;
432 if (fontset && fontset->nfont > 0
433 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
434 &charset)
435 == FcResultMatch))
436 cache_data->fc_charset = FcCharSetCopy (charset);
437 else
438 cache_data->fc_charset = FcCharSetCreate ();
440 finish:
441 if (fontset)
442 FcFontSetDestroy (fontset);
443 if (objset)
444 FcObjectSetDestroy (objset);
445 if (pat)
446 FcPatternDestroy (pat);
449 return cache;
452 FcCharSet *
453 ftfont_get_fc_charset (entity)
454 Lisp_Object entity;
456 Lisp_Object val, cache;
457 struct ftfont_cache_data *cache_data;
459 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
460 val = XCDR (cache);
461 cache_data = XSAVE_VALUE (val)->pointer;
462 return cache_data->fc_charset;
465 #ifdef HAVE_LIBOTF
466 static OTF *
467 ftfont_get_otf (ftfont_info)
468 struct ftfont_info *ftfont_info;
470 OTF *otf;
472 if (ftfont_info->otf)
473 return ftfont_info->otf;
474 if (! ftfont_info->maybe_otf)
475 return NULL;
476 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
477 if (! otf || OTF_get_table (otf, "head") < 0)
479 if (otf)
480 OTF_close (otf);
481 ftfont_info->maybe_otf = 0;
482 return NULL;
484 ftfont_info->otf = otf;
485 return otf;
487 #endif /* HAVE_LIBOTF */
489 static Lisp_Object ftfont_get_cache P_ ((FRAME_PTR));
490 static Lisp_Object ftfont_list P_ ((Lisp_Object, Lisp_Object));
491 static Lisp_Object ftfont_match P_ ((Lisp_Object, Lisp_Object));
492 static Lisp_Object ftfont_list_family P_ ((Lisp_Object));
493 static Lisp_Object ftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
494 static void ftfont_close P_ ((FRAME_PTR, struct font *));
495 static int ftfont_has_char P_ ((Lisp_Object, int));
496 static unsigned ftfont_encode_char P_ ((struct font *, int));
497 static int ftfont_text_extents P_ ((struct font *, unsigned *, int,
498 struct font_metrics *));
499 static int ftfont_get_bitmap P_ ((struct font *, unsigned,
500 struct font_bitmap *, int));
501 static int ftfont_anchor_point P_ ((struct font *, unsigned, int,
502 int *, int *));
503 static Lisp_Object ftfont_otf_capability P_ ((struct font *));
504 static Lisp_Object ftfont_shape P_ ((Lisp_Object));
506 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
507 static int ftfont_variation_glyphs P_ ((struct font *, int c,
508 unsigned variations[256]));
509 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
511 struct font_driver ftfont_driver =
513 0, /* Qfreetype */
514 0, /* case insensitive */
515 ftfont_get_cache,
516 ftfont_list,
517 ftfont_match,
518 ftfont_list_family,
519 NULL, /* free_entity */
520 ftfont_open,
521 ftfont_close,
522 /* We can't draw a text without device dependent functions. */
523 NULL, /* prepare_face */
524 NULL, /* done_face */
525 ftfont_has_char,
526 ftfont_encode_char,
527 ftfont_text_extents,
528 /* We can't draw a text without device dependent functions. */
529 NULL, /* draw */
530 ftfont_get_bitmap,
531 NULL, /* get_bitmap */
532 NULL, /* free_bitmap */
533 NULL, /* get_outline */
534 ftfont_anchor_point,
535 #ifdef HAVE_LIBOTF
536 ftfont_otf_capability,
537 #else /* not HAVE_LIBOTF */
538 NULL,
539 #endif /* not HAVE_LIBOTF */
540 NULL, /* otf_drive */
541 NULL, /* start_for_frame */
542 NULL, /* end_for_frame */
543 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
544 ftfont_shape,
545 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
546 NULL,
547 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
548 NULL, /* check */
550 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
551 ftfont_variation_glyphs,
552 #else
553 NULL,
554 #endif
556 ftfont_filter_properties, /* filter_properties */
559 extern Lisp_Object QCname;
561 static Lisp_Object
562 ftfont_get_cache (f)
563 FRAME_PTR f;
565 return freetype_font_cache;
568 static int
569 ftfont_get_charset (registry)
570 Lisp_Object registry;
572 char *str = (char *) SDATA (SYMBOL_NAME (registry));
573 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
574 Lisp_Object regexp;
575 int i, j;
577 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
579 if (str[i] == '.')
580 re[j++] = '\\';
581 else if (str[i] == '*')
582 re[j++] = '.';
583 re[j] = str[i];
584 if (re[j] == '?')
585 re[j] = '.';
587 re[j] = '\0';
588 regexp = make_unibyte_string (re, j);
589 for (i = 0; fc_charset_table[i].name; i++)
590 if (fast_c_string_match_ignore_case (regexp, fc_charset_table[i].name) >= 0)
591 break;
592 if (! fc_charset_table[i].name)
593 return -1;
594 if (! fc_charset_table[i].fc_charset)
596 FcCharSet *charset = FcCharSetCreate ();
597 int *uniquifier = fc_charset_table[i].uniquifier;
599 if (! charset)
600 return -1;
601 for (j = 0; uniquifier[j]; j++)
602 if (! FcCharSetAddChar (charset, uniquifier[j]))
604 FcCharSetDestroy (charset);
605 return -1;
607 fc_charset_table[i].fc_charset = charset;
609 return i;
612 struct OpenTypeSpec
614 Lisp_Object script;
615 unsigned int script_tag, langsys_tag;
616 int nfeatures[2];
617 unsigned int *features[2];
620 #define OTF_SYM_TAG(SYM, TAG) \
621 do { \
622 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
623 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
624 } while (0)
626 #define OTF_TAG_STR(TAG, P) \
627 do { \
628 (P)[0] = (char) (TAG >> 24); \
629 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
630 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
631 (P)[3] = (char) (TAG & 0xFF); \
632 (P)[4] = '\0'; \
633 } while (0)
635 #define OTF_TAG_SYM(SYM, TAG) \
636 do { \
637 char str[5]; \
639 OTF_TAG_STR (TAG, str); \
640 (SYM) = font_intern_prop (str, 4, 1); \
641 } while (0)
644 static struct OpenTypeSpec *
645 ftfont_get_open_type_spec (Lisp_Object otf_spec)
647 struct OpenTypeSpec *spec = malloc (sizeof (struct OpenTypeSpec));
648 Lisp_Object val;
649 int i, j, negative;
651 if (! spec)
652 return NULL;
653 spec->script = XCAR (otf_spec);
654 if (! NILP (spec->script))
656 OTF_SYM_TAG (spec->script, spec->script_tag);
657 val = assq_no_quit (spec->script, Votf_script_alist);
658 if (CONSP (val) && SYMBOLP (XCDR (val)))
659 spec->script = XCDR (val);
660 else
661 spec->script = Qnil;
663 else
664 spec->script_tag = 0x44464C54; /* "DFLT" */
665 otf_spec = XCDR (otf_spec);
666 spec->langsys_tag = 0;
667 if (! NILP (otf_spec))
669 val = XCAR (otf_spec);
670 if (! NILP (val))
671 OTF_SYM_TAG (val, spec->langsys_tag);
672 otf_spec = XCDR (otf_spec);
674 spec->nfeatures[0] = spec->nfeatures[1] = 0;
675 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
677 Lisp_Object len;
679 val = XCAR (otf_spec);
680 if (NILP (val))
681 continue;
682 len = Flength (val);
683 spec->features[i] = malloc (sizeof (int) * XINT (len));
684 if (! spec->features[i])
686 if (i > 0 && spec->features[0])
687 free (spec->features[0]);
688 free (spec);
689 return NULL;
691 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
693 if (NILP (XCAR (val)))
694 negative = 1;
695 else
697 unsigned int tag;
699 OTF_SYM_TAG (XCAR (val), tag);
700 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
703 spec->nfeatures[i] = j;
705 return spec;
708 static FcPattern *ftfont_spec_pattern P_ ((Lisp_Object, char *,
709 struct OpenTypeSpec **,
710 char **langname));
712 static FcPattern *
713 ftfont_spec_pattern (spec, otlayout, otspec, langname)
714 Lisp_Object spec;
715 char *otlayout;
716 struct OpenTypeSpec **otspec;
717 char **langname;
719 Lisp_Object tmp, extra;
720 FcPattern *pattern = NULL;
721 FcCharSet *charset = NULL;
722 FcLangSet *langset = NULL;
723 int n;
724 int dpi = -1;
725 int scalable = -1;
726 Lisp_Object script = Qnil;
727 Lisp_Object registry;
728 int fc_charset_idx;
730 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
731 && n < 100)
732 /* Fontconfig doesn't support reverse-italic/obligue. */
733 return NULL;
735 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
736 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
737 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
738 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
739 scalable = 1;
741 registry = AREF (spec, FONT_REGISTRY_INDEX);
742 if (NILP (registry)
743 || EQ (registry, Qascii_0)
744 || EQ (registry, Qiso10646_1)
745 || EQ (registry, Qunicode_bmp))
746 fc_charset_idx = -1;
747 else
749 FcChar8 *lang;
751 fc_charset_idx = ftfont_get_charset (registry);
752 if (fc_charset_idx < 0)
753 return NULL;
754 charset = fc_charset_table[fc_charset_idx].fc_charset;
755 *langname = fc_charset_table[fc_charset_idx].lang;
756 lang = (FcChar8 *) *langname;
757 if (lang)
759 langset = FcLangSetCreate ();
760 if (! langset)
761 goto err;
762 FcLangSetAdd (langset, lang);
766 otlayout[0] = '\0';
767 for (extra = AREF (spec, FONT_EXTRA_INDEX);
768 CONSP (extra); extra = XCDR (extra))
770 Lisp_Object key, val;
772 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
773 if (EQ (key, QCdpi))
774 dpi = XINT (val);
775 else if (EQ (key, QClang))
777 if (! langset)
778 langset = FcLangSetCreate ();
779 if (! langset)
780 goto err;
781 if (SYMBOLP (val))
783 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
784 goto err;
786 else
787 for (; CONSP (val); val = XCDR (val))
788 if (SYMBOLP (XCAR (val))
789 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
790 goto err;
792 else if (EQ (key, QCotf))
794 *otspec = ftfont_get_open_type_spec (val);
795 if (! *otspec)
796 return NULL;
797 strcat (otlayout, "otlayout:");
798 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
799 script = (*otspec)->script;
801 else if (EQ (key, QCscript))
802 script = val;
803 else if (EQ (key, QCscalable))
804 scalable = ! NILP (val);
807 if (! NILP (script) && ! charset)
809 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
811 if (CONSP (chars) && CONSP (CDR (chars)))
813 charset = FcCharSetCreate ();
814 if (! charset)
815 goto err;
816 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
817 if (CHARACTERP (XCAR (chars))
818 && ! FcCharSetAddChar (charset, XUINT (XCAR (chars))))
819 goto err;
823 pattern = FcPatternCreate ();
824 if (! pattern)
825 goto err;
826 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
827 if (! NILP (tmp)
828 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
829 goto err;
830 tmp = AREF (spec, FONT_FAMILY_INDEX);
831 if (! NILP (tmp)
832 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
833 goto err;
834 if (charset
835 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
836 goto err;
837 if (langset
838 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
839 goto err;
840 if (dpi >= 0
841 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
842 goto err;
843 if (scalable >= 0
844 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
845 goto err;
847 goto finish;
849 err:
850 /* We come here because of unexpected error in fontconfig API call
851 (usually insufficient memory). */
852 if (pattern)
854 FcPatternDestroy (pattern);
855 pattern = NULL;
857 if (*otspec)
859 if ((*otspec)->nfeatures[0] > 0)
860 free ((*otspec)->features[0]);
861 if ((*otspec)->nfeatures[1] > 0)
862 free ((*otspec)->features[1]);
863 free (*otspec);
864 *otspec = NULL;
867 finish:
868 if (langset) FcLangSetDestroy (langset);
869 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
870 return pattern;
873 static Lisp_Object
874 ftfont_list (frame, spec)
875 Lisp_Object frame, spec;
877 Lisp_Object val = Qnil, family, adstyle;
878 int i;
879 FcPattern *pattern;
880 FcFontSet *fontset = NULL;
881 FcObjectSet *objset = NULL;
882 FcCharSet *charset;
883 Lisp_Object chars = Qnil;
884 FcResult result;
885 char otlayout[15]; /* For "otlayout:XXXX" */
886 struct OpenTypeSpec *otspec = NULL;
887 int spacing = -1;
888 char *langname = NULL;
890 if (! fc_initialized)
892 FcInit ();
893 fc_initialized = 1;
896 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
897 if (! pattern)
898 return Qnil;
899 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
901 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
902 if (! NILP (val))
904 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
905 if (CONSP (val) && VECTORP (XCDR (val)))
906 chars = XCDR (val);
908 val = Qnil;
910 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
911 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
912 family = AREF (spec, FONT_FAMILY_INDEX);
913 if (! NILP (family))
915 Lisp_Object resolved;
917 resolved = ftfont_resolve_generic_family (family, pattern);
918 if (! NILP (resolved))
920 FcPatternDel (pattern, FC_FAMILY);
921 if (! FcPatternAddString (pattern, FC_FAMILY,
922 SYMBOL_FcChar8 (resolved)))
923 goto err;
926 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
927 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
928 adstyle = Qnil;
929 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
930 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
931 FC_STYLE, FC_FILE, FC_INDEX,
932 #ifdef FC_CAPABILITY
933 FC_CAPABILITY,
934 #endif /* FC_CAPABILITY */
935 #ifdef FC_FONTFORMAT
936 FC_FONTFORMAT,
937 #endif
938 NULL);
939 if (! objset)
940 goto err;
941 if (! NILP (chars))
942 FcObjectSetAdd (objset, FC_CHARSET);
944 fontset = FcFontList (NULL, pattern, objset);
945 if (! fontset || fontset->nfont == 0)
946 goto finish;
947 #if 0
948 /* Need fix because this finds any fonts. */
949 if (fontset->nfont == 0 && ! NILP (family))
951 /* Try maching with configuration. For instance, the
952 configuration may specify "Nimbus Mono L" as an alias of
953 "Courier". */
954 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
955 SYMBOL_FcChar8 (family), NULL);
956 FcChar8 *fam;
958 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
960 for (i = 0;
961 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
962 i++)
964 FcPatternDel (pattern, FC_FAMILY);
965 FcPatternAddString (pattern, FC_FAMILY, fam);
966 FcFontSetDestroy (fontset);
967 fontset = FcFontList (NULL, pattern, objset);
968 if (fontset && fontset->nfont > 0)
969 break;
973 #endif
974 for (i = 0; i < fontset->nfont; i++)
976 Lisp_Object entity;
978 if (spacing >= 0)
980 int this;
982 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
983 == FcResultMatch)
984 && spacing != this)
985 continue;
988 #ifdef FC_CAPABILITY
989 if (otlayout[0])
991 FcChar8 *this;
993 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
994 != FcResultMatch
995 || ! strstr ((char *) this, otlayout))
996 continue;
998 #endif /* FC_CAPABILITY */
999 #ifdef HAVE_LIBOTF
1000 if (otspec)
1002 FcChar8 *file;
1003 OTF *otf;
1005 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1006 != FcResultMatch)
1007 continue;
1008 otf = OTF_open ((char *) file);
1009 if (! otf)
1010 continue;
1011 if (OTF_check_features (otf, 1,
1012 otspec->script_tag, otspec->langsys_tag,
1013 otspec->features[0],
1014 otspec->nfeatures[0]) != 1
1015 || OTF_check_features (otf, 0,
1016 otspec->script_tag, otspec->langsys_tag,
1017 otspec->features[1],
1018 otspec->nfeatures[1]) != 1)
1019 continue;
1021 #endif /* HAVE_LIBOTF */
1022 if (VECTORP (chars))
1024 int j;
1026 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1027 != FcResultMatch)
1028 continue;
1029 for (j = 0; j < ASIZE (chars); j++)
1030 if (NATNUMP (AREF (chars, j))
1031 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1032 break;
1033 if (j == ASIZE (chars))
1034 continue;
1036 if (! NILP (adstyle) || langname)
1038 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1040 if (! NILP (adstyle)
1041 && (NILP (this_adstyle)
1042 || xstrcasecmp (SDATA (SYMBOL_NAME (adstyle)),
1043 SDATA (SYMBOL_NAME (this_adstyle))) != 0))
1044 continue;
1045 if (langname
1046 && ! NILP (this_adstyle)
1047 && xstrcasecmp (langname, SDATA (SYMBOL_NAME (this_adstyle))))
1048 continue;
1050 entity = ftfont_pattern_entity (fontset->fonts[i],
1051 AREF (spec, FONT_EXTRA_INDEX));
1052 if (! NILP (entity))
1053 val = Fcons (entity, val);
1055 val = Fnreverse (val);
1056 goto finish;
1058 err:
1059 /* We come here because of unexpected error in fontconfig API call
1060 (usually insufficient memory). */
1061 val = Qnil;
1063 finish:
1064 FONT_ADD_LOG ("ftfont-list", spec, val);
1065 if (objset) FcObjectSetDestroy (objset);
1066 if (fontset) FcFontSetDestroy (fontset);
1067 if (pattern) FcPatternDestroy (pattern);
1068 return val;
1071 static Lisp_Object
1072 ftfont_match (frame, spec)
1073 Lisp_Object frame, spec;
1075 Lisp_Object entity = Qnil;
1076 FcPattern *pattern, *match = NULL;
1077 FcResult result;
1078 char otlayout[15]; /* For "otlayout:XXXX" */
1079 struct OpenTypeSpec *otspec = NULL;
1080 char *langname = NULL;
1082 if (! fc_initialized)
1084 FcInit ();
1085 fc_initialized = 1;
1088 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1089 if (! pattern)
1090 return Qnil;
1092 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1094 FcValue value;
1096 value.type = FcTypeDouble;
1097 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1098 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1100 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1102 FcDefaultSubstitute (pattern);
1103 match = FcFontMatch (NULL, pattern, &result);
1104 if (match)
1106 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1107 FcPatternDestroy (match);
1108 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1109 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1110 ftfont_generic_family_list))
1111 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1112 AREF (entity, FONT_FAMILY_INDEX))))
1113 entity = Qnil;
1116 FcPatternDestroy (pattern);
1118 FONT_ADD_LOG ("ftfont-match", spec, entity);
1119 return entity;
1122 static Lisp_Object
1123 ftfont_list_family (frame)
1124 Lisp_Object frame;
1126 Lisp_Object list = Qnil;
1127 FcPattern *pattern = NULL;
1128 FcFontSet *fontset = NULL;
1129 FcObjectSet *objset = NULL;
1130 int i;
1132 if (! fc_initialized)
1134 FcInit ();
1135 fc_initialized = 1;
1138 pattern = FcPatternCreate ();
1139 if (! pattern)
1140 goto finish;
1141 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1142 if (! objset)
1143 goto finish;
1144 fontset = FcFontList (NULL, pattern, objset);
1145 if (! fontset)
1146 goto finish;
1148 for (i = 0; i < fontset->nfont; i++)
1150 FcPattern *pat = fontset->fonts[i];
1151 FcChar8 *str;
1153 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1154 list = Fcons (intern ((char *) str), list);
1157 finish:
1158 if (objset) FcObjectSetDestroy (objset);
1159 if (fontset) FcFontSetDestroy (fontset);
1160 if (pattern) FcPatternDestroy (pattern);
1162 return list;
1166 static Lisp_Object
1167 ftfont_open (f, entity, pixel_size)
1168 FRAME_PTR f;
1169 Lisp_Object entity;
1170 int pixel_size;
1172 struct ftfont_info *ftfont_info;
1173 struct font *font;
1174 struct ftfont_cache_data *cache_data;
1175 FT_Face ft_face;
1176 FT_Size ft_size;
1177 FT_UInt size;
1178 Lisp_Object val, filename, index, cache, font_object;
1179 int scalable;
1180 int spacing;
1181 char name[256];
1182 int i, len;
1183 int upEM;
1185 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1186 if (! CONSP (val))
1187 return Qnil;
1188 val = XCDR (val);
1189 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1190 if (NILP (cache))
1191 return Qnil;
1192 filename = XCAR (val);
1193 index = XCDR (val);
1194 val = XCDR (cache);
1195 cache_data = XSAVE_VALUE (XCDR (cache))->pointer;
1196 ft_face = cache_data->ft_face;
1197 if (XSAVE_VALUE (val)->integer > 0)
1199 /* FT_Face in this cache is already used by the different size. */
1200 if (FT_New_Size (ft_face, &ft_size) != 0)
1201 return Qnil;
1202 if (FT_Activate_Size (ft_size) != 0)
1204 FT_Done_Size (ft_size);
1205 return Qnil;
1208 XSAVE_VALUE (val)->integer++;
1209 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1210 if (size == 0)
1211 size = pixel_size;
1212 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1214 if (XSAVE_VALUE (val)->integer == 0)
1215 FT_Done_Face (ft_face);
1216 return Qnil;
1219 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
1220 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
1221 len = font_unparse_xlfd (entity, size, name, 256);
1222 if (len > 0)
1223 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
1224 len = font_unparse_fcname (entity, size, name, 256);
1225 if (len > 0)
1226 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
1227 else
1228 ASET (font_object, FONT_FULLNAME_INDEX,
1229 AREF (font_object, FONT_NAME_INDEX));
1230 ASET (font_object, FONT_FILE_INDEX, filename);
1231 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
1232 font = XFONT_OBJECT (font_object);
1233 ftfont_info = (struct ftfont_info *) font;
1234 ftfont_info->ft_size = ft_face->size;
1235 ftfont_info->index = XINT (index);
1236 #ifdef HAVE_LIBOTF
1237 ftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
1238 ftfont_info->otf = NULL;
1239 #endif /* HAVE_LIBOTF */
1240 /* This means that there's no need of transformation. */
1241 ftfont_info->matrix.xx = 0;
1242 font->pixel_size = size;
1243 font->driver = &ftfont_driver;
1244 font->encoding_charset = font->repertory_charset = -1;
1246 upEM = ft_face->units_per_EM;
1247 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1248 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1249 if (scalable)
1251 font->ascent = ft_face->ascender * size / upEM;
1252 font->descent = - ft_face->descender * size / upEM;
1253 font->height = ft_face->height * size / upEM;
1255 else
1257 font->ascent = ft_face->size->metrics.ascender >> 6;
1258 font->descent = - ft_face->size->metrics.descender >> 6;
1259 font->height = ft_face->size->metrics.height >> 6;
1261 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1262 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1263 else
1264 spacing = FC_PROPORTIONAL;
1265 if (spacing != FC_PROPORTIONAL
1266 #ifdef FC_DUAL
1267 && spacing != FC_DUAL
1268 #endif /* FC_DUAL */
1270 font->min_width = font->average_width = font->space_width
1271 = (scalable ? ft_face->max_advance_width * size / upEM
1272 : ft_face->size->metrics.max_advance >> 6);
1273 else
1275 int n;
1277 font->min_width = font->average_width = font->space_width = 0;
1278 for (i = 32, n = 0; i < 127; i++)
1279 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1281 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1283 if (this_width > 0
1284 && (! font->min_width || font->min_width > this_width))
1285 font->min_width = this_width;
1286 if (i == 32)
1287 font->space_width = this_width;
1288 font->average_width += this_width;
1289 n++;
1291 if (n > 0)
1292 font->average_width /= n;
1295 font->baseline_offset = 0;
1296 font->relative_compose = 0;
1297 font->default_ascent = 0;
1298 font->vertical_centering = 0;
1299 if (scalable)
1301 font->underline_position = -ft_face->underline_position * size / upEM;
1302 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1304 else
1306 font->underline_position = -1;
1307 font->underline_thickness = 0;
1310 return font_object;
1313 static void
1314 ftfont_close (f, font)
1315 FRAME_PTR f;
1316 struct font *font;
1318 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1319 Lisp_Object val, cache;
1321 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1322 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1323 xassert (CONSP (cache));
1324 val = XCDR (cache);
1325 (XSAVE_VALUE (val)->integer)--;
1326 if (XSAVE_VALUE (val)->integer == 0)
1328 struct ftfont_cache_data *cache_data = XSAVE_VALUE (val)->pointer;
1330 FT_Done_Face (cache_data->ft_face);
1331 #ifdef HAVE_LIBOTF
1332 if (ftfont_info->otf)
1333 OTF_close (ftfont_info->otf);
1334 #endif
1335 cache_data->ft_face = NULL;
1337 else
1338 FT_Done_Size (ftfont_info->ft_size);
1341 static int
1342 ftfont_has_char (font, c)
1343 Lisp_Object font;
1344 int c;
1346 struct charset *cs = NULL;
1348 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1349 && charset_jisx0208 >= 0)
1350 cs = CHARSET_FROM_ID (charset_jisx0208);
1351 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1352 && charset_ksc5601 >= 0)
1353 cs = CHARSET_FROM_ID (charset_ksc5601);
1354 if (cs)
1355 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1357 if (FONT_ENTITY_P (font))
1359 FcCharSet *charset = ftfont_get_fc_charset (font);
1361 return (FcCharSetHasChar (charset, c) == FcTrue);
1363 else
1365 struct ftfont_info *ftfont_info;
1367 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1368 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1369 != 0);
1373 static unsigned
1374 ftfont_encode_char (font, c)
1375 struct font *font;
1376 int c;
1378 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1379 FT_Face ft_face = ftfont_info->ft_size->face;
1380 FT_ULong charcode = c;
1381 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1383 return (code > 0 ? code : FONT_INVALID_CODE);
1386 static int
1387 ftfont_text_extents (font, code, nglyphs, metrics)
1388 struct font *font;
1389 unsigned *code;
1390 int nglyphs;
1391 struct font_metrics *metrics;
1393 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1394 FT_Face ft_face = ftfont_info->ft_size->face;
1395 int width = 0;
1396 int i, first;
1398 if (ftfont_info->ft_size != ft_face->size)
1399 FT_Activate_Size (ftfont_info->ft_size);
1400 if (metrics)
1401 bzero (metrics, sizeof (struct font_metrics));
1402 for (i = 0, first = 1; i < nglyphs; i++)
1404 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1406 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1408 if (first)
1410 if (metrics)
1412 metrics->lbearing = m->horiBearingX >> 6;
1413 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1414 metrics->ascent = m->horiBearingY >> 6;
1415 metrics->descent = (m->height - m->horiBearingY) >> 6;
1417 first = 0;
1419 if (metrics)
1421 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1422 metrics->lbearing = width + (m->horiBearingX >> 6);
1423 if (metrics->rbearing
1424 < width + ((m->horiBearingX + m->width) >> 6))
1425 metrics->rbearing
1426 = width + ((m->horiBearingX + m->width) >> 6);
1427 if (metrics->ascent < (m->horiBearingY >> 6))
1428 metrics->ascent = m->horiBearingY >> 6;
1429 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1430 metrics->descent = (m->height - m->horiBearingY) >> 6;
1432 width += m->horiAdvance >> 6;
1434 else
1436 width += font->space_width;
1439 if (metrics)
1440 metrics->width = width;
1442 return width;
1445 static int
1446 ftfont_get_bitmap (font, code, bitmap, bits_per_pixel)
1447 struct font *font;
1448 unsigned code;
1449 struct font_bitmap *bitmap;
1450 int bits_per_pixel;
1452 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1453 FT_Face ft_face = ftfont_info->ft_size->face;
1454 FT_Int32 load_flags = FT_LOAD_RENDER;
1456 if (ftfont_info->ft_size != ft_face->size)
1457 FT_Activate_Size (ftfont_info->ft_size);
1458 if (bits_per_pixel == 1)
1460 #ifdef FT_LOAD_TARGET_MONO
1461 load_flags |= FT_LOAD_TARGET_MONO;
1462 #else
1463 load_flags |= FT_LOAD_MONOCHROME;
1464 #endif
1466 else if (bits_per_pixel != 8)
1467 /* We don't support such a rendering. */
1468 return -1;
1470 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1471 return -1;
1472 bitmap->bits_per_pixel
1473 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1474 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1475 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1476 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1477 : -1);
1478 if (bitmap->bits_per_pixel < 0)
1479 /* We don't suport that kind of pixel mode. */
1480 return -1;
1481 bitmap->rows = ft_face->glyph->bitmap.rows;
1482 bitmap->width = ft_face->glyph->bitmap.width;
1483 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1484 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1485 bitmap->left = ft_face->glyph->bitmap_left;
1486 bitmap->top = ft_face->glyph->bitmap_top;
1487 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1488 bitmap->extra = NULL;
1490 return 0;
1493 static int
1494 ftfont_anchor_point (font, code, index, x, y)
1495 struct font *font;
1496 unsigned code;
1497 int index;
1498 int *x, *y;
1500 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1501 FT_Face ft_face = ftfont_info->ft_size->face;
1503 if (ftfont_info->ft_size != ft_face->size)
1504 FT_Activate_Size (ftfont_info->ft_size);
1505 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1506 return -1;
1507 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1508 return -1;
1509 if (index >= ft_face->glyph->outline.n_points)
1510 return -1;
1511 *x = ft_face->glyph->outline.points[index].x;
1512 *y = ft_face->glyph->outline.points[index].y;
1513 return 0;
1516 #ifdef HAVE_LIBOTF
1518 static Lisp_Object
1519 ftfont_otf_features (gsub_gpos)
1520 OTF_GSUB_GPOS *gsub_gpos;
1522 Lisp_Object scripts, langsyses, features, sym;
1523 int i, j, k, l;
1525 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1527 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1529 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1531 OTF_LangSys *otf_langsys;
1533 if (j >= 0)
1534 otf_langsys = otf_script->LangSys + j;
1535 else if (otf_script->DefaultLangSysOffset)
1536 otf_langsys = &otf_script->DefaultLangSys;
1537 else
1538 break;
1540 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1542 l = otf_langsys->FeatureIndex[k];
1543 if (l >= gsub_gpos->FeatureList.FeatureCount)
1544 continue;
1545 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1546 features = Fcons (sym, features);
1548 if (j >= 0)
1549 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1550 else
1551 sym = Qnil;
1552 langsyses = Fcons (Fcons (sym, features), langsyses);
1555 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1556 scripts = Fcons (Fcons (sym, langsyses), scripts);
1558 return scripts;
1563 static Lisp_Object
1564 ftfont_otf_capability (font)
1565 struct font *font;
1567 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1568 OTF *otf = ftfont_get_otf (ftfont_info);
1569 Lisp_Object gsub_gpos;
1571 if (! otf)
1572 return Qnil;
1573 gsub_gpos = Fcons (Qnil, Qnil);
1574 if (OTF_get_table (otf, "GSUB") == 0
1575 && otf->gsub->FeatureList.FeatureCount > 0)
1576 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1577 if (OTF_get_table (otf, "GPOS") == 0
1578 && otf->gpos->FeatureList.FeatureCount > 0)
1579 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1580 return gsub_gpos;
1583 #ifdef HAVE_M17N_FLT
1585 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1586 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1587 /* We can use the new feature of libotf and m17n-flt to handle the
1588 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1589 some Agian scripts. */
1590 #define M17N_FLT_USE_NEW_FEATURE
1591 #endif
1593 struct MFLTFontFT
1595 MFLTFont flt_font;
1596 struct font *font;
1597 FT_Face ft_face;
1598 OTF *otf;
1599 FT_Matrix *matrix;
1602 static int
1603 ftfont_get_glyph_id (font, gstring, from, to)
1604 MFLTFont *font;
1605 MFLTGlyphString *gstring;
1606 int from, to;
1608 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1609 FT_Face ft_face = flt_font_ft->ft_face;
1610 MFLTGlyph *g;
1612 for (g = gstring->glyphs + from; from < to; g++, from++)
1613 if (! g->encoded)
1615 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1617 g->code = code > 0 ? code : FONT_INVALID_CODE;
1618 g->encoded = 1;
1620 return 0;
1623 /* Operators for 26.6 fixed fractional pixel format */
1625 #define FLOOR(x) ((x) & -64)
1626 #define CEIL(x) (((x)+63) & -64)
1627 #define ROUND(x) (((x)+32) & -64)
1629 static int
1630 ftfont_get_metrics (font, gstring, from, to)
1631 MFLTFont *font;
1632 MFLTGlyphString *gstring;
1633 int from, to;
1635 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1636 FT_Face ft_face = flt_font_ft->ft_face;
1637 MFLTGlyph *g;
1639 for (g = gstring->glyphs + from; from < to; g++, from++)
1640 if (! g->measured)
1642 if (g->code != FONT_INVALID_CODE)
1644 FT_Glyph_Metrics *m;
1645 int lbearing, rbearing, ascent, descent, xadv;
1647 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1648 abort ();
1649 m = &ft_face->glyph->metrics;
1650 if (flt_font_ft->matrix)
1652 FT_Vector v[4];
1653 int i;
1655 v[0].x = v[1].x = m->horiBearingX;
1656 v[2].x = v[3].x = m->horiBearingX + m->width;
1657 v[0].y = v[2].y = m->horiBearingY;
1658 v[1].y = v[3].y = m->horiBearingY - m->height;
1659 for (i = 0; i < 4; i++)
1660 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1661 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1662 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1663 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1664 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1666 else
1668 g->lbearing = FLOOR (m->horiBearingX);
1669 g->rbearing = CEIL (m->horiBearingX + m->width);
1670 g->ascent = CEIL (m->horiBearingY);
1671 g->descent = - FLOOR (m->horiBearingY - m->height);
1673 g->xadv = ROUND (ft_face->glyph->advance.x);
1675 else
1677 g->lbearing = 0;
1678 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1679 g->ascent = flt_font_ft->font->ascent << 6;
1680 g->descent = flt_font_ft->font->descent << 6;
1682 g->yadv = 0;
1683 g->measured = 1;
1685 return 0;
1688 static int
1689 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1691 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1692 OTF *otf = flt_font_ft->otf;
1693 OTF_Tag *tags;
1694 int i, n, negative;
1696 for (i = 0; i < 2; i++)
1698 if (! spec->features[i])
1699 continue;
1700 for (n = 0; spec->features[i][n]; n++);
1701 tags = alloca (sizeof (OTF_Tag) * n);
1702 for (n = 0, negative = 0; spec->features[i][n]; n++)
1704 if (spec->features[i][n] == 0xFFFFFFFF)
1705 negative = 1;
1706 else if (negative)
1707 tags[n - 1] = spec->features[i][n] | 0x80000000;
1708 else
1709 tags[n] = spec->features[i][n];
1711 #ifdef M17N_FLT_USE_NEW_FEATURE
1712 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1713 tags, n - negative) != 1)
1714 return 0;
1715 #else /* not M17N_FLT_USE_NEW_FEATURE */
1716 if (n - negative > 0
1717 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1718 tags, n - negative) != 1)
1719 return 0;
1720 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1722 return 1;
1725 #define DEVICE_DELTA(table, size) \
1726 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1727 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1728 : 0)
1730 static void
1731 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1732 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1734 if (anchor->AnchorFormat == 2)
1736 FT_Outline *outline;
1737 int ap = anchor->f.f1.AnchorPoint;
1739 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1740 outline = &ft_face->glyph->outline;
1741 if (ap < outline->n_points)
1743 *x = outline->points[ap].x << 6;
1744 *y = outline->points[ap].y << 6;
1747 else if (anchor->AnchorFormat == 3)
1749 if (anchor->f.f2.XDeviceTable.offset
1750 && anchor->f.f2.XDeviceTable.DeltaValue)
1751 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1752 if (anchor->f.f2.YDeviceTable.offset
1753 && anchor->f.f2.YDeviceTable.DeltaValue)
1754 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1758 static OTF_GlyphString otf_gstring;
1760 static void
1761 setup_otf_gstring (int size)
1763 if (otf_gstring.size == 0)
1765 otf_gstring.glyphs = (OTF_Glyph *) xmalloc (sizeof (OTF_Glyph) * size);
1766 otf_gstring.size = size;
1768 else if (otf_gstring.size < size)
1770 otf_gstring.glyphs = xrealloc (otf_gstring.glyphs,
1771 sizeof (OTF_Glyph) * size);
1772 otf_gstring.size = size;
1774 otf_gstring.used = size;
1775 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1778 #ifdef M17N_FLT_USE_NEW_FEATURE
1780 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1781 #define PACK_OTF_TAG(TAG) \
1782 ((((TAG) & 0x7F000000) >> 3) \
1783 | (((TAG) & 0x7F0000) >> 2) \
1784 | (((TAG) & 0x7F00) >> 1) \
1785 | ((TAG) & 0x7F))
1787 /* Assuming that FONT is an OpenType font, apply OpenType features
1788 specified in SPEC on glyphs between FROM and TO of IN, and record
1789 the lastly applied feature in each glyph of IN. If OUT is not
1790 NULL, append the resulting glyphs to OUT while storing glyph
1791 position adjustment information in ADJUSTMENT. */
1793 static int
1794 ftfont_drive_otf (font, spec, in, from, to, out, adjustment)
1795 MFLTFont *font;
1796 MFLTOtfSpec *spec;
1797 MFLTGlyphString *in;
1798 int from, to;
1799 MFLTGlyphString *out;
1800 MFLTGlyphAdjustment *adjustment;
1802 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1803 FT_Face ft_face = flt_font_ft->ft_face;
1804 OTF *otf = flt_font_ft->otf;
1805 int len = to - from;
1806 int i, j, gidx;
1807 OTF_Glyph *otfg;
1808 char script[5], *langsys = NULL;
1809 char *gsub_features = NULL, *gpos_features = NULL;
1810 OTF_Feature *features;
1812 if (len == 0)
1813 return from;
1814 OTF_tag_name (spec->script, script);
1815 if (spec->langsys)
1817 langsys = alloca (5);
1818 OTF_tag_name (spec->langsys, langsys);
1820 for (i = 0; i < 2; i++)
1822 char *p;
1824 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1826 for (j = 0; spec->features[i][j]; j++);
1827 if (i == 0)
1828 p = gsub_features = alloca (6 * j);
1829 else
1830 p = gpos_features = alloca (6 * j);
1831 for (j = 0; spec->features[i][j]; j++)
1833 if (spec->features[i][j] == 0xFFFFFFFF)
1834 *p++ = '*', *p++ = ',';
1835 else
1837 OTF_tag_name (spec->features[i][j], p);
1838 p[4] = ',';
1839 p += 5;
1842 *--p = '\0';
1846 setup_otf_gstring (len);
1847 for (i = 0; i < len; i++)
1849 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
1850 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1853 OTF_drive_gdef (otf, &otf_gstring);
1854 gidx = out ? out->used : from;
1856 if (gsub_features && out)
1858 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1859 gsub_features) < 0)
1860 goto simple_copy;
1861 if (out->allocated < out->used + otf_gstring.used)
1862 return -2;
1863 features = otf->gsub->FeatureList.Feature;
1864 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1866 MFLTGlyph *g;
1867 int min_from, max_to;
1868 int j;
1869 int feature_idx = otfg->positioning_type >> 4;
1871 g = out->glyphs + out->used;
1872 *g = in->glyphs[from + otfg->f.index.from];
1873 if (g->code != otfg->glyph_id)
1875 g->c = 0;
1876 g->code = otfg->glyph_id;
1877 g->measured = 0;
1879 out->used++;
1880 min_from = g->from;
1881 max_to = g->to;
1882 if (otfg->f.index.from < otfg->f.index.to)
1884 /* OTFG substitutes multiple glyphs in IN. */
1885 for (j = from + otfg->f.index.from + 1;
1886 j <= from + otfg->f.index.to; j++)
1888 if (min_from > in->glyphs[j].from)
1889 min_from = in->glyphs[j].from;
1890 if (max_to < in->glyphs[j].to)
1891 max_to = in->glyphs[j].to;
1893 g->from = min_from;
1894 g->to = max_to;
1896 if (feature_idx)
1898 unsigned int tag = features[feature_idx - 1].FeatureTag;
1899 tag = PACK_OTF_TAG (tag);
1900 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1902 for (i++, otfg++; (i < otf_gstring.used
1903 && otfg->f.index.from == otfg[-1].f.index.from);
1904 i++, otfg++)
1906 g = out->glyphs + out->used;
1907 *g = in->glyphs[from + otfg->f.index.to];
1908 if (g->code != otfg->glyph_id)
1910 g->c = 0;
1911 g->code = otfg->glyph_id;
1912 g->measured = 0;
1914 feature_idx = otfg->positioning_type >> 4;
1915 if (feature_idx)
1917 unsigned int tag = features[feature_idx - 1].FeatureTag;
1918 tag = PACK_OTF_TAG (tag);
1919 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1921 out->used++;
1925 else if (gsub_features)
1927 /* Just for checking which features will be applied. */
1928 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1929 gsub_features) < 0)
1930 goto simple_copy;
1931 features = otf->gsub->FeatureList.Feature;
1932 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1933 otfg++)
1935 int feature_idx = otfg->positioning_type >> 4;
1937 if (feature_idx)
1939 unsigned int tag = features[feature_idx - 1].FeatureTag;
1940 tag = PACK_OTF_TAG (tag);
1941 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1943 MFLTGlyph *g = in->glyphs + (from + j);
1944 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1949 else if (out)
1951 if (out->allocated < out->used + len)
1952 return -2;
1953 for (i = 0; i < len; i++)
1954 out->glyphs[out->used++] = in->glyphs[from + i];
1957 if (gpos_features && out)
1959 MFLTGlyph *base = NULL, *mark = NULL, *g;
1960 int x_ppem, y_ppem, x_scale, y_scale;
1962 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1963 gpos_features) < 0)
1964 return to;
1965 features = otf->gpos->FeatureList.Feature;
1966 x_ppem = ft_face->size->metrics.x_ppem;
1967 y_ppem = ft_face->size->metrics.y_ppem;
1968 x_scale = ft_face->size->metrics.x_scale;
1969 y_scale = ft_face->size->metrics.y_scale;
1971 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1972 i < otf_gstring.used; i++, otfg++, g++)
1974 MFLTGlyph *prev;
1975 int feature_idx = otfg->positioning_type >> 4;
1977 if (feature_idx)
1979 unsigned int tag = features[feature_idx - 1].FeatureTag;
1980 tag = PACK_OTF_TAG (tag);
1981 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1984 if (! otfg->glyph_id)
1985 continue;
1986 switch (otfg->positioning_type & 0xF)
1988 case 0:
1989 break;
1990 case 1: /* Single */
1991 case 2: /* Pair */
1993 int format = otfg->f.f1.format;
1995 if (format & OTF_XPlacement)
1996 adjustment[i].xoff
1997 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
1998 if (format & OTF_XPlaDevice)
1999 adjustment[i].xoff
2000 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2001 if (format & OTF_YPlacement)
2002 adjustment[i].yoff
2003 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2004 if (format & OTF_YPlaDevice)
2005 adjustment[i].yoff
2006 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2007 if (format & OTF_XAdvance)
2008 adjustment[i].xadv
2009 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2010 if (format & OTF_XAdvDevice)
2011 adjustment[i].xadv
2012 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2013 if (format & OTF_YAdvance)
2014 adjustment[i].yadv
2015 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2016 if (format & OTF_YAdvDevice)
2017 adjustment[i].yadv
2018 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2019 adjustment[i].set = 1;
2021 break;
2022 case 3: /* Cursive */
2023 /* Not yet supported. */
2024 break;
2025 case 4: /* Mark-to-Base */
2026 case 5: /* Mark-to-Ligature */
2027 if (! base)
2028 break;
2029 prev = base;
2030 goto label_adjust_anchor;
2031 default: /* i.e. case 6 Mark-to-Mark */
2032 if (! mark)
2033 break;
2034 prev = mark;
2036 label_adjust_anchor:
2038 int base_x, base_y, mark_x, mark_y;
2039 int this_from, this_to;
2041 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2042 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2043 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2044 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2046 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2047 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2048 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2049 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2050 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2051 x_ppem, y_ppem, &mark_x, &mark_y);
2052 adjustment[i].xoff = (base_x - mark_x);
2053 adjustment[i].yoff = - (base_y - mark_y);
2054 adjustment[i].back = (g - prev);
2055 adjustment[i].xadv = 0;
2056 adjustment[i].advance_is_absolute = 1;
2057 adjustment[i].set = 1;
2058 this_from = g->from;
2059 this_to = g->to;
2060 for (j = 0; prev + j < g; j++)
2062 if (this_from > prev[j].from)
2063 this_from = prev[j].from;
2064 if (this_to < prev[j].to)
2065 this_to = prev[j].to;
2067 for (; prev <= g; prev++)
2069 prev->from = this_from;
2070 prev->to = this_to;
2074 if (otfg->GlyphClass == OTF_GlyphClass0)
2075 base = mark = g;
2076 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2077 mark = g;
2078 else
2079 base = g;
2082 else if (gpos_features)
2084 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2085 gpos_features) < 0)
2086 return to;
2087 features = otf->gpos->FeatureList.Feature;
2088 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2089 i++, otfg++)
2090 if (otfg->positioning_type & 0xF)
2092 int feature_idx = otfg->positioning_type >> 4;
2094 if (feature_idx)
2096 unsigned int tag = features[feature_idx - 1].FeatureTag;
2097 tag = PACK_OTF_TAG (tag);
2098 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2100 MFLTGlyph *g = in->glyphs + (from + j);
2101 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2106 return to;
2108 simple_copy:
2109 if (! out)
2110 return to;
2111 if (out->allocated < out->used + len)
2112 return -2;
2113 font->get_metrics (font, in, from, to);
2114 memcpy (out->glyphs + out->used, in->glyphs + from,
2115 sizeof (MFLTGlyph) * len);
2116 out->used += len;
2117 return to;
2120 static int
2121 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2122 MFLTGlyphString *in, int from, int to)
2124 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2127 #else /* not M17N_FLT_USE_NEW_FEATURE */
2129 static int
2130 ftfont_drive_otf (font, spec, in, from, to, out, adjustment)
2131 MFLTFont *font;
2132 MFLTOtfSpec *spec;
2133 MFLTGlyphString *in;
2134 int from, to;
2135 MFLTGlyphString *out;
2136 MFLTGlyphAdjustment *adjustment;
2138 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2139 FT_Face ft_face = flt_font_ft->ft_face;
2140 OTF *otf = flt_font_ft->otf;
2141 int len = to - from;
2142 int i, j, gidx;
2143 OTF_Glyph *otfg;
2144 char script[5], *langsys = NULL;
2145 char *gsub_features = NULL, *gpos_features = NULL;
2147 if (len == 0)
2148 return from;
2149 OTF_tag_name (spec->script, script);
2150 if (spec->langsys)
2152 langsys = alloca (5);
2153 OTF_tag_name (spec->langsys, langsys);
2155 for (i = 0; i < 2; i++)
2157 char *p;
2159 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2161 for (j = 0; spec->features[i][j]; j++);
2162 if (i == 0)
2163 p = gsub_features = alloca (6 * j);
2164 else
2165 p = gpos_features = alloca (6 * j);
2166 for (j = 0; spec->features[i][j]; j++)
2168 if (spec->features[i][j] == 0xFFFFFFFF)
2169 *p++ = '*', *p++ = ',';
2170 else
2172 OTF_tag_name (spec->features[i][j], p);
2173 p[4] = ',';
2174 p += 5;
2177 *--p = '\0';
2181 setup_otf_gstring (len);
2182 for (i = 0; i < len; i++)
2184 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2185 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2188 OTF_drive_gdef (otf, &otf_gstring);
2189 gidx = out->used;
2191 if (gsub_features)
2193 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2194 < 0)
2195 goto simple_copy;
2196 if (out->allocated < out->used + otf_gstring.used)
2197 return -2;
2198 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2200 MFLTGlyph *g;
2201 int min_from, max_to;
2202 int j;
2204 g = out->glyphs + out->used;
2205 *g = in->glyphs[from + otfg->f.index.from];
2206 if (g->code != otfg->glyph_id)
2208 g->c = 0;
2209 g->code = otfg->glyph_id;
2210 g->measured = 0;
2212 out->used++;
2213 min_from = g->from;
2214 max_to = g->to;
2215 if (otfg->f.index.from < otfg->f.index.to)
2217 /* OTFG substitutes multiple glyphs in IN. */
2218 for (j = from + otfg->f.index.from + 1;
2219 j <= from + otfg->f.index.to; j++)
2221 if (min_from > in->glyphs[j].from)
2222 min_from = in->glyphs[j].from;
2223 if (max_to < in->glyphs[j].to)
2224 max_to = in->glyphs[j].to;
2226 g->from = min_from;
2227 g->to = max_to;
2229 for (i++, otfg++; (i < otf_gstring.used
2230 && otfg->f.index.from == otfg[-1].f.index.from);
2231 i++, otfg++)
2233 g = out->glyphs + out->used;
2234 *g = in->glyphs[from + otfg->f.index.to];
2235 if (g->code != otfg->glyph_id)
2237 g->c = 0;
2238 g->code = otfg->glyph_id;
2239 g->measured = 0;
2241 out->used++;
2245 else
2247 if (out->allocated < out->used + len)
2248 return -2;
2249 for (i = 0; i < len; i++)
2250 out->glyphs[out->used++] = in->glyphs[from + i];
2253 if (gpos_features)
2255 MFLTGlyph *base = NULL, *mark = NULL, *g;
2256 int x_ppem, y_ppem, x_scale, y_scale;
2258 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2259 < 0)
2260 return to;
2262 x_ppem = ft_face->size->metrics.x_ppem;
2263 y_ppem = ft_face->size->metrics.y_ppem;
2264 x_scale = ft_face->size->metrics.x_scale;
2265 y_scale = ft_face->size->metrics.y_scale;
2267 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2268 i < otf_gstring.used; i++, otfg++, g++)
2270 MFLTGlyph *prev;
2272 if (! otfg->glyph_id)
2273 continue;
2274 switch (otfg->positioning_type)
2276 case 0:
2277 break;
2278 case 1: /* Single */
2279 case 2: /* Pair */
2281 int format = otfg->f.f1.format;
2283 if (format & OTF_XPlacement)
2284 adjustment[i].xoff
2285 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2286 if (format & OTF_XPlaDevice)
2287 adjustment[i].xoff
2288 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2289 if (format & OTF_YPlacement)
2290 adjustment[i].yoff
2291 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2292 if (format & OTF_YPlaDevice)
2293 adjustment[i].yoff
2294 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2295 if (format & OTF_XAdvance)
2296 adjustment[i].xadv
2297 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2298 if (format & OTF_XAdvDevice)
2299 adjustment[i].xadv
2300 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2301 if (format & OTF_YAdvance)
2302 adjustment[i].yadv
2303 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2304 if (format & OTF_YAdvDevice)
2305 adjustment[i].yadv
2306 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2307 adjustment[i].set = 1;
2309 break;
2310 case 3: /* Cursive */
2311 /* Not yet supported. */
2312 break;
2313 case 4: /* Mark-to-Base */
2314 case 5: /* Mark-to-Ligature */
2315 if (! base)
2316 break;
2317 prev = base;
2318 goto label_adjust_anchor;
2319 default: /* i.e. case 6 Mark-to-Mark */
2320 if (! mark)
2321 break;
2322 prev = mark;
2324 label_adjust_anchor:
2326 int base_x, base_y, mark_x, mark_y;
2327 int this_from, this_to;
2329 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2330 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2331 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2332 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2334 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2335 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2336 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2337 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2338 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2339 x_ppem, y_ppem, &mark_x, &mark_y);
2340 adjustment[i].xoff = (base_x - mark_x);
2341 adjustment[i].yoff = - (base_y - mark_y);
2342 adjustment[i].back = (g - prev);
2343 adjustment[i].xadv = 0;
2344 adjustment[i].advance_is_absolute = 1;
2345 adjustment[i].set = 1;
2346 this_from = g->from;
2347 this_to = g->to;
2348 for (j = 0; prev + j < g; j++)
2350 if (this_from > prev[j].from)
2351 this_from = prev[j].from;
2352 if (this_to < prev[j].to)
2353 this_to = prev[j].to;
2355 for (; prev <= g; prev++)
2357 prev->from = this_from;
2358 prev->to = this_to;
2362 if (otfg->GlyphClass == OTF_GlyphClass0)
2363 base = mark = g;
2364 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2365 mark = g;
2366 else
2367 base = g;
2370 return to;
2372 simple_copy:
2373 if (out->allocated < out->used + len)
2374 return -2;
2375 font->get_metrics (font, in, from, to);
2376 memcpy (out->glyphs + out->used, in->glyphs + from,
2377 sizeof (MFLTGlyph) * len);
2378 out->used += len;
2379 return to;
2382 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2384 static MFLTGlyphString gstring;
2386 static int m17n_flt_initialized;
2388 extern Lisp_Object QCfamily;
2390 static Lisp_Object
2391 ftfont_shape_by_flt (lgstring, font, ft_face, otf, matrix)
2392 Lisp_Object lgstring;
2393 struct font *font;
2394 FT_Face ft_face;
2395 OTF *otf;
2396 FT_Matrix *matrix;
2398 EMACS_UINT len = LGSTRING_GLYPH_LEN (lgstring);
2399 EMACS_UINT i;
2400 struct MFLTFontFT flt_font_ft;
2401 MFLT *flt = NULL;
2402 int with_variation_selector = 0;
2404 if (! m17n_flt_initialized)
2406 M17N_INIT ();
2407 #ifdef M17N_FLT_USE_NEW_FEATURE
2408 mflt_enable_new_feature = 1;
2409 mflt_try_otf = ftfont_try_otf;
2410 #endif /* M17N_FLT_USE_NEW_FEATURE */
2411 m17n_flt_initialized = 1;
2414 for (i = 0; i < len; i++)
2416 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2417 int c;
2419 if (NILP (g))
2420 break;
2421 c = LGLYPH_CHAR (g);
2422 if (CHAR_VARIATION_SELECTOR_P (c))
2423 with_variation_selector++;
2425 len = i;
2426 if (with_variation_selector)
2428 setup_otf_gstring (len);
2429 for (i = 0; i < len; i++)
2431 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2433 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2434 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2435 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2437 OTF_drive_cmap (otf, &otf_gstring);
2438 for (i = 0; i < otf_gstring.used; i++)
2440 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2441 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2442 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2444 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2445 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2446 LGSTRING_SET_GLYPH (lgstring, i, g0);
2448 if (len > otf_gstring.used)
2450 len = otf_gstring.used;
2451 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2455 if (gstring.allocated == 0)
2457 gstring.allocated = len * 2;
2458 gstring.glyph_size = sizeof (MFLTGlyph);
2459 gstring.glyphs = xmalloc (sizeof (MFLTGlyph) * gstring.allocated);
2461 else if (gstring.allocated < len * 2)
2463 gstring.allocated = len * 2;
2464 gstring.glyphs = xrealloc (gstring.glyphs,
2465 sizeof (MFLTGlyph) * gstring.allocated);
2467 memset (gstring.glyphs, 0, sizeof (MFLTGlyph) * len);
2468 for (i = 0; i < len; i++)
2470 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2472 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2473 if (with_variation_selector)
2475 gstring.glyphs[i].code = LGLYPH_CODE (g);
2476 gstring.glyphs[i].encoded = 1;
2480 gstring.used = len;
2481 gstring.r2l = 0;
2484 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2486 if (NILP (family))
2487 flt_font_ft.flt_font.family = Mnil;
2488 else
2489 flt_font_ft.flt_font.family
2490 = msymbol ((char *) SDATA (Fdowncase (SYMBOL_NAME (family))));
2492 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2493 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2494 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2495 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2496 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2497 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2498 flt_font_ft.flt_font.internal = NULL;
2499 flt_font_ft.font = font;
2500 flt_font_ft.ft_face = ft_face;
2501 flt_font_ft.otf = otf;
2502 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2503 if (len > 1
2504 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2505 /* A little bit ad hoc. Perhaps, shaper must get script and
2506 language information, and select a proper flt for them
2507 here. */
2508 flt = mflt_get (msymbol ("combining"));
2509 for (i = 0; i < 3; i++)
2511 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2512 if (result != -2)
2513 break;
2514 gstring.allocated += gstring.allocated;
2515 gstring.glyphs = xrealloc (gstring.glyphs,
2516 sizeof (MFLTGlyph) * gstring.allocated);
2518 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2519 return Qnil;
2520 for (i = 0; i < gstring.used; i++)
2522 MFLTGlyph *g = gstring.glyphs + i;
2524 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2525 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2528 for (i = 0; i < gstring.used; i++)
2530 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2531 MFLTGlyph *g = gstring.glyphs + i;
2533 if (NILP (lglyph))
2535 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2536 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2538 LGLYPH_SET_FROM (lglyph, g->from);
2539 LGLYPH_SET_TO (lglyph, g->to);
2540 LGLYPH_SET_CHAR (lglyph, g->c);
2541 LGLYPH_SET_CODE (lglyph, g->code);
2542 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2543 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2544 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2545 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2546 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2547 if (g->adjusted)
2549 Lisp_Object vec;
2551 vec = Fmake_vector (make_number (3), Qnil);
2552 ASET (vec, 0, make_number (g->xoff >> 6));
2553 ASET (vec, 1, make_number (g->yoff >> 6));
2554 ASET (vec, 2, make_number (g->xadv >> 6));
2555 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2558 return make_number (i);
2561 Lisp_Object
2562 ftfont_shape (lgstring)
2563 Lisp_Object lgstring;
2565 struct font *font;
2566 struct ftfont_info *ftfont_info;
2567 OTF *otf;
2569 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2570 ftfont_info = (struct ftfont_info *) font;
2571 otf = ftfont_get_otf (ftfont_info);
2572 if (! otf)
2573 return make_number (0);
2574 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2575 &ftfont_info->matrix);
2578 #endif /* HAVE_M17N_FLT */
2580 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2582 static int
2583 ftfont_variation_glyphs (font, c, variations)
2584 struct font *font;
2585 int c;
2586 unsigned variations[256];
2588 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2589 OTF *otf = ftfont_get_otf (ftfont_info);
2591 if (! otf)
2592 return 0;
2593 return OTF_get_variation_glyphs (otf, c, variations);
2596 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2597 #endif /* HAVE_LIBOTF */
2599 Lisp_Object
2600 ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
2602 FcChar8 *str;
2604 #ifdef FC_FONTFORMAT
2605 if (pattern)
2607 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2608 return Qnil;
2609 if (strcmp ((char *) str, "TrueType") == 0)
2610 return intern ("truetype");
2611 if (strcmp ((char *) str, "Type 1") == 0)
2612 return intern ("type1");
2613 if (strcmp ((char *) str, "PCF") == 0)
2614 return intern ("pcf");
2615 if (strcmp ((char *) str, "BDF") == 0)
2616 return intern ("bdf");
2618 #endif /* FC_FONTFORMAT */
2619 if (STRINGP (filename))
2621 int len = SBYTES (filename);
2623 if (len >= 4)
2625 str = (FcChar8 *) (SDATA (filename) + len - 4);
2626 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2627 return intern ("truetype");
2628 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2629 return intern ("type1");
2630 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2631 return intern ("pcf");
2632 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2633 return intern ("bdf");
2636 return intern ("unknown");
2639 static const char *ftfont_booleans [] = {
2640 ":antialias",
2641 ":hinting",
2642 ":verticallayout",
2643 ":autohint",
2644 ":globaladvance",
2645 ":outline",
2646 ":scalable",
2647 ":minspace",
2648 ":embolden",
2649 NULL,
2652 static const char *ftfont_non_booleans [] = {
2653 ":family",
2654 ":familylang",
2655 ":style",
2656 ":stylelang",
2657 ":fullname",
2658 ":fullnamelang",
2659 ":slant",
2660 ":weight",
2661 ":size",
2662 ":width",
2663 ":aspect",
2664 ":pixelsize",
2665 ":spacing",
2666 ":foundry",
2667 ":hintstyle",
2668 ":file",
2669 ":index",
2670 ":ftface",
2671 ":rasterizer",
2672 ":scale",
2673 ":dpi",
2674 ":rgba",
2675 ":lcdfilter",
2676 ":charset",
2677 ":lang",
2678 ":fontversion",
2679 ":capability",
2680 NULL,
2683 static void
2684 ftfont_filter_properties (font, alist)
2685 Lisp_Object font;
2686 Lisp_Object alist;
2688 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2692 void
2693 syms_of_ftfont ()
2695 DEFSYM (Qfreetype, "freetype");
2696 DEFSYM (Qmonospace, "monospace");
2697 DEFSYM (Qsans_serif, "sans-serif");
2698 DEFSYM (Qserif, "serif");
2699 DEFSYM (Qmono, "mono");
2700 DEFSYM (Qsans, "sans");
2701 DEFSYM (Qsans__serif, "sans serif");
2703 staticpro (&freetype_font_cache);
2704 freetype_font_cache = Fcons (Qt, Qnil);
2706 staticpro (&ftfont_generic_family_list);
2707 ftfont_generic_family_list
2708 = Fcons (Fcons (Qmonospace, Qt),
2709 Fcons (Fcons (Qsans_serif, Qt),
2710 Fcons (Fcons (Qsans, Qt), Qnil)));
2712 staticpro (&ft_face_cache);
2713 ft_face_cache = Qnil;
2715 ftfont_driver.type = Qfreetype;
2716 register_font_driver (&ftfont_driver, NULL);
2719 /* arch-tag: 7cfa432c-33a6-4988-83d2-a82ed8604aca
2720 (do not change this comment) */