Make epa-file progress message user-friendly.
[emacs.git] / src / ftfont.c
blob5c98073057c6eb6cc22a577c94eab4394427ab72
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-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 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 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
168 return Qnil;
169 str = (char *) fcstr;
170 for (end = str; *end && *end != ' '; end++);
171 if (*end)
173 char *newstr = alloca (end - str + 1);
174 memcpy (newstr, str, end - str);
175 newstr[end - str] = '\0';
176 end = newstr + (end - str);
177 str = newstr;
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 (FcPattern *p, Lisp_Object extra)
193 Lisp_Object key, cache, entity;
194 FcChar8 *str;
195 char *file;
196 int idx;
197 int numeric;
198 double dbl;
199 FcBool b;
201 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
202 return Qnil;
203 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
204 return Qnil;
206 file = (char *) str;
207 key = Fcons (make_unibyte_string (file, strlen (file)), make_number (idx));
208 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
209 entity = XCAR (cache);
210 if (! NILP (entity))
212 Lisp_Object val = font_make_entity ();
213 int i;
215 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
216 ASET (val, i, AREF (entity, i));
218 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
219 font_put_extra (val, QCfont_entity, key);
221 return val;
223 entity = font_make_entity ();
224 XSETCAR (cache, entity);
226 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
227 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
229 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
231 char *s = (char *) str;
232 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
234 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
236 char *s = (char *) str;
237 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
239 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
241 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
242 numeric = FC_WEIGHT_MEDIUM;
243 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
245 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
247 numeric += 100;
248 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
250 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
252 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
254 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
256 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
258 else
259 ASET (entity, FONT_SIZE_INDEX, make_number (0));
260 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
261 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
262 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
264 int dpi = dbl;
265 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
267 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
268 && b == FcTrue)
270 ASET (entity, FONT_SIZE_INDEX, make_number (0));
271 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
273 else
275 /* As this font is not scalable, parhaps this is a BDF or PCF
276 font. */
277 FT_Face ft_face;
279 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
280 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
281 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
283 BDF_PropertyRec rec;
285 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
286 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
287 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
288 FT_Done_Face (ft_face);
292 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
293 font_put_extra (entity, QCfont_entity, key);
294 return entity;
298 static Lisp_Object ftfont_generic_family_list;
300 static Lisp_Object
301 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
303 Lisp_Object slot;
304 FcPattern *match;
305 FcResult result;
306 FcLangSet *langset;
308 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
309 if (EQ (family, Qmono))
310 family = Qmonospace;
311 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
312 family = Qsans_serif;
313 slot = assq_no_quit (family, ftfont_generic_family_list);
314 if (! CONSP (slot))
315 return Qnil;
316 if (! EQ (XCDR (slot), Qt))
317 return XCDR (slot);
318 pattern = FcPatternDuplicate (pattern);
319 if (! pattern)
320 goto err;
321 FcPatternDel (pattern, FC_FOUNDRY);
322 FcPatternDel (pattern, FC_FAMILY);
323 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
324 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
326 /* This is to avoid the effect of locale. */
327 static const FcChar8 lang[] = "en";
328 langset = FcLangSetCreate ();
329 FcLangSetAdd (langset, lang);
330 FcPatternAddLangSet (pattern, FC_LANG, langset);
331 FcLangSetDestroy (langset);
333 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
334 FcDefaultSubstitute (pattern);
335 match = FcFontMatch (NULL, pattern, &result);
336 if (match)
338 FcChar8 *fam;
340 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
341 family = intern ((char *) fam);
343 else
344 family = Qnil;
345 XSETCDR (slot, family);
346 if (match) FcPatternDestroy (match);
347 err:
348 if (pattern) FcPatternDestroy (pattern);
349 return family;
352 struct ftfont_cache_data
354 FT_Face ft_face;
355 FcCharSet *fc_charset;
358 static Lisp_Object
359 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
361 Lisp_Object cache, val, entity;
362 struct ftfont_cache_data *cache_data;
364 if (FONT_ENTITY_P (key))
366 entity = key;
367 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
368 xassert (CONSP (val));
369 key = XCDR (val);
371 else
372 entity = Qnil;
374 if (NILP (ft_face_cache))
375 cache = Qnil;
376 else
377 cache = Fgethash (key, ft_face_cache, Qnil);
378 if (NILP (cache))
380 if (NILP (ft_face_cache))
382 Lisp_Object args[2];
384 args[0] = QCtest;
385 args[1] = Qequal;
386 ft_face_cache = Fmake_hash_table (2, args);
388 cache_data = xmalloc (sizeof (struct ftfont_cache_data));
389 cache_data->ft_face = NULL;
390 cache_data->fc_charset = NULL;
391 val = make_save_value (NULL, 0);
392 XSAVE_VALUE (val)->integer = 0;
393 XSAVE_VALUE (val)->pointer = cache_data;
394 cache = Fcons (Qnil, val);
395 Fputhash (key, cache, ft_face_cache);
397 else
399 val = XCDR (cache);
400 cache_data = XSAVE_VALUE (val)->pointer;
403 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
404 return cache;
406 if (cache_for == FTFONT_CACHE_FOR_FACE
407 ? ! cache_data->ft_face : ! cache_data->fc_charset)
409 char *filename = SSDATA (XCAR (key));
410 int idx = XINT (XCDR (key));
412 if (cache_for == FTFONT_CACHE_FOR_FACE)
414 if (! ft_library
415 && FT_Init_FreeType (&ft_library) != 0)
416 return Qnil;
417 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
418 != 0)
419 return Qnil;
421 else
423 FcPattern *pat = NULL;
424 FcFontSet *fontset = NULL;
425 FcObjectSet *objset = NULL;
426 FcCharSet *charset = NULL;
428 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
429 FC_INDEX, FcTypeInteger, idx, NULL);
430 if (! pat)
431 goto finish;
432 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
433 if (! objset)
434 goto finish;
435 fontset = FcFontList (NULL, pat, objset);
436 if (! fontset)
437 goto finish;
438 if (fontset && fontset->nfont > 0
439 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
440 &charset)
441 == FcResultMatch))
442 cache_data->fc_charset = FcCharSetCopy (charset);
443 else
444 cache_data->fc_charset = FcCharSetCreate ();
446 finish:
447 if (fontset)
448 FcFontSetDestroy (fontset);
449 if (objset)
450 FcObjectSetDestroy (objset);
451 if (pat)
452 FcPatternDestroy (pat);
455 return cache;
458 FcCharSet *
459 ftfont_get_fc_charset (Lisp_Object entity)
461 Lisp_Object val, cache;
462 struct ftfont_cache_data *cache_data;
464 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
465 val = XCDR (cache);
466 cache_data = XSAVE_VALUE (val)->pointer;
467 return cache_data->fc_charset;
470 #ifdef HAVE_LIBOTF
471 static OTF *
472 ftfont_get_otf (struct ftfont_info *ftfont_info)
474 OTF *otf;
476 if (ftfont_info->otf)
477 return ftfont_info->otf;
478 if (! ftfont_info->maybe_otf)
479 return NULL;
480 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
481 if (! otf || OTF_get_table (otf, "head") < 0)
483 if (otf)
484 OTF_close (otf);
485 ftfont_info->maybe_otf = 0;
486 return NULL;
488 ftfont_info->otf = otf;
489 return otf;
491 #endif /* HAVE_LIBOTF */
493 static Lisp_Object ftfont_get_cache (FRAME_PTR);
494 static Lisp_Object ftfont_list (Lisp_Object, Lisp_Object);
495 static Lisp_Object ftfont_match (Lisp_Object, Lisp_Object);
496 static Lisp_Object ftfont_list_family (Lisp_Object);
497 static Lisp_Object ftfont_open (FRAME_PTR, Lisp_Object, int);
498 static void ftfont_close (FRAME_PTR, struct font *);
499 static int ftfont_has_char (Lisp_Object, int);
500 static unsigned ftfont_encode_char (struct font *, int);
501 static int ftfont_text_extents (struct font *, unsigned *, int,
502 struct font_metrics *);
503 static int ftfont_get_bitmap (struct font *, unsigned,
504 struct font_bitmap *, int);
505 static int ftfont_anchor_point (struct font *, unsigned, int,
506 int *, int *);
507 #ifdef HAVE_LIBOTF
508 static Lisp_Object ftfont_otf_capability (struct font *);
509 # ifdef HAVE_M17N_FLT
510 static Lisp_Object ftfont_shape (Lisp_Object);
511 # endif
512 #endif
514 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
515 static int ftfont_variation_glyphs (struct font *, int c,
516 unsigned variations[256]);
517 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
519 struct font_driver ftfont_driver =
521 0, /* Qfreetype */
522 0, /* case insensitive */
523 ftfont_get_cache,
524 ftfont_list,
525 ftfont_match,
526 ftfont_list_family,
527 NULL, /* free_entity */
528 ftfont_open,
529 ftfont_close,
530 /* We can't draw a text without device dependent functions. */
531 NULL, /* prepare_face */
532 NULL, /* done_face */
533 ftfont_has_char,
534 ftfont_encode_char,
535 ftfont_text_extents,
536 /* We can't draw a text without device dependent functions. */
537 NULL, /* draw */
538 ftfont_get_bitmap,
539 NULL, /* get_bitmap */
540 NULL, /* free_bitmap */
541 NULL, /* get_outline */
542 ftfont_anchor_point,
543 #ifdef HAVE_LIBOTF
544 ftfont_otf_capability,
545 #else /* not HAVE_LIBOTF */
546 NULL,
547 #endif /* not HAVE_LIBOTF */
548 NULL, /* otf_drive */
549 NULL, /* start_for_frame */
550 NULL, /* end_for_frame */
551 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
552 ftfont_shape,
553 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
554 NULL,
555 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
556 NULL, /* check */
558 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
559 ftfont_variation_glyphs,
560 #else
561 NULL,
562 #endif
564 ftfont_filter_properties, /* filter_properties */
567 static Lisp_Object
568 ftfont_get_cache (FRAME_PTR f)
570 return freetype_font_cache;
573 static int
574 ftfont_get_charset (Lisp_Object registry)
576 char *str = SSDATA (SYMBOL_NAME (registry));
577 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
578 Lisp_Object regexp;
579 int i, j;
581 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
583 if (str[i] == '.')
584 re[j++] = '\\';
585 else if (str[i] == '*')
586 re[j++] = '.';
587 re[j] = str[i];
588 if (re[j] == '?')
589 re[j] = '.';
591 re[j] = '\0';
592 regexp = make_unibyte_string (re, j);
593 for (i = 0; fc_charset_table[i].name; i++)
594 if (fast_c_string_match_ignore_case (regexp, fc_charset_table[i].name) >= 0)
595 break;
596 if (! fc_charset_table[i].name)
597 return -1;
598 if (! fc_charset_table[i].fc_charset)
600 FcCharSet *charset = FcCharSetCreate ();
601 int *uniquifier = fc_charset_table[i].uniquifier;
603 if (! charset)
604 return -1;
605 for (j = 0; uniquifier[j]; j++)
606 if (! FcCharSetAddChar (charset, uniquifier[j]))
608 FcCharSetDestroy (charset);
609 return -1;
611 fc_charset_table[i].fc_charset = charset;
613 return i;
616 struct OpenTypeSpec
618 Lisp_Object script;
619 unsigned int script_tag, langsys_tag;
620 int nfeatures[2];
621 unsigned int *features[2];
624 #define OTF_SYM_TAG(SYM, TAG) \
625 do { \
626 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
627 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
628 } while (0)
630 #define OTF_TAG_STR(TAG, P) \
631 do { \
632 (P)[0] = (char) (TAG >> 24); \
633 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
634 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
635 (P)[3] = (char) (TAG & 0xFF); \
636 (P)[4] = '\0'; \
637 } while (0)
639 #ifdef HAVE_LIBOTF
640 #define OTF_TAG_SYM(SYM, TAG) \
641 do { \
642 char str[5]; \
644 OTF_TAG_STR (TAG, str); \
645 (SYM) = font_intern_prop (str, 4, 1); \
646 } while (0)
647 #endif
650 static struct OpenTypeSpec *
651 ftfont_get_open_type_spec (Lisp_Object otf_spec)
653 struct OpenTypeSpec *spec = malloc (sizeof (struct OpenTypeSpec));
654 Lisp_Object val;
655 int i, j, negative;
657 if (! spec)
658 return NULL;
659 spec->script = XCAR (otf_spec);
660 if (! NILP (spec->script))
662 OTF_SYM_TAG (spec->script, spec->script_tag);
663 val = assq_no_quit (spec->script, Votf_script_alist);
664 if (CONSP (val) && SYMBOLP (XCDR (val)))
665 spec->script = XCDR (val);
666 else
667 spec->script = Qnil;
669 else
670 spec->script_tag = 0x44464C54; /* "DFLT" */
671 otf_spec = XCDR (otf_spec);
672 spec->langsys_tag = 0;
673 if (! NILP (otf_spec))
675 val = XCAR (otf_spec);
676 if (! NILP (val))
677 OTF_SYM_TAG (val, spec->langsys_tag);
678 otf_spec = XCDR (otf_spec);
680 spec->nfeatures[0] = spec->nfeatures[1] = 0;
681 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
683 Lisp_Object len;
685 val = XCAR (otf_spec);
686 if (NILP (val))
687 continue;
688 len = Flength (val);
689 spec->features[i] = malloc (sizeof (int) * XINT (len));
690 if (! spec->features[i])
692 if (i > 0 && spec->features[0])
693 free (spec->features[0]);
694 free (spec);
695 return NULL;
697 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
699 if (NILP (XCAR (val)))
700 negative = 1;
701 else
703 unsigned int tag;
705 OTF_SYM_TAG (XCAR (val), tag);
706 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
709 spec->nfeatures[i] = j;
711 return spec;
714 static FcPattern *
715 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
717 Lisp_Object tmp, extra;
718 FcPattern *pattern = NULL;
719 FcCharSet *charset = NULL;
720 FcLangSet *langset = NULL;
721 int n;
722 int dpi = -1;
723 int scalable = -1;
724 Lisp_Object script = Qnil;
725 Lisp_Object registry;
726 int fc_charset_idx;
728 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
729 && n < 100)
730 /* Fontconfig doesn't support reverse-italic/obligue. */
731 return NULL;
733 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
734 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
735 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
736 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
737 scalable = 1;
739 registry = AREF (spec, FONT_REGISTRY_INDEX);
740 if (NILP (registry)
741 || EQ (registry, Qascii_0)
742 || EQ (registry, Qiso10646_1)
743 || EQ (registry, Qunicode_bmp))
744 fc_charset_idx = -1;
745 else
747 FcChar8 *lang;
749 fc_charset_idx = ftfont_get_charset (registry);
750 if (fc_charset_idx < 0)
751 return NULL;
752 charset = fc_charset_table[fc_charset_idx].fc_charset;
753 *langname = fc_charset_table[fc_charset_idx].lang;
754 lang = (FcChar8 *) *langname;
755 if (lang)
757 langset = FcLangSetCreate ();
758 if (! langset)
759 goto err;
760 FcLangSetAdd (langset, lang);
764 otlayout[0] = '\0';
765 for (extra = AREF (spec, FONT_EXTRA_INDEX);
766 CONSP (extra); extra = XCDR (extra))
768 Lisp_Object key, val;
770 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
771 if (EQ (key, QCdpi))
773 if (INTEGERP (val))
774 dpi = XINT (val);
776 else if (EQ (key, QClang))
778 if (! langset)
779 langset = FcLangSetCreate ();
780 if (! langset)
781 goto err;
782 if (SYMBOLP (val))
784 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
785 goto err;
787 else
788 for (; CONSP (val); val = XCDR (val))
789 if (SYMBOLP (XCAR (val))
790 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
791 goto err;
793 else if (EQ (key, QCotf))
795 if (CONSP (val))
797 *otspec = ftfont_get_open_type_spec (val);
798 if (! *otspec)
799 return NULL;
800 strcat (otlayout, "otlayout:");
801 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
802 script = (*otspec)->script;
805 else if (EQ (key, QCscript))
806 script = val;
807 else if (EQ (key, QCscalable))
808 scalable = ! NILP (val);
811 if (! NILP (script) && ! charset)
813 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
815 if (CONSP (chars) && CONSP (CDR (chars)))
817 charset = FcCharSetCreate ();
818 if (! charset)
819 goto err;
820 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
821 if (CHARACTERP (XCAR (chars))
822 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
823 goto err;
827 pattern = FcPatternCreate ();
828 if (! pattern)
829 goto err;
830 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
831 if (! NILP (tmp)
832 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
833 goto err;
834 tmp = AREF (spec, FONT_FAMILY_INDEX);
835 if (! NILP (tmp)
836 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
837 goto err;
838 if (charset
839 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
840 goto err;
841 if (langset
842 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
843 goto err;
844 if (dpi >= 0
845 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
846 goto err;
847 if (scalable >= 0
848 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
849 goto err;
851 goto finish;
853 err:
854 /* We come here because of unexpected error in fontconfig API call
855 (usually insufficient memory). */
856 if (pattern)
858 FcPatternDestroy (pattern);
859 pattern = NULL;
861 if (*otspec)
863 if ((*otspec)->nfeatures[0] > 0)
864 free ((*otspec)->features[0]);
865 if ((*otspec)->nfeatures[1] > 0)
866 free ((*otspec)->features[1]);
867 free (*otspec);
868 *otspec = NULL;
871 finish:
872 if (langset) FcLangSetDestroy (langset);
873 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
874 return pattern;
877 static Lisp_Object
878 ftfont_list (Lisp_Object frame, Lisp_Object spec)
880 Lisp_Object val = Qnil, family, adstyle;
881 int i;
882 FcPattern *pattern;
883 FcFontSet *fontset = NULL;
884 FcObjectSet *objset = NULL;
885 FcCharSet *charset;
886 Lisp_Object chars = Qnil;
887 char otlayout[15]; /* For "otlayout:XXXX" */
888 struct OpenTypeSpec *otspec = NULL;
889 int spacing = -1;
890 const char *langname = NULL;
892 if (! fc_initialized)
894 FcInit ();
895 fc_initialized = 1;
898 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
899 if (! pattern)
900 return Qnil;
901 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
903 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
904 if (! NILP (val))
906 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
907 if (CONSP (val) && VECTORP (XCDR (val)))
908 chars = XCDR (val);
910 val = Qnil;
912 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
913 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
914 family = AREF (spec, FONT_FAMILY_INDEX);
915 if (! NILP (family))
917 Lisp_Object resolved;
919 resolved = ftfont_resolve_generic_family (family, pattern);
920 if (! NILP (resolved))
922 FcPatternDel (pattern, FC_FAMILY);
923 if (! FcPatternAddString (pattern, FC_FAMILY,
924 SYMBOL_FcChar8 (resolved)))
925 goto err;
928 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
929 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
930 adstyle = Qnil;
931 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
932 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
933 FC_STYLE, FC_FILE, FC_INDEX,
934 #ifdef FC_CAPABILITY
935 FC_CAPABILITY,
936 #endif /* FC_CAPABILITY */
937 #ifdef FC_FONTFORMAT
938 FC_FONTFORMAT,
939 #endif
940 NULL);
941 if (! objset)
942 goto err;
943 if (! NILP (chars))
944 FcObjectSetAdd (objset, FC_CHARSET);
946 fontset = FcFontList (NULL, pattern, objset);
947 if (! fontset || fontset->nfont == 0)
948 goto finish;
949 #if 0
950 /* Need fix because this finds any fonts. */
951 if (fontset->nfont == 0 && ! NILP (family))
953 /* Try maching with configuration. For instance, the
954 configuration may specify "Nimbus Mono L" as an alias of
955 "Courier". */
956 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
957 SYMBOL_FcChar8 (family), NULL);
958 FcChar8 *fam;
960 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
962 for (i = 0;
963 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
964 i++)
966 FcPatternDel (pattern, FC_FAMILY);
967 FcPatternAddString (pattern, FC_FAMILY, fam);
968 FcFontSetDestroy (fontset);
969 fontset = FcFontList (NULL, pattern, objset);
970 if (fontset && fontset->nfont > 0)
971 break;
975 #endif
976 for (i = 0; i < fontset->nfont; i++)
978 Lisp_Object entity;
980 if (spacing >= 0)
982 int this;
984 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
985 == FcResultMatch)
986 && spacing != this)
987 continue;
990 #ifdef FC_CAPABILITY
991 if (otlayout[0])
993 FcChar8 *this;
995 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
996 != FcResultMatch
997 || ! strstr ((char *) this, otlayout))
998 continue;
1000 #endif /* FC_CAPABILITY */
1001 #ifdef HAVE_LIBOTF
1002 if (otspec)
1004 FcChar8 *file;
1005 OTF *otf;
1007 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1008 != FcResultMatch)
1009 continue;
1010 otf = OTF_open ((char *) file);
1011 if (! otf)
1012 continue;
1013 if (OTF_check_features (otf, 1,
1014 otspec->script_tag, otspec->langsys_tag,
1015 otspec->features[0],
1016 otspec->nfeatures[0]) != 1
1017 || OTF_check_features (otf, 0,
1018 otspec->script_tag, otspec->langsys_tag,
1019 otspec->features[1],
1020 otspec->nfeatures[1]) != 1)
1021 continue;
1023 #endif /* HAVE_LIBOTF */
1024 if (VECTORP (chars))
1026 int j;
1028 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1029 != FcResultMatch)
1030 continue;
1031 for (j = 0; j < ASIZE (chars); j++)
1032 if (NATNUMP (AREF (chars, j))
1033 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1034 break;
1035 if (j == ASIZE (chars))
1036 continue;
1038 if (! NILP (adstyle) || langname)
1040 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1042 if (! NILP (adstyle)
1043 && (NILP (this_adstyle)
1044 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1045 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1046 continue;
1047 if (langname
1048 && ! NILP (this_adstyle)
1049 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1050 continue;
1052 entity = ftfont_pattern_entity (fontset->fonts[i],
1053 AREF (spec, FONT_EXTRA_INDEX));
1054 if (! NILP (entity))
1055 val = Fcons (entity, val);
1057 val = Fnreverse (val);
1058 goto finish;
1060 err:
1061 /* We come here because of unexpected error in fontconfig API call
1062 (usually insufficient memory). */
1063 val = Qnil;
1065 finish:
1066 FONT_ADD_LOG ("ftfont-list", spec, val);
1067 if (objset) FcObjectSetDestroy (objset);
1068 if (fontset) FcFontSetDestroy (fontset);
1069 if (pattern) FcPatternDestroy (pattern);
1070 return val;
1073 static Lisp_Object
1074 ftfont_match (Lisp_Object frame, Lisp_Object spec)
1076 Lisp_Object entity = Qnil;
1077 FcPattern *pattern, *match = NULL;
1078 FcResult result;
1079 char otlayout[15]; /* For "otlayout:XXXX" */
1080 struct OpenTypeSpec *otspec = NULL;
1081 const char *langname = NULL;
1083 if (! fc_initialized)
1085 FcInit ();
1086 fc_initialized = 1;
1089 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1090 if (! pattern)
1091 return Qnil;
1093 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1095 FcValue value;
1097 value.type = FcTypeDouble;
1098 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1099 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1101 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1103 FcDefaultSubstitute (pattern);
1104 match = FcFontMatch (NULL, pattern, &result);
1105 if (match)
1107 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1108 FcPatternDestroy (match);
1109 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1110 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1111 ftfont_generic_family_list))
1112 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1113 AREF (entity, FONT_FAMILY_INDEX))))
1114 entity = Qnil;
1117 FcPatternDestroy (pattern);
1119 FONT_ADD_LOG ("ftfont-match", spec, entity);
1120 return entity;
1123 static Lisp_Object
1124 ftfont_list_family (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 (FRAME_PTR f, Lisp_Object entity, int pixel_size)
1169 struct ftfont_info *ftfont_info;
1170 struct font *font;
1171 struct ftfont_cache_data *cache_data;
1172 FT_Face ft_face;
1173 FT_Size ft_size;
1174 FT_UInt size;
1175 Lisp_Object val, filename, idx, cache, font_object;
1176 int scalable;
1177 int spacing;
1178 char name[256];
1179 int i, len;
1180 int upEM;
1182 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1183 if (! CONSP (val))
1184 return Qnil;
1185 val = XCDR (val);
1186 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1187 if (NILP (cache))
1188 return Qnil;
1189 filename = XCAR (val);
1190 idx = XCDR (val);
1191 val = XCDR (cache);
1192 cache_data = XSAVE_VALUE (XCDR (cache))->pointer;
1193 ft_face = cache_data->ft_face;
1194 if (XSAVE_VALUE (val)->integer > 0)
1196 /* FT_Face in this cache is already used by the different size. */
1197 if (FT_New_Size (ft_face, &ft_size) != 0)
1198 return Qnil;
1199 if (FT_Activate_Size (ft_size) != 0)
1201 FT_Done_Size (ft_size);
1202 return Qnil;
1205 XSAVE_VALUE (val)->integer++;
1206 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1207 if (size == 0)
1208 size = pixel_size;
1209 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1211 if (XSAVE_VALUE (val)->integer == 0)
1212 FT_Done_Face (ft_face);
1213 return Qnil;
1216 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
1217 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
1218 len = font_unparse_xlfd (entity, size, name, 256);
1219 if (len > 0)
1220 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
1221 len = font_unparse_fcname (entity, size, name, 256);
1222 if (len > 0)
1223 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
1224 else
1225 ASET (font_object, FONT_FULLNAME_INDEX,
1226 AREF (font_object, FONT_NAME_INDEX));
1227 ASET (font_object, FONT_FILE_INDEX, filename);
1228 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
1229 font = XFONT_OBJECT (font_object);
1230 ftfont_info = (struct ftfont_info *) font;
1231 ftfont_info->ft_size = ft_face->size;
1232 ftfont_info->index = XINT (idx);
1233 #ifdef HAVE_LIBOTF
1234 ftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
1235 ftfont_info->otf = NULL;
1236 #endif /* HAVE_LIBOTF */
1237 /* This means that there's no need of transformation. */
1238 ftfont_info->matrix.xx = 0;
1239 font->pixel_size = size;
1240 font->driver = &ftfont_driver;
1241 font->encoding_charset = font->repertory_charset = -1;
1243 upEM = ft_face->units_per_EM;
1244 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1245 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1246 if (scalable)
1248 font->ascent = ft_face->ascender * size / upEM;
1249 font->descent = - ft_face->descender * size / upEM;
1250 font->height = ft_face->height * size / upEM;
1252 else
1254 font->ascent = ft_face->size->metrics.ascender >> 6;
1255 font->descent = - ft_face->size->metrics.descender >> 6;
1256 font->height = ft_face->size->metrics.height >> 6;
1258 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1259 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1260 else
1261 spacing = FC_PROPORTIONAL;
1262 if (spacing != FC_PROPORTIONAL
1263 #ifdef FC_DUAL
1264 && spacing != FC_DUAL
1265 #endif /* FC_DUAL */
1267 font->min_width = font->average_width = font->space_width
1268 = (scalable ? ft_face->max_advance_width * size / upEM
1269 : ft_face->size->metrics.max_advance >> 6);
1270 else
1272 int n;
1274 font->min_width = font->average_width = font->space_width = 0;
1275 for (i = 32, n = 0; i < 127; i++)
1276 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1278 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1280 if (this_width > 0
1281 && (! font->min_width || font->min_width > this_width))
1282 font->min_width = this_width;
1283 if (i == 32)
1284 font->space_width = this_width;
1285 font->average_width += this_width;
1286 n++;
1288 if (n > 0)
1289 font->average_width /= n;
1292 font->baseline_offset = 0;
1293 font->relative_compose = 0;
1294 font->default_ascent = 0;
1295 font->vertical_centering = 0;
1296 if (scalable)
1298 font->underline_position = -ft_face->underline_position * size / upEM;
1299 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1301 else
1303 font->underline_position = -1;
1304 font->underline_thickness = 0;
1307 return font_object;
1310 static void
1311 ftfont_close (FRAME_PTR f, struct font *font)
1313 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1314 Lisp_Object val, cache;
1316 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1317 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1318 xassert (CONSP (cache));
1319 val = XCDR (cache);
1320 (XSAVE_VALUE (val)->integer)--;
1321 if (XSAVE_VALUE (val)->integer == 0)
1323 struct ftfont_cache_data *cache_data = XSAVE_VALUE (val)->pointer;
1325 FT_Done_Face (cache_data->ft_face);
1326 #ifdef HAVE_LIBOTF
1327 if (ftfont_info->otf)
1328 OTF_close (ftfont_info->otf);
1329 #endif
1330 cache_data->ft_face = NULL;
1332 else
1333 FT_Done_Size (ftfont_info->ft_size);
1336 static int
1337 ftfont_has_char (Lisp_Object font, int c)
1339 struct charset *cs = NULL;
1341 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1342 && charset_jisx0208 >= 0)
1343 cs = CHARSET_FROM_ID (charset_jisx0208);
1344 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1345 && charset_ksc5601 >= 0)
1346 cs = CHARSET_FROM_ID (charset_ksc5601);
1347 if (cs)
1348 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1350 if (FONT_ENTITY_P (font))
1352 FcCharSet *charset = ftfont_get_fc_charset (font);
1354 return (FcCharSetHasChar (charset, c) == FcTrue);
1356 else
1358 struct ftfont_info *ftfont_info;
1360 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1361 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1362 != 0);
1366 static unsigned
1367 ftfont_encode_char (struct font *font, int c)
1369 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1370 FT_Face ft_face = ftfont_info->ft_size->face;
1371 FT_ULong charcode = c;
1372 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1374 return (code > 0 ? code : FONT_INVALID_CODE);
1377 static int
1378 ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
1380 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1381 FT_Face ft_face = ftfont_info->ft_size->face;
1382 int width = 0;
1383 int i, first;
1385 if (ftfont_info->ft_size != ft_face->size)
1386 FT_Activate_Size (ftfont_info->ft_size);
1387 if (metrics)
1388 memset (metrics, 0, sizeof (struct font_metrics));
1389 for (i = 0, first = 1; i < nglyphs; i++)
1391 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1393 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1395 if (first)
1397 if (metrics)
1399 metrics->lbearing = m->horiBearingX >> 6;
1400 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1401 metrics->ascent = m->horiBearingY >> 6;
1402 metrics->descent = (m->height - m->horiBearingY) >> 6;
1404 first = 0;
1406 if (metrics)
1408 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1409 metrics->lbearing = width + (m->horiBearingX >> 6);
1410 if (metrics->rbearing
1411 < width + ((m->horiBearingX + m->width) >> 6))
1412 metrics->rbearing
1413 = width + ((m->horiBearingX + m->width) >> 6);
1414 if (metrics->ascent < (m->horiBearingY >> 6))
1415 metrics->ascent = m->horiBearingY >> 6;
1416 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1417 metrics->descent = (m->height - m->horiBearingY) >> 6;
1419 width += m->horiAdvance >> 6;
1421 else
1423 width += font->space_width;
1426 if (metrics)
1427 metrics->width = width;
1429 return width;
1432 static int
1433 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1435 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1436 FT_Face ft_face = ftfont_info->ft_size->face;
1437 FT_Int32 load_flags = FT_LOAD_RENDER;
1439 if (ftfont_info->ft_size != ft_face->size)
1440 FT_Activate_Size (ftfont_info->ft_size);
1441 if (bits_per_pixel == 1)
1443 #ifdef FT_LOAD_TARGET_MONO
1444 load_flags |= FT_LOAD_TARGET_MONO;
1445 #else
1446 load_flags |= FT_LOAD_MONOCHROME;
1447 #endif
1449 else if (bits_per_pixel != 8)
1450 /* We don't support such a rendering. */
1451 return -1;
1453 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1454 return -1;
1455 bitmap->bits_per_pixel
1456 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1457 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1458 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1459 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1460 : -1);
1461 if (bitmap->bits_per_pixel < 0)
1462 /* We don't suport that kind of pixel mode. */
1463 return -1;
1464 bitmap->rows = ft_face->glyph->bitmap.rows;
1465 bitmap->width = ft_face->glyph->bitmap.width;
1466 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1467 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1468 bitmap->left = ft_face->glyph->bitmap_left;
1469 bitmap->top = ft_face->glyph->bitmap_top;
1470 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1471 bitmap->extra = NULL;
1473 return 0;
1476 static int
1477 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1478 int *x, int *y)
1480 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1481 FT_Face ft_face = ftfont_info->ft_size->face;
1483 if (ftfont_info->ft_size != ft_face->size)
1484 FT_Activate_Size (ftfont_info->ft_size);
1485 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1486 return -1;
1487 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1488 return -1;
1489 if (idx >= ft_face->glyph->outline.n_points)
1490 return -1;
1491 *x = ft_face->glyph->outline.points[idx].x;
1492 *y = ft_face->glyph->outline.points[idx].y;
1493 return 0;
1496 #ifdef HAVE_LIBOTF
1498 static Lisp_Object
1499 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1501 Lisp_Object scripts, langsyses, features, sym;
1502 int i, j, k, l;
1504 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1506 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1508 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1510 OTF_LangSys *otf_langsys;
1512 if (j >= 0)
1513 otf_langsys = otf_script->LangSys + j;
1514 else if (otf_script->DefaultLangSysOffset)
1515 otf_langsys = &otf_script->DefaultLangSys;
1516 else
1517 break;
1519 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1521 l = otf_langsys->FeatureIndex[k];
1522 if (l >= gsub_gpos->FeatureList.FeatureCount)
1523 continue;
1524 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1525 features = Fcons (sym, features);
1527 if (j >= 0)
1528 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1529 else
1530 sym = Qnil;
1531 langsyses = Fcons (Fcons (sym, features), langsyses);
1534 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1535 scripts = Fcons (Fcons (sym, langsyses), scripts);
1537 return scripts;
1542 static Lisp_Object
1543 ftfont_otf_capability (struct font *font)
1545 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1546 OTF *otf = ftfont_get_otf (ftfont_info);
1547 Lisp_Object gsub_gpos;
1549 if (! otf)
1550 return Qnil;
1551 gsub_gpos = Fcons (Qnil, Qnil);
1552 if (OTF_get_table (otf, "GSUB") == 0
1553 && otf->gsub->FeatureList.FeatureCount > 0)
1554 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1555 if (OTF_get_table (otf, "GPOS") == 0
1556 && otf->gpos->FeatureList.FeatureCount > 0)
1557 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1558 return gsub_gpos;
1561 #ifdef HAVE_M17N_FLT
1563 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1564 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1565 /* We can use the new feature of libotf and m17n-flt to handle the
1566 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1567 some Agian scripts. */
1568 #define M17N_FLT_USE_NEW_FEATURE
1569 #endif
1571 struct MFLTFontFT
1573 MFLTFont flt_font;
1574 struct font *font;
1575 FT_Face ft_face;
1576 OTF *otf;
1577 FT_Matrix *matrix;
1580 static int
1581 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1582 int from, int to)
1584 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1585 FT_Face ft_face = flt_font_ft->ft_face;
1586 MFLTGlyph *g;
1588 for (g = gstring->glyphs + from; from < to; g++, from++)
1589 if (! g->encoded)
1591 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1593 g->code = code > 0 ? code : FONT_INVALID_CODE;
1594 g->encoded = 1;
1596 return 0;
1599 /* Operators for 26.6 fixed fractional pixel format */
1601 #define FLOOR(x) ((x) & -64)
1602 #define CEIL(x) (((x)+63) & -64)
1603 #define ROUND(x) (((x)+32) & -64)
1605 static int
1606 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1607 int from, int to)
1609 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1610 FT_Face ft_face = flt_font_ft->ft_face;
1611 MFLTGlyph *g;
1613 for (g = gstring->glyphs + from; from < to; g++, from++)
1614 if (! g->measured)
1616 if (g->code != FONT_INVALID_CODE)
1618 FT_Glyph_Metrics *m;
1620 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1621 abort ();
1622 m = &ft_face->glyph->metrics;
1623 if (flt_font_ft->matrix)
1625 FT_Vector v[4];
1626 int i;
1628 v[0].x = v[1].x = m->horiBearingX;
1629 v[2].x = v[3].x = m->horiBearingX + m->width;
1630 v[0].y = v[2].y = m->horiBearingY;
1631 v[1].y = v[3].y = m->horiBearingY - m->height;
1632 for (i = 0; i < 4; i++)
1633 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1634 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1635 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1636 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1637 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1639 else
1641 g->lbearing = FLOOR (m->horiBearingX);
1642 g->rbearing = CEIL (m->horiBearingX + m->width);
1643 g->ascent = CEIL (m->horiBearingY);
1644 g->descent = - FLOOR (m->horiBearingY - m->height);
1646 g->xadv = ROUND (ft_face->glyph->advance.x);
1648 else
1650 g->lbearing = 0;
1651 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1652 g->ascent = flt_font_ft->font->ascent << 6;
1653 g->descent = flt_font_ft->font->descent << 6;
1655 g->yadv = 0;
1656 g->measured = 1;
1658 return 0;
1661 static int
1662 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1664 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1666 #define FEATURE_ANY(IDX) \
1667 (spec->features[IDX] \
1668 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1670 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1671 OTF *otf = flt_font_ft->otf;
1672 OTF_Tag *tags;
1673 int i, n, negative;
1675 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1676 /* Return 1 iff any of GSUB or GPOS support the script (and language). */
1677 return (otf
1678 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1679 NULL, 0) > 0
1680 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1681 NULL, 0) > 0));
1683 for (i = 0; i < 2; i++)
1684 if (! FEATURE_ANY (i))
1686 if (FEATURE_NONE (i))
1688 if (otf
1689 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1690 NULL, 0) > 0)
1691 return 0;
1692 continue;
1694 if (spec->features[i][0] == 0xFFFFFFFF)
1696 if (! otf
1697 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1698 NULL, 0) <= 0)
1699 continue;
1701 else if (! otf)
1702 return 0;
1703 for (n = 1; spec->features[i][n]; n++);
1704 tags = alloca (sizeof (OTF_Tag) * n);
1705 for (n = 0, negative = 0; spec->features[i][n]; n++)
1707 if (spec->features[i][n] == 0xFFFFFFFF)
1708 negative = 1;
1709 else if (negative)
1710 tags[n - 1] = spec->features[i][n] | 0x80000000;
1711 else
1712 tags[n] = spec->features[i][n];
1714 #ifdef M17N_FLT_USE_NEW_FEATURE
1715 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1716 tags, n - negative) != 1)
1717 return 0;
1718 #else /* not M17N_FLT_USE_NEW_FEATURE */
1719 if (n - negative > 0
1720 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1721 tags, n - negative) != 1)
1722 return 0;
1723 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1725 return 1;
1726 #undef FEATURE_NONE
1727 #undef FEATURE_ANY
1730 #define DEVICE_DELTA(table, size) \
1731 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1732 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1733 : 0)
1735 static void
1736 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1737 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1739 if (anchor->AnchorFormat == 2)
1741 FT_Outline *outline;
1742 int ap = anchor->f.f1.AnchorPoint;
1744 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1745 outline = &ft_face->glyph->outline;
1746 if (ap < outline->n_points)
1748 *x = outline->points[ap].x << 6;
1749 *y = outline->points[ap].y << 6;
1752 else if (anchor->AnchorFormat == 3)
1754 if (anchor->f.f2.XDeviceTable.offset
1755 && anchor->f.f2.XDeviceTable.DeltaValue)
1756 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1757 if (anchor->f.f2.YDeviceTable.offset
1758 && anchor->f.f2.YDeviceTable.DeltaValue)
1759 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1763 static OTF_GlyphString otf_gstring;
1765 static void
1766 setup_otf_gstring (int size)
1768 if (otf_gstring.size == 0)
1770 otf_gstring.glyphs = (OTF_Glyph *) xmalloc (sizeof (OTF_Glyph) * size);
1771 otf_gstring.size = size;
1773 else if (otf_gstring.size < size)
1775 otf_gstring.glyphs = xrealloc (otf_gstring.glyphs,
1776 sizeof (OTF_Glyph) * size);
1777 otf_gstring.size = size;
1779 otf_gstring.used = size;
1780 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1783 #ifdef M17N_FLT_USE_NEW_FEATURE
1785 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1786 #define PACK_OTF_TAG(TAG) \
1787 ((((TAG) & 0x7F000000) >> 3) \
1788 | (((TAG) & 0x7F0000) >> 2) \
1789 | (((TAG) & 0x7F00) >> 1) \
1790 | ((TAG) & 0x7F))
1792 /* Assuming that FONT is an OpenType font, apply OpenType features
1793 specified in SPEC on glyphs between FROM and TO of IN, and record
1794 the lastly applied feature in each glyph of IN. If OUT is not
1795 NULL, append the resulting glyphs to OUT while storing glyph
1796 position adjustment information in ADJUSTMENT. */
1798 static int
1799 ftfont_drive_otf (MFLTFont *font,
1800 MFLTOtfSpec *spec,
1801 MFLTGlyphString *in,
1802 int from,
1803 int to,
1804 MFLTGlyphString *out,
1805 MFLTGlyphAdjustment *adjustment)
1807 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1808 FT_Face ft_face = flt_font_ft->ft_face;
1809 OTF *otf = flt_font_ft->otf;
1810 int len = to - from;
1811 int i, j, gidx;
1812 OTF_Glyph *otfg;
1813 char script[5], *langsys = NULL;
1814 char *gsub_features = NULL, *gpos_features = NULL;
1815 OTF_Feature *features;
1817 if (len == 0)
1818 return from;
1819 OTF_tag_name (spec->script, script);
1820 if (spec->langsys)
1822 langsys = alloca (5);
1823 OTF_tag_name (spec->langsys, langsys);
1825 for (i = 0; i < 2; i++)
1827 char *p;
1829 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1831 for (j = 0; spec->features[i][j]; j++);
1832 if (i == 0)
1833 p = gsub_features = alloca (6 * j);
1834 else
1835 p = gpos_features = alloca (6 * j);
1836 for (j = 0; spec->features[i][j]; j++)
1838 if (spec->features[i][j] == 0xFFFFFFFF)
1839 *p++ = '*', *p++ = ',';
1840 else
1842 OTF_tag_name (spec->features[i][j], p);
1843 p[4] = ',';
1844 p += 5;
1847 *--p = '\0';
1851 setup_otf_gstring (len);
1852 for (i = 0; i < len; i++)
1854 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
1855 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1858 OTF_drive_gdef (otf, &otf_gstring);
1859 gidx = out ? out->used : from;
1861 if (gsub_features && out)
1863 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1864 gsub_features) < 0)
1865 goto simple_copy;
1866 if (out->allocated < out->used + otf_gstring.used)
1867 return -2;
1868 features = otf->gsub->FeatureList.Feature;
1869 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1871 MFLTGlyph *g;
1872 int min_from, max_to;
1873 int feature_idx = otfg->positioning_type >> 4;
1875 g = out->glyphs + out->used;
1876 *g = in->glyphs[from + otfg->f.index.from];
1877 if (g->code != otfg->glyph_id)
1879 g->c = 0;
1880 g->code = otfg->glyph_id;
1881 g->measured = 0;
1883 out->used++;
1884 min_from = g->from;
1885 max_to = g->to;
1886 if (otfg->f.index.from < otfg->f.index.to)
1888 /* OTFG substitutes multiple glyphs in IN. */
1889 for (j = from + otfg->f.index.from + 1;
1890 j <= from + otfg->f.index.to; j++)
1892 if (min_from > in->glyphs[j].from)
1893 min_from = in->glyphs[j].from;
1894 if (max_to < in->glyphs[j].to)
1895 max_to = in->glyphs[j].to;
1897 g->from = min_from;
1898 g->to = max_to;
1900 if (feature_idx)
1902 unsigned int tag = features[feature_idx - 1].FeatureTag;
1903 tag = PACK_OTF_TAG (tag);
1904 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1906 for (i++, otfg++; (i < otf_gstring.used
1907 && otfg->f.index.from == otfg[-1].f.index.from);
1908 i++, otfg++)
1910 g = out->glyphs + out->used;
1911 *g = in->glyphs[from + otfg->f.index.to];
1912 if (g->code != otfg->glyph_id)
1914 g->c = 0;
1915 g->code = otfg->glyph_id;
1916 g->measured = 0;
1918 feature_idx = otfg->positioning_type >> 4;
1919 if (feature_idx)
1921 unsigned int tag = features[feature_idx - 1].FeatureTag;
1922 tag = PACK_OTF_TAG (tag);
1923 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1925 out->used++;
1929 else if (gsub_features)
1931 /* Just for checking which features will be applied. */
1932 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1933 gsub_features) < 0)
1934 goto simple_copy;
1935 features = otf->gsub->FeatureList.Feature;
1936 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1937 otfg++)
1939 int feature_idx = otfg->positioning_type >> 4;
1941 if (feature_idx)
1943 unsigned int tag = features[feature_idx - 1].FeatureTag;
1944 tag = PACK_OTF_TAG (tag);
1945 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1947 MFLTGlyph *g = in->glyphs + (from + j);
1948 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1953 else if (out)
1955 if (out->allocated < out->used + len)
1956 return -2;
1957 for (i = 0; i < len; i++)
1958 out->glyphs[out->used++] = in->glyphs[from + i];
1961 if (gpos_features && out)
1963 MFLTGlyph *base = NULL, *mark = NULL, *g;
1964 int x_ppem, y_ppem, x_scale, y_scale;
1966 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1967 gpos_features) < 0)
1968 return to;
1969 features = otf->gpos->FeatureList.Feature;
1970 x_ppem = ft_face->size->metrics.x_ppem;
1971 y_ppem = ft_face->size->metrics.y_ppem;
1972 x_scale = ft_face->size->metrics.x_scale;
1973 y_scale = ft_face->size->metrics.y_scale;
1975 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1976 i < otf_gstring.used; i++, otfg++, g++)
1978 MFLTGlyph *prev;
1979 int feature_idx = otfg->positioning_type >> 4;
1981 if (feature_idx)
1983 unsigned int tag = features[feature_idx - 1].FeatureTag;
1984 tag = PACK_OTF_TAG (tag);
1985 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1988 if (! otfg->glyph_id)
1989 continue;
1990 switch (otfg->positioning_type & 0xF)
1992 case 0:
1993 break;
1994 case 1: /* Single */
1995 case 2: /* Pair */
1997 int format = otfg->f.f1.format;
1999 if (format & OTF_XPlacement)
2000 adjustment[i].xoff
2001 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2002 if (format & OTF_XPlaDevice)
2003 adjustment[i].xoff
2004 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2005 if (format & OTF_YPlacement)
2006 adjustment[i].yoff
2007 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2008 if (format & OTF_YPlaDevice)
2009 adjustment[i].yoff
2010 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2011 if (format & OTF_XAdvance)
2012 adjustment[i].xadv
2013 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2014 if (format & OTF_XAdvDevice)
2015 adjustment[i].xadv
2016 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2017 if (format & OTF_YAdvance)
2018 adjustment[i].yadv
2019 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2020 if (format & OTF_YAdvDevice)
2021 adjustment[i].yadv
2022 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2023 adjustment[i].set = 1;
2025 break;
2026 case 3: /* Cursive */
2027 /* Not yet supported. */
2028 break;
2029 case 4: /* Mark-to-Base */
2030 case 5: /* Mark-to-Ligature */
2031 if (! base)
2032 break;
2033 prev = base;
2034 goto label_adjust_anchor;
2035 default: /* i.e. case 6 Mark-to-Mark */
2036 if (! mark)
2037 break;
2038 prev = mark;
2040 label_adjust_anchor:
2042 int base_x, base_y, mark_x, mark_y;
2043 int this_from, this_to;
2045 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2046 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2047 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2048 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2050 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2051 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2052 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2053 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2054 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2055 x_ppem, y_ppem, &mark_x, &mark_y);
2056 adjustment[i].xoff = (base_x - mark_x);
2057 adjustment[i].yoff = - (base_y - mark_y);
2058 adjustment[i].back = (g - prev);
2059 adjustment[i].xadv = 0;
2060 adjustment[i].advance_is_absolute = 1;
2061 adjustment[i].set = 1;
2062 this_from = g->from;
2063 this_to = g->to;
2064 for (j = 0; prev + j < g; j++)
2066 if (this_from > prev[j].from)
2067 this_from = prev[j].from;
2068 if (this_to < prev[j].to)
2069 this_to = prev[j].to;
2071 for (; prev <= g; prev++)
2073 prev->from = this_from;
2074 prev->to = this_to;
2078 if (otfg->GlyphClass == OTF_GlyphClass0)
2079 base = mark = g;
2080 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2081 mark = g;
2082 else
2083 base = g;
2086 else if (gpos_features)
2088 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2089 gpos_features) < 0)
2090 return to;
2091 features = otf->gpos->FeatureList.Feature;
2092 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2093 i++, otfg++)
2094 if (otfg->positioning_type & 0xF)
2096 int feature_idx = otfg->positioning_type >> 4;
2098 if (feature_idx)
2100 unsigned int tag = features[feature_idx - 1].FeatureTag;
2101 tag = PACK_OTF_TAG (tag);
2102 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2104 MFLTGlyph *g = in->glyphs + (from + j);
2105 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2110 return to;
2112 simple_copy:
2113 if (! out)
2114 return to;
2115 if (out->allocated < out->used + len)
2116 return -2;
2117 font->get_metrics (font, in, from, to);
2118 memcpy (out->glyphs + out->used, in->glyphs + from,
2119 sizeof (MFLTGlyph) * len);
2120 out->used += len;
2121 return to;
2124 static int
2125 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2126 MFLTGlyphString *in, int from, int to)
2128 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2131 #else /* not M17N_FLT_USE_NEW_FEATURE */
2133 static int
2134 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2135 int from, int to,
2136 MFLTGlyphString *out, 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 static Lisp_Object
2389 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2390 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2392 EMACS_INT len = LGSTRING_GLYPH_LEN (lgstring);
2393 EMACS_INT i;
2394 struct MFLTFontFT flt_font_ft;
2395 MFLT *flt = NULL;
2396 int with_variation_selector = 0;
2398 if (! m17n_flt_initialized)
2400 M17N_INIT ();
2401 #ifdef M17N_FLT_USE_NEW_FEATURE
2402 mflt_enable_new_feature = 1;
2403 mflt_try_otf = ftfont_try_otf;
2404 #endif /* M17N_FLT_USE_NEW_FEATURE */
2405 m17n_flt_initialized = 1;
2408 for (i = 0; i < len; i++)
2410 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2411 int c;
2413 if (NILP (g))
2414 break;
2415 c = LGLYPH_CHAR (g);
2416 if (CHAR_VARIATION_SELECTOR_P (c))
2417 with_variation_selector++;
2420 len = i;
2421 lint_assume (len <= TYPE_MAXIMUM (EMACS_INT) - 2);
2423 if (with_variation_selector)
2425 setup_otf_gstring (len);
2426 for (i = 0; i < len; i++)
2428 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2430 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2431 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2432 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2434 OTF_drive_cmap (otf, &otf_gstring);
2435 for (i = 0; i < otf_gstring.used; i++)
2437 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2438 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2439 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2441 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2442 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2443 LGSTRING_SET_GLYPH (lgstring, i, g0);
2445 if (len > otf_gstring.used)
2447 len = otf_gstring.used;
2448 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2452 if (gstring.allocated == 0)
2454 gstring.allocated = len * 2;
2455 gstring.glyph_size = sizeof (MFLTGlyph);
2456 gstring.glyphs = xmalloc (sizeof (MFLTGlyph) * gstring.allocated);
2458 else if (gstring.allocated < len * 2)
2460 gstring.allocated = len * 2;
2461 gstring.glyphs = xrealloc (gstring.glyphs,
2462 sizeof (MFLTGlyph) * gstring.allocated);
2464 memset (gstring.glyphs, 0, sizeof (MFLTGlyph) * len);
2465 for (i = 0; i < len; i++)
2467 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2469 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2470 if (with_variation_selector)
2472 gstring.glyphs[i].code = LGLYPH_CODE (g);
2473 gstring.glyphs[i].encoded = 1;
2477 gstring.used = len;
2478 gstring.r2l = 0;
2481 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2483 if (NILP (family))
2484 flt_font_ft.flt_font.family = Mnil;
2485 else
2486 flt_font_ft.flt_font.family
2487 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2489 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2490 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2491 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2492 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2493 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2494 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2495 flt_font_ft.flt_font.internal = NULL;
2496 flt_font_ft.font = font;
2497 flt_font_ft.ft_face = ft_face;
2498 flt_font_ft.otf = otf;
2499 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2500 if (len > 1
2501 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2502 /* A little bit ad hoc. Perhaps, shaper must get script and
2503 language information, and select a proper flt for them
2504 here. */
2505 flt = mflt_get (msymbol ("combining"));
2506 for (i = 0; i < 3; i++)
2508 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2509 if (result != -2)
2510 break;
2511 gstring.allocated += gstring.allocated;
2512 gstring.glyphs = xrealloc (gstring.glyphs,
2513 sizeof (MFLTGlyph) * gstring.allocated);
2515 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2516 return Qnil;
2517 for (i = 0; i < gstring.used; i++)
2519 MFLTGlyph *g = gstring.glyphs + i;
2521 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2522 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2525 for (i = 0; i < gstring.used; i++)
2527 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2528 MFLTGlyph *g = gstring.glyphs + i;
2530 if (NILP (lglyph))
2532 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2533 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2535 LGLYPH_SET_FROM (lglyph, g->from);
2536 LGLYPH_SET_TO (lglyph, g->to);
2537 LGLYPH_SET_CHAR (lglyph, g->c);
2538 LGLYPH_SET_CODE (lglyph, g->code);
2539 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2540 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2541 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2542 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2543 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2544 if (g->adjusted)
2546 Lisp_Object vec;
2548 vec = Fmake_vector (make_number (3), Qnil);
2549 ASET (vec, 0, make_number (g->xoff >> 6));
2550 ASET (vec, 1, make_number (g->yoff >> 6));
2551 ASET (vec, 2, make_number (g->xadv >> 6));
2552 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2555 return make_number (i);
2558 Lisp_Object
2559 ftfont_shape (Lisp_Object lgstring)
2561 struct font *font;
2562 struct ftfont_info *ftfont_info;
2563 OTF *otf;
2565 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2566 ftfont_info = (struct ftfont_info *) font;
2567 otf = ftfont_get_otf (ftfont_info);
2568 if (! otf)
2569 return make_number (0);
2570 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2571 &ftfont_info->matrix);
2574 #endif /* HAVE_M17N_FLT */
2576 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2578 static int
2579 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2581 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2582 OTF *otf = ftfont_get_otf (ftfont_info);
2584 if (! otf)
2585 return 0;
2586 return OTF_get_variation_glyphs (otf, c, variations);
2589 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2590 #endif /* HAVE_LIBOTF */
2592 Lisp_Object
2593 ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
2595 FcChar8 *str;
2597 #ifdef FC_FONTFORMAT
2598 if (pattern)
2600 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2601 return Qnil;
2602 if (strcmp ((char *) str, "TrueType") == 0)
2603 return intern ("truetype");
2604 if (strcmp ((char *) str, "Type 1") == 0)
2605 return intern ("type1");
2606 if (strcmp ((char *) str, "PCF") == 0)
2607 return intern ("pcf");
2608 if (strcmp ((char *) str, "BDF") == 0)
2609 return intern ("bdf");
2611 #endif /* FC_FONTFORMAT */
2612 if (STRINGP (filename))
2614 int len = SBYTES (filename);
2616 if (len >= 4)
2618 str = (FcChar8 *) (SDATA (filename) + len - 4);
2619 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2620 return intern ("truetype");
2621 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2622 return intern ("type1");
2623 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2624 return intern ("pcf");
2625 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2626 return intern ("bdf");
2629 return intern ("unknown");
2632 static const char *const ftfont_booleans [] = {
2633 ":antialias",
2634 ":hinting",
2635 ":verticallayout",
2636 ":autohint",
2637 ":globaladvance",
2638 ":outline",
2639 ":scalable",
2640 ":minspace",
2641 ":embolden",
2642 NULL,
2645 static const char *const ftfont_non_booleans [] = {
2646 ":family",
2647 ":familylang",
2648 ":style",
2649 ":stylelang",
2650 ":fullname",
2651 ":fullnamelang",
2652 ":slant",
2653 ":weight",
2654 ":size",
2655 ":width",
2656 ":aspect",
2657 ":pixelsize",
2658 ":spacing",
2659 ":foundry",
2660 ":hintstyle",
2661 ":file",
2662 ":index",
2663 ":ftface",
2664 ":rasterizer",
2665 ":scale",
2666 ":dpi",
2667 ":rgba",
2668 ":lcdfilter",
2669 ":charset",
2670 ":lang",
2671 ":fontversion",
2672 ":capability",
2673 NULL,
2676 static void
2677 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2679 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2683 void
2684 syms_of_ftfont (void)
2686 DEFSYM (Qfreetype, "freetype");
2687 DEFSYM (Qmonospace, "monospace");
2688 DEFSYM (Qsans_serif, "sans-serif");
2689 DEFSYM (Qserif, "serif");
2690 DEFSYM (Qmono, "mono");
2691 DEFSYM (Qsans, "sans");
2692 DEFSYM (Qsans__serif, "sans serif");
2694 staticpro (&freetype_font_cache);
2695 freetype_font_cache = Fcons (Qt, Qnil);
2697 staticpro (&ftfont_generic_family_list);
2698 ftfont_generic_family_list
2699 = Fcons (Fcons (Qmonospace, Qt),
2700 Fcons (Fcons (Qsans_serif, Qt),
2701 Fcons (Fcons (Qsans, Qt), Qnil)));
2703 staticpro (&ft_face_cache);
2704 ft_face_cache = Qnil;
2706 ftfont_driver.type = Qfreetype;
2707 register_font_driver (&ftfont_driver, NULL);