Adapt the MS-DOS build to the latest changes.
[emacs.git] / src / ftfont.c
blob29732e4c8705825a6e802571cf604196796fc0a6
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2012 Free Software Foundation, Inc.
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
7 This file is part of GNU Emacs.
9 GNU Emacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 #include <config.h>
23 #include <stdio.h>
24 #include <setjmp.h>
26 #include <fontconfig/fontconfig.h>
27 #include <fontconfig/fcfreetype.h>
29 #include "lisp.h"
30 #include "dispextern.h"
31 #include "frame.h"
32 #include "blockinput.h"
33 #include "character.h"
34 #include "charset.h"
35 #include "coding.h"
36 #include "composite.h"
37 #include "fontset.h"
38 #include "font.h"
39 #include "ftfont.h"
41 /* Symbolic type of this font-driver. */
42 static Lisp_Object Qfreetype;
44 /* Fontconfig's generic families and their aliases. */
45 static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
47 /* Flag to tell if FcInit is already called or not. */
48 static int fc_initialized;
50 /* Handle to a FreeType library instance. */
51 static FT_Library ft_library;
53 /* Cache for FreeType fonts. */
54 static Lisp_Object freetype_font_cache;
56 /* Cache for FT_Face and FcCharSet. */
57 static Lisp_Object ft_face_cache;
59 /* The actual structure for FreeType font that can be casted to struct
60 font. */
62 struct ftfont_info
64 struct font font;
65 #ifdef HAVE_LIBOTF
66 /* The following four members must be here in this order to be
67 compatible with struct xftfont_info (in xftfont.c). */
68 int maybe_otf; /* Flag to tell if this may be OTF or not. */
69 OTF *otf;
70 #endif /* HAVE_LIBOTF */
71 FT_Size ft_size;
72 int index;
73 FT_Matrix matrix;
76 enum ftfont_cache_for
78 FTFONT_CACHE_FOR_FACE,
79 FTFONT_CACHE_FOR_CHARSET,
80 FTFONT_CACHE_FOR_ENTITY
83 static Lisp_Object ftfont_pattern_entity (FcPattern *, Lisp_Object);
85 static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
86 FcPattern *);
87 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
88 enum ftfont_cache_for);
90 static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
92 Lisp_Object ftfont_font_format (FcPattern *, Lisp_Object);
94 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
96 static struct
98 /* registry name */
99 const char *name;
100 /* characters to distinguish the charset from the others */
101 int uniquifier[6];
102 /* additional constraint by language */
103 const char *lang;
104 /* set on demand */
105 FcCharSet *fc_charset;
106 } fc_charset_table[] =
107 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
108 { "iso8859-2", { 0x00A0, 0x010E }},
109 { "iso8859-3", { 0x00A0, 0x0108 }},
110 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
111 { "iso8859-5", { 0x00A0, 0x0401 }},
112 { "iso8859-6", { 0x00A0, 0x060C }},
113 { "iso8859-7", { 0x00A0, 0x0384 }},
114 { "iso8859-8", { 0x00A0, 0x05D0 }},
115 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
116 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
117 { "iso8859-11", { 0x00A0, 0x0E01 }},
118 { "iso8859-13", { 0x00A0, 0x201C }},
119 { "iso8859-14", { 0x00A0, 0x0174 }},
120 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
121 { "iso8859-16", { 0x00A0, 0x0218}},
122 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
123 { "big5-0", { 0xF6B1 }, "zh-tw" },
124 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
125 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
126 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
127 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
128 { "cns11643.1992-3", { 0x201A9 }},
129 { "cns11643.1992-4", { 0x20057 }},
130 { "cns11643.1992-5", { 0x20000 }},
131 { "cns11643.1992-6", { 0x20003 }},
132 { "cns11643.1992-7", { 0x20055 }},
133 { "gbk-0", { 0x4E06 }, "zh-cn"},
134 { "jisx0212.1990-0", { 0x4E44 }},
135 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
136 { "jisx0213.2000-2", { 0xFA49 }},
137 { "jisx0213.2004-1", { 0x20B9F }},
138 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
139 { "tis620.2529-1", { 0x0E01 }, "th"},
140 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
141 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
142 { "mulelao-1", { 0x0E81 }, "lo"},
143 { "unicode-sip", { 0x20000 }},
144 { NULL }
147 /* Dirty hack for handing ADSTYLE property.
149 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
150 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
151 "Oblique", "Italic", or any non-normal SWIDTH property names
152 (e.g. SemiCondensed) are appended. In addition, if there's no
153 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
154 "Regular" is used for FC_STYLE (see the function
155 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
157 Unfortunately this behavior is not documented, so the following
158 code may fail if FreeType changes the behavior in the future. */
160 static Lisp_Object
161 get_adstyle_property (FcPattern *p)
163 FcChar8 *fcstr;
164 char *str, *end;
165 Lisp_Object adstyle;
167 #ifdef FC_FONTFORMAT
168 if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
169 && xstrcasecmp ((char *) fcstr, "bdf") != 0
170 && xstrcasecmp ((char *) fcstr, "pcf") != 0)
171 /* Not a BDF nor PCF font. */
172 return Qnil;
173 #endif
174 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
175 return Qnil;
176 str = (char *) fcstr;
177 for (end = str; *end && *end != ' '; end++);
178 if (*end)
180 char *newstr = alloca (end - str + 1);
181 memcpy (newstr, str, end - str);
182 newstr[end - str] = '\0';
183 end = newstr + (end - str);
184 str = newstr;
186 if (xstrcasecmp (str, "Regular") == 0
187 || xstrcasecmp (str, "Bold") == 0
188 || xstrcasecmp (str, "Oblique") == 0
189 || xstrcasecmp (str, "Italic") == 0)
190 return Qnil;
191 adstyle = font_intern_prop (str, end - str, 1);
192 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
193 return Qnil;
194 return adstyle;
197 static Lisp_Object
198 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
200 Lisp_Object key, cache, entity;
201 FcChar8 *str;
202 char *file;
203 int idx;
204 int numeric;
205 double dbl;
206 FcBool b;
208 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
209 return Qnil;
210 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
211 return Qnil;
213 file = (char *) str;
214 key = Fcons (make_unibyte_string (file, strlen (file)), make_number (idx));
215 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
216 entity = XCAR (cache);
217 if (! NILP (entity))
219 Lisp_Object val = font_make_entity ();
220 int i;
222 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
223 ASET (val, i, AREF (entity, i));
225 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
226 font_put_extra (val, QCfont_entity, key);
228 return val;
230 entity = font_make_entity ();
231 XSETCAR (cache, entity);
233 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
234 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
236 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
238 char *s = (char *) str;
239 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
241 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
243 char *s = (char *) str;
244 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
246 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
248 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
249 numeric = FC_WEIGHT_MEDIUM;
250 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
252 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
254 numeric += 100;
255 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
257 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
259 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
261 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
263 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
265 else
266 ASET (entity, FONT_SIZE_INDEX, make_number (0));
267 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
268 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
269 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
271 int dpi = dbl;
272 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
274 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
275 && b == FcTrue)
277 ASET (entity, FONT_SIZE_INDEX, make_number (0));
278 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
280 else
282 /* As this font is not scalable, perhaps this is a BDF or PCF
283 font. */
284 FT_Face ft_face;
286 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
287 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
288 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
290 BDF_PropertyRec rec;
292 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
293 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
294 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
295 FT_Done_Face (ft_face);
299 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
300 font_put_extra (entity, QCfont_entity, key);
301 return entity;
305 static Lisp_Object ftfont_generic_family_list;
307 static Lisp_Object
308 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
310 Lisp_Object slot;
311 FcPattern *match;
312 FcResult result;
313 FcLangSet *langset;
315 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
316 if (EQ (family, Qmono))
317 family = Qmonospace;
318 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
319 family = Qsans_serif;
320 slot = assq_no_quit (family, ftfont_generic_family_list);
321 if (! CONSP (slot))
322 return Qnil;
323 if (! EQ (XCDR (slot), Qt))
324 return XCDR (slot);
325 pattern = FcPatternDuplicate (pattern);
326 if (! pattern)
327 goto err;
328 FcPatternDel (pattern, FC_FOUNDRY);
329 FcPatternDel (pattern, FC_FAMILY);
330 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
331 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
333 /* This is to avoid the effect of locale. */
334 static const FcChar8 lang[] = "en";
335 langset = FcLangSetCreate ();
336 FcLangSetAdd (langset, lang);
337 FcPatternAddLangSet (pattern, FC_LANG, langset);
338 FcLangSetDestroy (langset);
340 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
341 FcDefaultSubstitute (pattern);
342 match = FcFontMatch (NULL, pattern, &result);
343 if (match)
345 FcChar8 *fam;
347 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
348 family = intern ((char *) fam);
350 else
351 family = Qnil;
352 XSETCDR (slot, family);
353 if (match) FcPatternDestroy (match);
354 err:
355 if (pattern) FcPatternDestroy (pattern);
356 return family;
359 struct ftfont_cache_data
361 FT_Face ft_face;
362 FcCharSet *fc_charset;
365 static Lisp_Object
366 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
368 Lisp_Object cache, val, entity;
369 struct ftfont_cache_data *cache_data;
371 if (FONT_ENTITY_P (key))
373 entity = key;
374 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
375 eassert (CONSP (val));
376 key = XCDR (val);
378 else
379 entity = Qnil;
381 if (NILP (ft_face_cache))
382 cache = Qnil;
383 else
384 cache = Fgethash (key, ft_face_cache, Qnil);
385 if (NILP (cache))
387 if (NILP (ft_face_cache))
389 Lisp_Object args[2];
391 args[0] = QCtest;
392 args[1] = Qequal;
393 ft_face_cache = Fmake_hash_table (2, args);
395 cache_data = xmalloc (sizeof (struct ftfont_cache_data));
396 cache_data->ft_face = NULL;
397 cache_data->fc_charset = NULL;
398 val = make_save_value (NULL, 0);
399 XSAVE_VALUE (val)->integer = 0;
400 XSAVE_VALUE (val)->pointer = cache_data;
401 cache = Fcons (Qnil, val);
402 Fputhash (key, cache, ft_face_cache);
404 else
406 val = XCDR (cache);
407 cache_data = XSAVE_VALUE (val)->pointer;
410 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
411 return cache;
413 if (cache_for == FTFONT_CACHE_FOR_FACE
414 ? ! cache_data->ft_face : ! cache_data->fc_charset)
416 char *filename = SSDATA (XCAR (key));
417 int idx = XINT (XCDR (key));
419 if (cache_for == FTFONT_CACHE_FOR_FACE)
421 if (! ft_library
422 && FT_Init_FreeType (&ft_library) != 0)
423 return Qnil;
424 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
425 != 0)
426 return Qnil;
428 else
430 FcPattern *pat = NULL;
431 FcFontSet *fontset = NULL;
432 FcObjectSet *objset = NULL;
433 FcCharSet *charset = NULL;
435 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
436 FC_INDEX, FcTypeInteger, idx, NULL);
437 if (! pat)
438 goto finish;
439 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
440 if (! objset)
441 goto finish;
442 fontset = FcFontList (NULL, pat, objset);
443 if (! fontset)
444 goto finish;
445 if (fontset && fontset->nfont > 0
446 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
447 &charset)
448 == FcResultMatch))
449 cache_data->fc_charset = FcCharSetCopy (charset);
450 else
451 cache_data->fc_charset = FcCharSetCreate ();
453 finish:
454 if (fontset)
455 FcFontSetDestroy (fontset);
456 if (objset)
457 FcObjectSetDestroy (objset);
458 if (pat)
459 FcPatternDestroy (pat);
462 return cache;
465 FcCharSet *
466 ftfont_get_fc_charset (Lisp_Object entity)
468 Lisp_Object val, cache;
469 struct ftfont_cache_data *cache_data;
471 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
472 val = XCDR (cache);
473 cache_data = XSAVE_VALUE (val)->pointer;
474 return cache_data->fc_charset;
477 #ifdef HAVE_LIBOTF
478 static OTF *
479 ftfont_get_otf (struct ftfont_info *ftfont_info)
481 OTF *otf;
483 if (ftfont_info->otf)
484 return ftfont_info->otf;
485 if (! ftfont_info->maybe_otf)
486 return NULL;
487 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
488 if (! otf || OTF_get_table (otf, "head") < 0)
490 if (otf)
491 OTF_close (otf);
492 ftfont_info->maybe_otf = 0;
493 return NULL;
495 ftfont_info->otf = otf;
496 return otf;
498 #endif /* HAVE_LIBOTF */
500 static Lisp_Object ftfont_get_cache (FRAME_PTR);
501 static Lisp_Object ftfont_list (Lisp_Object, Lisp_Object);
502 static Lisp_Object ftfont_match (Lisp_Object, Lisp_Object);
503 static Lisp_Object ftfont_list_family (Lisp_Object);
504 static Lisp_Object ftfont_open (FRAME_PTR, Lisp_Object, int);
505 static void ftfont_close (FRAME_PTR, struct font *);
506 static int ftfont_has_char (Lisp_Object, int);
507 static unsigned ftfont_encode_char (struct font *, int);
508 static int ftfont_text_extents (struct font *, unsigned *, int,
509 struct font_metrics *);
510 static int ftfont_get_bitmap (struct font *, unsigned,
511 struct font_bitmap *, int);
512 static int ftfont_anchor_point (struct font *, unsigned, int,
513 int *, int *);
514 #ifdef HAVE_LIBOTF
515 static Lisp_Object ftfont_otf_capability (struct font *);
516 # ifdef HAVE_M17N_FLT
517 static Lisp_Object ftfont_shape (Lisp_Object);
518 # endif
519 #endif
521 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
522 static int ftfont_variation_glyphs (struct font *, int c,
523 unsigned variations[256]);
524 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
526 struct font_driver ftfont_driver =
528 LISP_INITIALLY_ZERO, /* Qfreetype */
529 0, /* case insensitive */
530 ftfont_get_cache,
531 ftfont_list,
532 ftfont_match,
533 ftfont_list_family,
534 NULL, /* free_entity */
535 ftfont_open,
536 ftfont_close,
537 /* We can't draw a text without device dependent functions. */
538 NULL, /* prepare_face */
539 NULL, /* done_face */
540 ftfont_has_char,
541 ftfont_encode_char,
542 ftfont_text_extents,
543 /* We can't draw a text without device dependent functions. */
544 NULL, /* draw */
545 ftfont_get_bitmap,
546 NULL, /* get_bitmap */
547 NULL, /* free_bitmap */
548 NULL, /* get_outline */
549 ftfont_anchor_point,
550 #ifdef HAVE_LIBOTF
551 ftfont_otf_capability,
552 #else /* not HAVE_LIBOTF */
553 NULL,
554 #endif /* not HAVE_LIBOTF */
555 NULL, /* otf_drive */
556 NULL, /* start_for_frame */
557 NULL, /* end_for_frame */
558 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
559 ftfont_shape,
560 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
561 NULL,
562 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
563 NULL, /* check */
565 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
566 ftfont_variation_glyphs,
567 #else
568 NULL,
569 #endif
571 ftfont_filter_properties, /* filter_properties */
574 static Lisp_Object
575 ftfont_get_cache (FRAME_PTR f)
577 return freetype_font_cache;
580 static int
581 ftfont_get_charset (Lisp_Object registry)
583 char *str = SSDATA (SYMBOL_NAME (registry));
584 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
585 Lisp_Object regexp;
586 int i, j;
588 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
590 if (str[i] == '.')
591 re[j++] = '\\';
592 else if (str[i] == '*')
593 re[j++] = '.';
594 re[j] = str[i];
595 if (re[j] == '?')
596 re[j] = '.';
598 re[j] = '\0';
599 regexp = make_unibyte_string (re, j);
600 for (i = 0; fc_charset_table[i].name; i++)
601 if (fast_c_string_match_ignore_case (regexp, fc_charset_table[i].name) >= 0)
602 break;
603 if (! fc_charset_table[i].name)
604 return -1;
605 if (! fc_charset_table[i].fc_charset)
607 FcCharSet *charset = FcCharSetCreate ();
608 int *uniquifier = fc_charset_table[i].uniquifier;
610 if (! charset)
611 return -1;
612 for (j = 0; uniquifier[j]; j++)
613 if (! FcCharSetAddChar (charset, uniquifier[j]))
615 FcCharSetDestroy (charset);
616 return -1;
618 fc_charset_table[i].fc_charset = charset;
620 return i;
623 struct OpenTypeSpec
625 Lisp_Object script;
626 unsigned int script_tag, langsys_tag;
627 int nfeatures[2];
628 unsigned int *features[2];
631 #define OTF_SYM_TAG(SYM, TAG) \
632 do { \
633 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
634 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
635 } while (0)
637 #define OTF_TAG_STR(TAG, P) \
638 do { \
639 (P)[0] = (char) (TAG >> 24); \
640 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
641 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
642 (P)[3] = (char) (TAG & 0xFF); \
643 (P)[4] = '\0'; \
644 } while (0)
646 #ifdef HAVE_LIBOTF
647 #define OTF_TAG_SYM(SYM, TAG) \
648 do { \
649 char str[5]; \
651 OTF_TAG_STR (TAG, str); \
652 (SYM) = font_intern_prop (str, 4, 1); \
653 } while (0)
654 #endif
657 static struct OpenTypeSpec *
658 ftfont_get_open_type_spec (Lisp_Object otf_spec)
660 struct OpenTypeSpec *spec = malloc (sizeof (struct OpenTypeSpec));
661 Lisp_Object val;
662 int i, j, negative;
664 if (! spec)
665 return NULL;
666 spec->script = XCAR (otf_spec);
667 if (! NILP (spec->script))
669 OTF_SYM_TAG (spec->script, spec->script_tag);
670 val = assq_no_quit (spec->script, Votf_script_alist);
671 if (CONSP (val) && SYMBOLP (XCDR (val)))
672 spec->script = XCDR (val);
673 else
674 spec->script = Qnil;
676 else
677 spec->script_tag = 0x44464C54; /* "DFLT" */
678 otf_spec = XCDR (otf_spec);
679 spec->langsys_tag = 0;
680 if (! NILP (otf_spec))
682 val = XCAR (otf_spec);
683 if (! NILP (val))
684 OTF_SYM_TAG (val, spec->langsys_tag);
685 otf_spec = XCDR (otf_spec);
687 spec->nfeatures[0] = spec->nfeatures[1] = 0;
688 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
690 Lisp_Object len;
692 val = XCAR (otf_spec);
693 if (NILP (val))
694 continue;
695 len = Flength (val);
696 spec->features[i] =
697 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
699 : malloc (sizeof (int) * XINT (len)));
700 if (! spec->features[i])
702 if (i > 0 && spec->features[0])
703 free (spec->features[0]);
704 free (spec);
705 return NULL;
707 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
709 if (NILP (XCAR (val)))
710 negative = 1;
711 else
713 unsigned int tag;
715 OTF_SYM_TAG (XCAR (val), tag);
716 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
719 spec->nfeatures[i] = j;
721 return spec;
724 static FcPattern *
725 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
727 Lisp_Object tmp, extra;
728 FcPattern *pattern = NULL;
729 FcCharSet *charset = NULL;
730 FcLangSet *langset = NULL;
731 int n;
732 int dpi = -1;
733 int scalable = -1;
734 Lisp_Object script = Qnil;
735 Lisp_Object registry;
736 int fc_charset_idx;
738 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
739 && n < 100)
740 /* Fontconfig doesn't support reverse-italic/oblique. */
741 return NULL;
743 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
744 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
745 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
746 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
747 scalable = 1;
749 registry = AREF (spec, FONT_REGISTRY_INDEX);
750 if (NILP (registry)
751 || EQ (registry, Qascii_0)
752 || EQ (registry, Qiso10646_1)
753 || EQ (registry, Qunicode_bmp))
754 fc_charset_idx = -1;
755 else
757 FcChar8 *lang;
759 fc_charset_idx = ftfont_get_charset (registry);
760 if (fc_charset_idx < 0)
761 return NULL;
762 charset = fc_charset_table[fc_charset_idx].fc_charset;
763 *langname = fc_charset_table[fc_charset_idx].lang;
764 lang = (FcChar8 *) *langname;
765 if (lang)
767 langset = FcLangSetCreate ();
768 if (! langset)
769 goto err;
770 FcLangSetAdd (langset, lang);
774 otlayout[0] = '\0';
775 for (extra = AREF (spec, FONT_EXTRA_INDEX);
776 CONSP (extra); extra = XCDR (extra))
778 Lisp_Object key, val;
780 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
781 if (EQ (key, QCdpi))
783 if (INTEGERP (val))
784 dpi = XINT (val);
786 else if (EQ (key, QClang))
788 if (! langset)
789 langset = FcLangSetCreate ();
790 if (! langset)
791 goto err;
792 if (SYMBOLP (val))
794 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
795 goto err;
797 else
798 for (; CONSP (val); val = XCDR (val))
799 if (SYMBOLP (XCAR (val))
800 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
801 goto err;
803 else if (EQ (key, QCotf))
805 if (CONSP (val))
807 *otspec = ftfont_get_open_type_spec (val);
808 if (! *otspec)
809 return NULL;
810 strcat (otlayout, "otlayout:");
811 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
812 script = (*otspec)->script;
815 else if (EQ (key, QCscript))
816 script = val;
817 else if (EQ (key, QCscalable))
818 scalable = ! NILP (val);
821 if (! NILP (script) && ! charset)
823 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
825 if (CONSP (chars) && CONSP (CDR (chars)))
827 charset = FcCharSetCreate ();
828 if (! charset)
829 goto err;
830 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
831 if (CHARACTERP (XCAR (chars))
832 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
833 goto err;
837 pattern = FcPatternCreate ();
838 if (! pattern)
839 goto err;
840 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
841 if (! NILP (tmp)
842 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
843 goto err;
844 tmp = AREF (spec, FONT_FAMILY_INDEX);
845 if (! NILP (tmp)
846 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
847 goto err;
848 if (charset
849 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
850 goto err;
851 if (langset
852 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
853 goto err;
854 if (dpi >= 0
855 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
856 goto err;
857 if (scalable >= 0
858 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
859 goto err;
861 goto finish;
863 err:
864 /* We come here because of unexpected error in fontconfig API call
865 (usually insufficient memory). */
866 if (pattern)
868 FcPatternDestroy (pattern);
869 pattern = NULL;
871 if (*otspec)
873 if ((*otspec)->nfeatures[0] > 0)
874 free ((*otspec)->features[0]);
875 if ((*otspec)->nfeatures[1] > 0)
876 free ((*otspec)->features[1]);
877 free (*otspec);
878 *otspec = NULL;
881 finish:
882 if (langset) FcLangSetDestroy (langset);
883 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
884 return pattern;
887 static Lisp_Object
888 ftfont_list (Lisp_Object frame, Lisp_Object spec)
890 Lisp_Object val = Qnil, family, adstyle;
891 int i;
892 FcPattern *pattern;
893 FcFontSet *fontset = NULL;
894 FcObjectSet *objset = NULL;
895 FcCharSet *charset;
896 Lisp_Object chars = Qnil;
897 char otlayout[15]; /* For "otlayout:XXXX" */
898 struct OpenTypeSpec *otspec = NULL;
899 int spacing = -1;
900 const char *langname = NULL;
902 if (! fc_initialized)
904 FcInit ();
905 fc_initialized = 1;
908 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
909 if (! pattern)
910 return Qnil;
911 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
913 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
914 if (! NILP (val))
916 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
917 if (CONSP (val) && VECTORP (XCDR (val)))
918 chars = XCDR (val);
920 val = Qnil;
922 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
923 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
924 family = AREF (spec, FONT_FAMILY_INDEX);
925 if (! NILP (family))
927 Lisp_Object resolved;
929 resolved = ftfont_resolve_generic_family (family, pattern);
930 if (! NILP (resolved))
932 FcPatternDel (pattern, FC_FAMILY);
933 if (! FcPatternAddString (pattern, FC_FAMILY,
934 SYMBOL_FcChar8 (resolved)))
935 goto err;
938 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
939 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
940 adstyle = Qnil;
941 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
942 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
943 FC_STYLE, FC_FILE, FC_INDEX,
944 #ifdef FC_CAPABILITY
945 FC_CAPABILITY,
946 #endif /* FC_CAPABILITY */
947 #ifdef FC_FONTFORMAT
948 FC_FONTFORMAT,
949 #endif
950 NULL);
951 if (! objset)
952 goto err;
953 if (! NILP (chars))
954 FcObjectSetAdd (objset, FC_CHARSET);
956 fontset = FcFontList (NULL, pattern, objset);
957 if (! fontset || fontset->nfont == 0)
958 goto finish;
959 #if 0
960 /* Need fix because this finds any fonts. */
961 if (fontset->nfont == 0 && ! NILP (family))
963 /* Try matching with configuration. For instance, the
964 configuration may specify "Nimbus Mono L" as an alias of
965 "Courier". */
966 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
967 SYMBOL_FcChar8 (family), NULL);
968 FcChar8 *fam;
970 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
972 for (i = 0;
973 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
974 i++)
976 FcPatternDel (pattern, FC_FAMILY);
977 FcPatternAddString (pattern, FC_FAMILY, fam);
978 FcFontSetDestroy (fontset);
979 fontset = FcFontList (NULL, pattern, objset);
980 if (fontset && fontset->nfont > 0)
981 break;
985 #endif
986 for (i = 0; i < fontset->nfont; i++)
988 Lisp_Object entity;
990 if (spacing >= 0)
992 int this;
994 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
995 == FcResultMatch)
996 && spacing != this)
997 continue;
1000 #ifdef FC_CAPABILITY
1001 if (otlayout[0])
1003 FcChar8 *this;
1005 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
1006 != FcResultMatch
1007 || ! strstr ((char *) this, otlayout))
1008 continue;
1010 #endif /* FC_CAPABILITY */
1011 #ifdef HAVE_LIBOTF
1012 if (otspec)
1014 FcChar8 *file;
1015 OTF *otf;
1017 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1018 != FcResultMatch)
1019 continue;
1020 otf = OTF_open ((char *) file);
1021 if (! otf)
1022 continue;
1023 if (OTF_check_features (otf, 1,
1024 otspec->script_tag, otspec->langsys_tag,
1025 otspec->features[0],
1026 otspec->nfeatures[0]) != 1
1027 || OTF_check_features (otf, 0,
1028 otspec->script_tag, otspec->langsys_tag,
1029 otspec->features[1],
1030 otspec->nfeatures[1]) != 1)
1031 continue;
1033 #endif /* HAVE_LIBOTF */
1034 if (VECTORP (chars))
1036 ptrdiff_t j;
1038 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1039 != FcResultMatch)
1040 continue;
1041 for (j = 0; j < ASIZE (chars); j++)
1042 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1043 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1044 break;
1045 if (j == ASIZE (chars))
1046 continue;
1048 if (! NILP (adstyle) || langname)
1050 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1052 if (! NILP (adstyle)
1053 && (NILP (this_adstyle)
1054 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1055 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1056 continue;
1057 if (langname
1058 && ! NILP (this_adstyle)
1059 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1060 continue;
1062 entity = ftfont_pattern_entity (fontset->fonts[i],
1063 AREF (spec, FONT_EXTRA_INDEX));
1064 if (! NILP (entity))
1065 val = Fcons (entity, val);
1067 val = Fnreverse (val);
1068 goto finish;
1070 err:
1071 /* We come here because of unexpected error in fontconfig API call
1072 (usually insufficient memory). */
1073 val = Qnil;
1075 finish:
1076 FONT_ADD_LOG ("ftfont-list", spec, val);
1077 if (objset) FcObjectSetDestroy (objset);
1078 if (fontset) FcFontSetDestroy (fontset);
1079 if (pattern) FcPatternDestroy (pattern);
1080 return val;
1083 static Lisp_Object
1084 ftfont_match (Lisp_Object frame, Lisp_Object spec)
1086 Lisp_Object entity = Qnil;
1087 FcPattern *pattern, *match = NULL;
1088 FcResult result;
1089 char otlayout[15]; /* For "otlayout:XXXX" */
1090 struct OpenTypeSpec *otspec = NULL;
1091 const char *langname = NULL;
1093 if (! fc_initialized)
1095 FcInit ();
1096 fc_initialized = 1;
1099 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1100 if (! pattern)
1101 return Qnil;
1103 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1105 FcValue value;
1107 value.type = FcTypeDouble;
1108 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1109 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1111 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1113 FcDefaultSubstitute (pattern);
1114 match = FcFontMatch (NULL, pattern, &result);
1115 if (match)
1117 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1118 FcPatternDestroy (match);
1119 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1120 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1121 ftfont_generic_family_list))
1122 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1123 AREF (entity, FONT_FAMILY_INDEX))))
1124 entity = Qnil;
1127 FcPatternDestroy (pattern);
1129 FONT_ADD_LOG ("ftfont-match", spec, entity);
1130 return entity;
1133 static Lisp_Object
1134 ftfont_list_family (Lisp_Object frame)
1136 Lisp_Object list = Qnil;
1137 FcPattern *pattern = NULL;
1138 FcFontSet *fontset = NULL;
1139 FcObjectSet *objset = NULL;
1140 int i;
1142 if (! fc_initialized)
1144 FcInit ();
1145 fc_initialized = 1;
1148 pattern = FcPatternCreate ();
1149 if (! pattern)
1150 goto finish;
1151 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1152 if (! objset)
1153 goto finish;
1154 fontset = FcFontList (NULL, pattern, objset);
1155 if (! fontset)
1156 goto finish;
1158 for (i = 0; i < fontset->nfont; i++)
1160 FcPattern *pat = fontset->fonts[i];
1161 FcChar8 *str;
1163 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1164 list = Fcons (intern ((char *) str), list);
1167 finish:
1168 if (objset) FcObjectSetDestroy (objset);
1169 if (fontset) FcFontSetDestroy (fontset);
1170 if (pattern) FcPatternDestroy (pattern);
1172 return list;
1176 static Lisp_Object
1177 ftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
1179 struct ftfont_info *ftfont_info;
1180 struct font *font;
1181 struct ftfont_cache_data *cache_data;
1182 FT_Face ft_face;
1183 FT_Size ft_size;
1184 FT_UInt size;
1185 Lisp_Object val, filename, idx, cache, font_object;
1186 int scalable;
1187 int spacing;
1188 char name[256];
1189 int i, len;
1190 int upEM;
1192 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1193 if (! CONSP (val))
1194 return Qnil;
1195 val = XCDR (val);
1196 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1197 if (NILP (cache))
1198 return Qnil;
1199 filename = XCAR (val);
1200 idx = XCDR (val);
1201 val = XCDR (cache);
1202 cache_data = XSAVE_VALUE (XCDR (cache))->pointer;
1203 ft_face = cache_data->ft_face;
1204 if (XSAVE_VALUE (val)->integer > 0)
1206 /* FT_Face in this cache is already used by the different size. */
1207 if (FT_New_Size (ft_face, &ft_size) != 0)
1208 return Qnil;
1209 if (FT_Activate_Size (ft_size) != 0)
1211 FT_Done_Size (ft_size);
1212 return Qnil;
1215 XSAVE_VALUE (val)->integer++;
1216 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1217 if (size == 0)
1218 size = pixel_size;
1219 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1221 if (XSAVE_VALUE (val)->integer == 0)
1222 FT_Done_Face (ft_face);
1223 return Qnil;
1226 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
1227 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
1228 len = font_unparse_xlfd (entity, size, name, 256);
1229 if (len > 0)
1230 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
1231 len = font_unparse_fcname (entity, size, name, 256);
1232 if (len > 0)
1233 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
1234 else
1235 ASET (font_object, FONT_FULLNAME_INDEX,
1236 AREF (font_object, FONT_NAME_INDEX));
1237 ASET (font_object, FONT_FILE_INDEX, filename);
1238 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
1239 font = XFONT_OBJECT (font_object);
1240 ftfont_info = (struct ftfont_info *) font;
1241 ftfont_info->ft_size = ft_face->size;
1242 ftfont_info->index = XINT (idx);
1243 #ifdef HAVE_LIBOTF
1244 ftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
1245 ftfont_info->otf = NULL;
1246 #endif /* HAVE_LIBOTF */
1247 /* This means that there's no need of transformation. */
1248 ftfont_info->matrix.xx = 0;
1249 font->pixel_size = size;
1250 font->driver = &ftfont_driver;
1251 font->encoding_charset = font->repertory_charset = -1;
1253 upEM = ft_face->units_per_EM;
1254 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1255 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1256 if (scalable)
1258 font->ascent = ft_face->ascender * size / upEM;
1259 font->descent = - ft_face->descender * size / upEM;
1260 font->height = ft_face->height * size / upEM;
1262 else
1264 font->ascent = ft_face->size->metrics.ascender >> 6;
1265 font->descent = - ft_face->size->metrics.descender >> 6;
1266 font->height = ft_face->size->metrics.height >> 6;
1268 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1269 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1270 else
1271 spacing = FC_PROPORTIONAL;
1272 if (spacing != FC_PROPORTIONAL
1273 #ifdef FC_DUAL
1274 && spacing != FC_DUAL
1275 #endif /* FC_DUAL */
1277 font->min_width = font->average_width = font->space_width
1278 = (scalable ? ft_face->max_advance_width * size / upEM
1279 : ft_face->size->metrics.max_advance >> 6);
1280 else
1282 int n;
1284 font->min_width = font->average_width = font->space_width = 0;
1285 for (i = 32, n = 0; i < 127; i++)
1286 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1288 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1290 if (this_width > 0
1291 && (! font->min_width || font->min_width > this_width))
1292 font->min_width = this_width;
1293 if (i == 32)
1294 font->space_width = this_width;
1295 font->average_width += this_width;
1296 n++;
1298 if (n > 0)
1299 font->average_width /= n;
1302 font->baseline_offset = 0;
1303 font->relative_compose = 0;
1304 font->default_ascent = 0;
1305 font->vertical_centering = 0;
1306 if (scalable)
1308 font->underline_position = -ft_face->underline_position * size / upEM;
1309 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1311 else
1313 font->underline_position = -1;
1314 font->underline_thickness = 0;
1317 return font_object;
1320 static void
1321 ftfont_close (FRAME_PTR f, struct font *font)
1323 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1324 Lisp_Object val, cache;
1326 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1327 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1328 eassert (CONSP (cache));
1329 val = XCDR (cache);
1330 (XSAVE_VALUE (val)->integer)--;
1331 if (XSAVE_VALUE (val)->integer == 0)
1333 struct ftfont_cache_data *cache_data = XSAVE_VALUE (val)->pointer;
1335 FT_Done_Face (cache_data->ft_face);
1336 #ifdef HAVE_LIBOTF
1337 if (ftfont_info->otf)
1338 OTF_close (ftfont_info->otf);
1339 #endif
1340 cache_data->ft_face = NULL;
1342 else
1343 FT_Done_Size (ftfont_info->ft_size);
1346 static int
1347 ftfont_has_char (Lisp_Object font, int c)
1349 struct charset *cs = NULL;
1351 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1352 && charset_jisx0208 >= 0)
1353 cs = CHARSET_FROM_ID (charset_jisx0208);
1354 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1355 && charset_ksc5601 >= 0)
1356 cs = CHARSET_FROM_ID (charset_ksc5601);
1357 if (cs)
1358 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1360 if (FONT_ENTITY_P (font))
1362 FcCharSet *charset = ftfont_get_fc_charset (font);
1364 return (FcCharSetHasChar (charset, c) == FcTrue);
1366 else
1368 struct ftfont_info *ftfont_info;
1370 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1371 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1372 != 0);
1376 static unsigned
1377 ftfont_encode_char (struct font *font, int c)
1379 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1380 FT_Face ft_face = ftfont_info->ft_size->face;
1381 FT_ULong charcode = c;
1382 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1384 return (code > 0 ? code : FONT_INVALID_CODE);
1387 static int
1388 ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
1390 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1391 FT_Face ft_face = ftfont_info->ft_size->face;
1392 int width = 0;
1393 int i, first;
1395 if (ftfont_info->ft_size != ft_face->size)
1396 FT_Activate_Size (ftfont_info->ft_size);
1397 if (metrics)
1398 memset (metrics, 0, sizeof (struct font_metrics));
1399 for (i = 0, first = 1; i < nglyphs; i++)
1401 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1403 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1405 if (first)
1407 if (metrics)
1409 metrics->lbearing = m->horiBearingX >> 6;
1410 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1411 metrics->ascent = m->horiBearingY >> 6;
1412 metrics->descent = (m->height - m->horiBearingY) >> 6;
1414 first = 0;
1416 if (metrics)
1418 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1419 metrics->lbearing = width + (m->horiBearingX >> 6);
1420 if (metrics->rbearing
1421 < width + ((m->horiBearingX + m->width) >> 6))
1422 metrics->rbearing
1423 = width + ((m->horiBearingX + m->width) >> 6);
1424 if (metrics->ascent < (m->horiBearingY >> 6))
1425 metrics->ascent = m->horiBearingY >> 6;
1426 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1427 metrics->descent = (m->height - m->horiBearingY) >> 6;
1429 width += m->horiAdvance >> 6;
1431 else
1433 width += font->space_width;
1436 if (metrics)
1437 metrics->width = width;
1439 return width;
1442 static int
1443 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1445 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1446 FT_Face ft_face = ftfont_info->ft_size->face;
1447 FT_Int32 load_flags = FT_LOAD_RENDER;
1449 if (ftfont_info->ft_size != ft_face->size)
1450 FT_Activate_Size (ftfont_info->ft_size);
1451 if (bits_per_pixel == 1)
1453 #ifdef FT_LOAD_TARGET_MONO
1454 load_flags |= FT_LOAD_TARGET_MONO;
1455 #else
1456 load_flags |= FT_LOAD_MONOCHROME;
1457 #endif
1459 else if (bits_per_pixel != 8)
1460 /* We don't support such a rendering. */
1461 return -1;
1463 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1464 return -1;
1465 bitmap->bits_per_pixel
1466 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1467 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1468 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1469 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1470 : -1);
1471 if (bitmap->bits_per_pixel < 0)
1472 /* We don't support that kind of pixel mode. */
1473 return -1;
1474 bitmap->rows = ft_face->glyph->bitmap.rows;
1475 bitmap->width = ft_face->glyph->bitmap.width;
1476 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1477 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1478 bitmap->left = ft_face->glyph->bitmap_left;
1479 bitmap->top = ft_face->glyph->bitmap_top;
1480 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1481 bitmap->extra = NULL;
1483 return 0;
1486 static int
1487 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1488 int *x, int *y)
1490 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1491 FT_Face ft_face = ftfont_info->ft_size->face;
1493 if (ftfont_info->ft_size != ft_face->size)
1494 FT_Activate_Size (ftfont_info->ft_size);
1495 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1496 return -1;
1497 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1498 return -1;
1499 if (idx >= ft_face->glyph->outline.n_points)
1500 return -1;
1501 *x = ft_face->glyph->outline.points[idx].x;
1502 *y = ft_face->glyph->outline.points[idx].y;
1503 return 0;
1506 #ifdef HAVE_LIBOTF
1508 static Lisp_Object
1509 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1511 Lisp_Object scripts, langsyses, features, sym;
1512 int i, j, k, l;
1514 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1516 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1518 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1520 OTF_LangSys *otf_langsys;
1522 if (j >= 0)
1523 otf_langsys = otf_script->LangSys + j;
1524 else if (otf_script->DefaultLangSysOffset)
1525 otf_langsys = &otf_script->DefaultLangSys;
1526 else
1527 break;
1529 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1531 l = otf_langsys->FeatureIndex[k];
1532 if (l >= gsub_gpos->FeatureList.FeatureCount)
1533 continue;
1534 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1535 features = Fcons (sym, features);
1537 if (j >= 0)
1538 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1539 else
1540 sym = Qnil;
1541 langsyses = Fcons (Fcons (sym, features), langsyses);
1544 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1545 scripts = Fcons (Fcons (sym, langsyses), scripts);
1547 return scripts;
1552 static Lisp_Object
1553 ftfont_otf_capability (struct font *font)
1555 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1556 OTF *otf = ftfont_get_otf (ftfont_info);
1557 Lisp_Object gsub_gpos;
1559 if (! otf)
1560 return Qnil;
1561 gsub_gpos = Fcons (Qnil, Qnil);
1562 if (OTF_get_table (otf, "GSUB") == 0
1563 && otf->gsub->FeatureList.FeatureCount > 0)
1564 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1565 if (OTF_get_table (otf, "GPOS") == 0
1566 && otf->gpos->FeatureList.FeatureCount > 0)
1567 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1568 return gsub_gpos;
1571 #ifdef HAVE_M17N_FLT
1573 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1574 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1575 /* We can use the new feature of libotf and m17n-flt to handle the
1576 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1577 some Agian scripts. */
1578 #define M17N_FLT_USE_NEW_FEATURE
1579 #endif
1581 struct MFLTFontFT
1583 MFLTFont flt_font;
1584 struct font *font;
1585 FT_Face ft_face;
1586 OTF *otf;
1587 FT_Matrix *matrix;
1590 static int
1591 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1592 int from, int to)
1594 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1595 FT_Face ft_face = flt_font_ft->ft_face;
1596 MFLTGlyph *g;
1598 for (g = gstring->glyphs + from; from < to; g++, from++)
1599 if (! g->encoded)
1601 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1603 g->code = code > 0 ? code : FONT_INVALID_CODE;
1604 g->encoded = 1;
1606 return 0;
1609 /* Operators for 26.6 fixed fractional pixel format */
1611 #define FLOOR(x) ((x) & -64)
1612 #define CEIL(x) (((x)+63) & -64)
1613 #define ROUND(x) (((x)+32) & -64)
1615 static int
1616 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1617 int from, int to)
1619 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1620 FT_Face ft_face = flt_font_ft->ft_face;
1621 MFLTGlyph *g;
1623 for (g = gstring->glyphs + from; from < to; g++, from++)
1624 if (! g->measured)
1626 if (g->code != FONT_INVALID_CODE)
1628 FT_Glyph_Metrics *m;
1630 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1631 abort ();
1632 m = &ft_face->glyph->metrics;
1633 if (flt_font_ft->matrix)
1635 FT_Vector v[4];
1636 int i;
1638 v[0].x = v[1].x = m->horiBearingX;
1639 v[2].x = v[3].x = m->horiBearingX + m->width;
1640 v[0].y = v[2].y = m->horiBearingY;
1641 v[1].y = v[3].y = m->horiBearingY - m->height;
1642 for (i = 0; i < 4; i++)
1643 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1644 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1645 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1646 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1647 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1649 else
1651 g->lbearing = FLOOR (m->horiBearingX);
1652 g->rbearing = CEIL (m->horiBearingX + m->width);
1653 g->ascent = CEIL (m->horiBearingY);
1654 g->descent = - FLOOR (m->horiBearingY - m->height);
1656 g->xadv = ROUND (ft_face->glyph->advance.x);
1658 else
1660 g->lbearing = 0;
1661 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1662 g->ascent = flt_font_ft->font->ascent << 6;
1663 g->descent = flt_font_ft->font->descent << 6;
1665 g->yadv = 0;
1666 g->measured = 1;
1668 return 0;
1671 static int
1672 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1674 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1676 #define FEATURE_ANY(IDX) \
1677 (spec->features[IDX] \
1678 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1680 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1681 OTF *otf = flt_font_ft->otf;
1682 OTF_Tag *tags;
1683 int i, n, negative;
1685 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1686 /* Return 1 iff any of GSUB or GPOS support the script (and language). */
1687 return (otf
1688 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1689 NULL, 0) > 0
1690 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1691 NULL, 0) > 0));
1693 for (i = 0; i < 2; i++)
1694 if (! FEATURE_ANY (i))
1696 if (FEATURE_NONE (i))
1698 if (otf
1699 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1700 NULL, 0) > 0)
1701 return 0;
1702 continue;
1704 if (spec->features[i][0] == 0xFFFFFFFF)
1706 if (! otf
1707 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1708 NULL, 0) <= 0)
1709 continue;
1711 else if (! otf)
1712 return 0;
1713 for (n = 1; spec->features[i][n]; n++);
1714 tags = alloca (sizeof (OTF_Tag) * n);
1715 for (n = 0, negative = 0; spec->features[i][n]; n++)
1717 if (spec->features[i][n] == 0xFFFFFFFF)
1718 negative = 1;
1719 else if (negative)
1720 tags[n - 1] = spec->features[i][n] | 0x80000000;
1721 else
1722 tags[n] = spec->features[i][n];
1724 #ifdef M17N_FLT_USE_NEW_FEATURE
1725 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1726 tags, n - negative) != 1)
1727 return 0;
1728 #else /* not M17N_FLT_USE_NEW_FEATURE */
1729 if (n - negative > 0
1730 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1731 tags, n - negative) != 1)
1732 return 0;
1733 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1735 return 1;
1736 #undef FEATURE_NONE
1737 #undef FEATURE_ANY
1740 #define DEVICE_DELTA(table, size) \
1741 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1742 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1743 : 0)
1745 static void
1746 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1747 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1749 if (anchor->AnchorFormat == 2)
1751 FT_Outline *outline;
1752 int ap = anchor->f.f1.AnchorPoint;
1754 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1755 outline = &ft_face->glyph->outline;
1756 if (ap < outline->n_points)
1758 *x = outline->points[ap].x << 6;
1759 *y = outline->points[ap].y << 6;
1762 else if (anchor->AnchorFormat == 3)
1764 if (anchor->f.f2.XDeviceTable.offset
1765 && anchor->f.f2.XDeviceTable.DeltaValue)
1766 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1767 if (anchor->f.f2.YDeviceTable.offset
1768 && anchor->f.f2.YDeviceTable.DeltaValue)
1769 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1773 static OTF_GlyphString otf_gstring;
1775 static void
1776 setup_otf_gstring (int size)
1778 if (otf_gstring.size < size)
1780 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1781 size, sizeof (OTF_Glyph));
1782 otf_gstring.size = size;
1784 otf_gstring.used = size;
1785 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1788 #ifdef M17N_FLT_USE_NEW_FEATURE
1790 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1791 #define PACK_OTF_TAG(TAG) \
1792 ((((TAG) & 0x7F000000) >> 3) \
1793 | (((TAG) & 0x7F0000) >> 2) \
1794 | (((TAG) & 0x7F00) >> 1) \
1795 | ((TAG) & 0x7F))
1797 /* Assuming that FONT is an OpenType font, apply OpenType features
1798 specified in SPEC on glyphs between FROM and TO of IN, and record
1799 the lastly applied feature in each glyph of IN. If OUT is not
1800 NULL, append the resulting glyphs to OUT while storing glyph
1801 position adjustment information in ADJUSTMENT. */
1803 static int
1804 ftfont_drive_otf (MFLTFont *font,
1805 MFLTOtfSpec *spec,
1806 MFLTGlyphString *in,
1807 int from,
1808 int to,
1809 MFLTGlyphString *out,
1810 MFLTGlyphAdjustment *adjustment)
1812 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1813 FT_Face ft_face = flt_font_ft->ft_face;
1814 OTF *otf = flt_font_ft->otf;
1815 int len = to - from;
1816 int i, j, gidx;
1817 OTF_Glyph *otfg;
1818 char script[5], *langsys = NULL;
1819 char *gsub_features = NULL, *gpos_features = NULL;
1820 OTF_Feature *features;
1822 if (len == 0)
1823 return from;
1824 OTF_tag_name (spec->script, script);
1825 if (spec->langsys)
1827 langsys = alloca (5);
1828 OTF_tag_name (spec->langsys, langsys);
1830 for (i = 0; i < 2; i++)
1832 char *p;
1834 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1836 for (j = 0; spec->features[i][j]; j++);
1837 if (i == 0)
1838 p = gsub_features = alloca (6 * j);
1839 else
1840 p = gpos_features = alloca (6 * j);
1841 for (j = 0; spec->features[i][j]; j++)
1843 if (spec->features[i][j] == 0xFFFFFFFF)
1844 *p++ = '*', *p++ = ',';
1845 else
1847 OTF_tag_name (spec->features[i][j], p);
1848 p[4] = ',';
1849 p += 5;
1852 *--p = '\0';
1856 setup_otf_gstring (len);
1857 for (i = 0; i < len; i++)
1859 otf_gstring.glyphs[i].c = in->glyphs[from + i].c & 0x11FFFF;
1860 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1863 OTF_drive_gdef (otf, &otf_gstring);
1864 gidx = out ? out->used : from;
1866 if (gsub_features && out)
1868 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1869 gsub_features) < 0)
1870 goto simple_copy;
1871 if (out->allocated < out->used + otf_gstring.used)
1872 return -2;
1873 features = otf->gsub->FeatureList.Feature;
1874 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1876 MFLTGlyph *g;
1877 int min_from, max_to;
1878 int feature_idx = otfg->positioning_type >> 4;
1880 g = out->glyphs + out->used;
1881 *g = in->glyphs[from + otfg->f.index.from];
1882 if (g->code != otfg->glyph_id)
1884 g->c = 0;
1885 g->code = otfg->glyph_id;
1886 g->measured = 0;
1888 out->used++;
1889 min_from = g->from;
1890 max_to = g->to;
1891 if (otfg->f.index.from < otfg->f.index.to)
1893 /* OTFG substitutes multiple glyphs in IN. */
1894 for (j = from + otfg->f.index.from + 1;
1895 j <= from + otfg->f.index.to; j++)
1897 if (min_from > in->glyphs[j].from)
1898 min_from = in->glyphs[j].from;
1899 if (max_to < in->glyphs[j].to)
1900 max_to = in->glyphs[j].to;
1902 g->from = min_from;
1903 g->to = max_to;
1905 if (feature_idx)
1907 unsigned int tag = features[feature_idx - 1].FeatureTag;
1908 tag = PACK_OTF_TAG (tag);
1909 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1911 for (i++, otfg++; (i < otf_gstring.used
1912 && otfg->f.index.from == otfg[-1].f.index.from);
1913 i++, otfg++)
1915 g = out->glyphs + out->used;
1916 *g = in->glyphs[from + otfg->f.index.to];
1917 if (g->code != otfg->glyph_id)
1919 g->c = 0;
1920 g->code = otfg->glyph_id;
1921 g->measured = 0;
1923 feature_idx = otfg->positioning_type >> 4;
1924 if (feature_idx)
1926 unsigned int tag = features[feature_idx - 1].FeatureTag;
1927 tag = PACK_OTF_TAG (tag);
1928 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1930 out->used++;
1934 else if (gsub_features)
1936 /* Just for checking which features will be applied. */
1937 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1938 gsub_features) < 0)
1939 goto simple_copy;
1940 features = otf->gsub->FeatureList.Feature;
1941 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1942 otfg++)
1944 int feature_idx = otfg->positioning_type >> 4;
1946 if (feature_idx)
1948 unsigned int tag = features[feature_idx - 1].FeatureTag;
1949 tag = PACK_OTF_TAG (tag);
1950 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1952 MFLTGlyph *g = in->glyphs + (from + j);
1953 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1958 else if (out)
1960 if (out->allocated < out->used + len)
1961 return -2;
1962 for (i = 0; i < len; i++)
1963 out->glyphs[out->used++] = in->glyphs[from + i];
1966 if (gpos_features && out)
1968 MFLTGlyph *base = NULL, *mark = NULL, *g;
1969 int x_ppem, y_ppem, x_scale, y_scale;
1971 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1972 gpos_features) < 0)
1973 return to;
1974 features = otf->gpos->FeatureList.Feature;
1975 x_ppem = ft_face->size->metrics.x_ppem;
1976 y_ppem = ft_face->size->metrics.y_ppem;
1977 x_scale = ft_face->size->metrics.x_scale;
1978 y_scale = ft_face->size->metrics.y_scale;
1980 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1981 i < otf_gstring.used; i++, otfg++, g++)
1983 MFLTGlyph *prev;
1984 int feature_idx = otfg->positioning_type >> 4;
1986 if (feature_idx)
1988 unsigned int tag = features[feature_idx - 1].FeatureTag;
1989 tag = PACK_OTF_TAG (tag);
1990 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1993 if (! otfg->glyph_id)
1994 continue;
1995 switch (otfg->positioning_type & 0xF)
1997 case 0:
1998 break;
1999 case 1: /* Single */
2000 case 2: /* Pair */
2002 int format = otfg->f.f1.format;
2004 if (format & OTF_XPlacement)
2005 adjustment[i].xoff
2006 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2007 if (format & OTF_XPlaDevice)
2008 adjustment[i].xoff
2009 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2010 if (format & OTF_YPlacement)
2011 adjustment[i].yoff
2012 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2013 if (format & OTF_YPlaDevice)
2014 adjustment[i].yoff
2015 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2016 if (format & OTF_XAdvance)
2017 adjustment[i].xadv
2018 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2019 if (format & OTF_XAdvDevice)
2020 adjustment[i].xadv
2021 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2022 if (format & OTF_YAdvance)
2023 adjustment[i].yadv
2024 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2025 if (format & OTF_YAdvDevice)
2026 adjustment[i].yadv
2027 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2028 adjustment[i].set = 1;
2030 break;
2031 case 3: /* Cursive */
2032 /* Not yet supported. */
2033 break;
2034 case 4: /* Mark-to-Base */
2035 case 5: /* Mark-to-Ligature */
2036 if (! base)
2037 break;
2038 prev = base;
2039 goto label_adjust_anchor;
2040 default: /* i.e. case 6 Mark-to-Mark */
2041 if (! mark)
2042 break;
2043 prev = mark;
2045 label_adjust_anchor:
2047 int base_x, base_y, mark_x, mark_y;
2048 int this_from, this_to;
2050 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2051 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2052 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2053 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2055 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2056 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2057 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2058 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2059 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2060 x_ppem, y_ppem, &mark_x, &mark_y);
2061 adjustment[i].xoff = (base_x - mark_x);
2062 adjustment[i].yoff = - (base_y - mark_y);
2063 adjustment[i].back = (g - prev);
2064 adjustment[i].xadv = 0;
2065 adjustment[i].advance_is_absolute = 1;
2066 adjustment[i].set = 1;
2067 this_from = g->from;
2068 this_to = g->to;
2069 for (j = 0; prev + j < g; j++)
2071 if (this_from > prev[j].from)
2072 this_from = prev[j].from;
2073 if (this_to < prev[j].to)
2074 this_to = prev[j].to;
2076 for (; prev <= g; prev++)
2078 prev->from = this_from;
2079 prev->to = this_to;
2083 if (otfg->GlyphClass == OTF_GlyphClass0)
2084 base = mark = g;
2085 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2086 mark = g;
2087 else
2088 base = g;
2091 else if (gpos_features)
2093 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2094 gpos_features) < 0)
2095 return to;
2096 features = otf->gpos->FeatureList.Feature;
2097 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2098 i++, otfg++)
2099 if (otfg->positioning_type & 0xF)
2101 int feature_idx = otfg->positioning_type >> 4;
2103 if (feature_idx)
2105 unsigned int tag = features[feature_idx - 1].FeatureTag;
2106 tag = PACK_OTF_TAG (tag);
2107 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2109 MFLTGlyph *g = in->glyphs + (from + j);
2110 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2115 return to;
2117 simple_copy:
2118 if (! out)
2119 return to;
2120 if (out->allocated < out->used + len)
2121 return -2;
2122 font->get_metrics (font, in, from, to);
2123 memcpy (out->glyphs + out->used, in->glyphs + from,
2124 sizeof (MFLTGlyph) * len);
2125 out->used += len;
2126 return to;
2129 static int
2130 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2131 MFLTGlyphString *in, int from, int to)
2133 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2136 #else /* not M17N_FLT_USE_NEW_FEATURE */
2138 static int
2139 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2140 int from, int to,
2141 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2143 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2144 FT_Face ft_face = flt_font_ft->ft_face;
2145 OTF *otf = flt_font_ft->otf;
2146 int len = to - from;
2147 int i, j, gidx;
2148 OTF_Glyph *otfg;
2149 char script[5], *langsys = NULL;
2150 char *gsub_features = NULL, *gpos_features = NULL;
2152 if (len == 0)
2153 return from;
2154 OTF_tag_name (spec->script, script);
2155 if (spec->langsys)
2157 langsys = alloca (5);
2158 OTF_tag_name (spec->langsys, langsys);
2160 for (i = 0; i < 2; i++)
2162 char *p;
2164 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2166 for (j = 0; spec->features[i][j]; j++);
2167 if (i == 0)
2168 p = gsub_features = alloca (6 * j);
2169 else
2170 p = gpos_features = alloca (6 * j);
2171 for (j = 0; spec->features[i][j]; j++)
2173 if (spec->features[i][j] == 0xFFFFFFFF)
2174 *p++ = '*', *p++ = ',';
2175 else
2177 OTF_tag_name (spec->features[i][j], p);
2178 p[4] = ',';
2179 p += 5;
2182 *--p = '\0';
2186 setup_otf_gstring (len);
2187 for (i = 0; i < len; i++)
2189 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2190 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2193 OTF_drive_gdef (otf, &otf_gstring);
2194 gidx = out->used;
2196 if (gsub_features)
2198 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2199 < 0)
2200 goto simple_copy;
2201 if (out->allocated < out->used + otf_gstring.used)
2202 return -2;
2203 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2205 MFLTGlyph *g;
2206 int min_from, max_to;
2207 int j;
2209 g = out->glyphs + out->used;
2210 *g = in->glyphs[from + otfg->f.index.from];
2211 if (g->code != otfg->glyph_id)
2213 g->c = 0;
2214 g->code = otfg->glyph_id;
2215 g->measured = 0;
2217 out->used++;
2218 min_from = g->from;
2219 max_to = g->to;
2220 if (otfg->f.index.from < otfg->f.index.to)
2222 /* OTFG substitutes multiple glyphs in IN. */
2223 for (j = from + otfg->f.index.from + 1;
2224 j <= from + otfg->f.index.to; j++)
2226 if (min_from > in->glyphs[j].from)
2227 min_from = in->glyphs[j].from;
2228 if (max_to < in->glyphs[j].to)
2229 max_to = in->glyphs[j].to;
2231 g->from = min_from;
2232 g->to = max_to;
2234 for (i++, otfg++; (i < otf_gstring.used
2235 && otfg->f.index.from == otfg[-1].f.index.from);
2236 i++, otfg++)
2238 g = out->glyphs + out->used;
2239 *g = in->glyphs[from + otfg->f.index.to];
2240 if (g->code != otfg->glyph_id)
2242 g->c = 0;
2243 g->code = otfg->glyph_id;
2244 g->measured = 0;
2246 out->used++;
2250 else
2252 if (out->allocated < out->used + len)
2253 return -2;
2254 for (i = 0; i < len; i++)
2255 out->glyphs[out->used++] = in->glyphs[from + i];
2258 if (gpos_features)
2260 MFLTGlyph *base = NULL, *mark = NULL, *g;
2261 int x_ppem, y_ppem, x_scale, y_scale;
2263 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2264 < 0)
2265 return to;
2267 x_ppem = ft_face->size->metrics.x_ppem;
2268 y_ppem = ft_face->size->metrics.y_ppem;
2269 x_scale = ft_face->size->metrics.x_scale;
2270 y_scale = ft_face->size->metrics.y_scale;
2272 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2273 i < otf_gstring.used; i++, otfg++, g++)
2275 MFLTGlyph *prev;
2277 if (! otfg->glyph_id)
2278 continue;
2279 switch (otfg->positioning_type)
2281 case 0:
2282 break;
2283 case 1: /* Single */
2284 case 2: /* Pair */
2286 int format = otfg->f.f1.format;
2288 if (format & OTF_XPlacement)
2289 adjustment[i].xoff
2290 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2291 if (format & OTF_XPlaDevice)
2292 adjustment[i].xoff
2293 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2294 if (format & OTF_YPlacement)
2295 adjustment[i].yoff
2296 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2297 if (format & OTF_YPlaDevice)
2298 adjustment[i].yoff
2299 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2300 if (format & OTF_XAdvance)
2301 adjustment[i].xadv
2302 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2303 if (format & OTF_XAdvDevice)
2304 adjustment[i].xadv
2305 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2306 if (format & OTF_YAdvance)
2307 adjustment[i].yadv
2308 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2309 if (format & OTF_YAdvDevice)
2310 adjustment[i].yadv
2311 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2312 adjustment[i].set = 1;
2314 break;
2315 case 3: /* Cursive */
2316 /* Not yet supported. */
2317 break;
2318 case 4: /* Mark-to-Base */
2319 case 5: /* Mark-to-Ligature */
2320 if (! base)
2321 break;
2322 prev = base;
2323 goto label_adjust_anchor;
2324 default: /* i.e. case 6 Mark-to-Mark */
2325 if (! mark)
2326 break;
2327 prev = mark;
2329 label_adjust_anchor:
2331 int base_x, base_y, mark_x, mark_y;
2332 int this_from, this_to;
2334 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2335 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2336 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2337 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2339 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2340 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2341 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2342 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2343 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2344 x_ppem, y_ppem, &mark_x, &mark_y);
2345 adjustment[i].xoff = (base_x - mark_x);
2346 adjustment[i].yoff = - (base_y - mark_y);
2347 adjustment[i].back = (g - prev);
2348 adjustment[i].xadv = 0;
2349 adjustment[i].advance_is_absolute = 1;
2350 adjustment[i].set = 1;
2351 this_from = g->from;
2352 this_to = g->to;
2353 for (j = 0; prev + j < g; j++)
2355 if (this_from > prev[j].from)
2356 this_from = prev[j].from;
2357 if (this_to < prev[j].to)
2358 this_to = prev[j].to;
2360 for (; prev <= g; prev++)
2362 prev->from = this_from;
2363 prev->to = this_to;
2367 if (otfg->GlyphClass == OTF_GlyphClass0)
2368 base = mark = g;
2369 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2370 mark = g;
2371 else
2372 base = g;
2375 return to;
2377 simple_copy:
2378 if (out->allocated < out->used + len)
2379 return -2;
2380 font->get_metrics (font, in, from, to);
2381 memcpy (out->glyphs + out->used, in->glyphs + from,
2382 sizeof (MFLTGlyph) * len);
2383 out->used += len;
2384 return to;
2387 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2389 static MFLTGlyphString gstring;
2391 static int m17n_flt_initialized;
2393 static Lisp_Object
2394 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2395 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2397 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2398 ptrdiff_t i;
2399 struct MFLTFontFT flt_font_ft;
2400 MFLT *flt = NULL;
2401 int with_variation_selector = 0;
2403 if (! m17n_flt_initialized)
2405 M17N_INIT ();
2406 #ifdef M17N_FLT_USE_NEW_FEATURE
2407 mflt_enable_new_feature = 1;
2408 mflt_try_otf = ftfont_try_otf;
2409 #endif /* M17N_FLT_USE_NEW_FEATURE */
2410 m17n_flt_initialized = 1;
2413 for (i = 0; i < len; i++)
2415 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2416 int c;
2418 if (NILP (g))
2419 break;
2420 c = LGLYPH_CHAR (g);
2421 if (CHAR_VARIATION_SELECTOR_P (c))
2422 with_variation_selector++;
2425 len = i;
2426 lint_assume (len <= STRING_BYTES_BOUND);
2428 if (with_variation_selector)
2430 setup_otf_gstring (len);
2431 for (i = 0; i < len; i++)
2433 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2435 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2436 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2437 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2439 OTF_drive_cmap (otf, &otf_gstring);
2440 for (i = 0; i < otf_gstring.used; i++)
2442 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2443 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2444 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2446 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2447 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2448 LGSTRING_SET_GLYPH (lgstring, i, g0);
2450 if (len > otf_gstring.used)
2452 len = otf_gstring.used;
2453 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2457 if (INT_MAX / 2 < len)
2458 memory_full (SIZE_MAX);
2460 if (gstring.allocated == 0)
2462 gstring.glyph_size = sizeof (MFLTGlyph);
2463 gstring.glyphs = xnmalloc (len * 2, sizeof (MFLTGlyph));
2464 gstring.allocated = len * 2;
2466 else if (gstring.allocated < len * 2)
2468 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2, sizeof (MFLTGlyph));
2469 gstring.allocated = len * 2;
2471 memset (gstring.glyphs, 0, sizeof (MFLTGlyph) * len);
2472 for (i = 0; i < len; i++)
2474 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2476 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2477 if (with_variation_selector)
2479 gstring.glyphs[i].code = LGLYPH_CODE (g);
2480 gstring.glyphs[i].encoded = 1;
2484 gstring.used = len;
2485 gstring.r2l = 0;
2488 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2490 if (NILP (family))
2491 flt_font_ft.flt_font.family = Mnil;
2492 else
2493 flt_font_ft.flt_font.family
2494 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2496 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2497 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2498 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2499 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2500 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2501 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2502 flt_font_ft.flt_font.internal = NULL;
2503 flt_font_ft.font = font;
2504 flt_font_ft.ft_face = ft_face;
2505 flt_font_ft.otf = otf;
2506 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2507 if (len > 1
2508 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2509 /* A little bit ad hoc. Perhaps, shaper must get script and
2510 language information, and select a proper flt for them
2511 here. */
2512 flt = mflt_get (msymbol ("combining"));
2513 for (i = 0; i < 3; i++)
2515 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2516 if (result != -2)
2517 break;
2518 if (INT_MAX / 2 < gstring.allocated)
2519 memory_full (SIZE_MAX);
2520 gstring.glyphs = xnrealloc (gstring.glyphs,
2521 gstring.allocated, 2 * sizeof (MFLTGlyph));
2522 gstring.allocated *= 2;
2524 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2525 return Qnil;
2526 for (i = 0; i < gstring.used; i++)
2528 MFLTGlyph *g = gstring.glyphs + i;
2530 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2531 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2534 for (i = 0; i < gstring.used; i++)
2536 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2537 MFLTGlyph *g = gstring.glyphs + i;
2539 if (NILP (lglyph))
2541 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2542 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2544 LGLYPH_SET_FROM (lglyph, g->from);
2545 LGLYPH_SET_TO (lglyph, g->to);
2546 LGLYPH_SET_CHAR (lglyph, g->c);
2547 LGLYPH_SET_CODE (lglyph, g->code);
2548 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2549 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2550 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2551 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2552 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2553 if (g->adjusted)
2555 Lisp_Object vec;
2557 vec = Fmake_vector (make_number (3), Qnil);
2558 ASET (vec, 0, make_number (g->xoff >> 6));
2559 ASET (vec, 1, make_number (g->yoff >> 6));
2560 ASET (vec, 2, make_number (g->xadv >> 6));
2561 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2564 return make_number (i);
2567 Lisp_Object
2568 ftfont_shape (Lisp_Object lgstring)
2570 struct font *font;
2571 struct ftfont_info *ftfont_info;
2572 OTF *otf;
2574 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2575 ftfont_info = (struct ftfont_info *) font;
2576 otf = ftfont_get_otf (ftfont_info);
2577 if (! otf)
2578 return make_number (0);
2579 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2580 &ftfont_info->matrix);
2583 #endif /* HAVE_M17N_FLT */
2585 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2587 static int
2588 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2590 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2591 OTF *otf = ftfont_get_otf (ftfont_info);
2593 if (! otf)
2594 return 0;
2595 return OTF_get_variation_glyphs (otf, c, variations);
2598 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2599 #endif /* HAVE_LIBOTF */
2601 Lisp_Object
2602 ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
2604 FcChar8 *str;
2606 #ifdef FC_FONTFORMAT
2607 if (pattern)
2609 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2610 return Qnil;
2611 if (strcmp ((char *) str, "TrueType") == 0)
2612 return intern ("truetype");
2613 if (strcmp ((char *) str, "Type 1") == 0)
2614 return intern ("type1");
2615 if (strcmp ((char *) str, "PCF") == 0)
2616 return intern ("pcf");
2617 if (strcmp ((char *) str, "BDF") == 0)
2618 return intern ("bdf");
2620 #endif /* FC_FONTFORMAT */
2621 if (STRINGP (filename))
2623 int len = SBYTES (filename);
2625 if (len >= 4)
2627 str = (FcChar8 *) (SDATA (filename) + len - 4);
2628 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2629 return intern ("truetype");
2630 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2631 return intern ("type1");
2632 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2633 return intern ("pcf");
2634 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2635 return intern ("bdf");
2638 return intern ("unknown");
2641 static const char *const ftfont_booleans [] = {
2642 ":antialias",
2643 ":hinting",
2644 ":verticallayout",
2645 ":autohint",
2646 ":globaladvance",
2647 ":outline",
2648 ":scalable",
2649 ":minspace",
2650 ":embolden",
2651 NULL,
2654 static const char *const ftfont_non_booleans [] = {
2655 ":family",
2656 ":familylang",
2657 ":style",
2658 ":stylelang",
2659 ":fullname",
2660 ":fullnamelang",
2661 ":slant",
2662 ":weight",
2663 ":size",
2664 ":width",
2665 ":aspect",
2666 ":pixelsize",
2667 ":spacing",
2668 ":foundry",
2669 ":hintstyle",
2670 ":file",
2671 ":index",
2672 ":ftface",
2673 ":rasterizer",
2674 ":scale",
2675 ":dpi",
2676 ":rgba",
2677 ":lcdfilter",
2678 ":charset",
2679 ":lang",
2680 ":fontversion",
2681 ":capability",
2682 NULL,
2685 static void
2686 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2688 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2692 void
2693 syms_of_ftfont (void)
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);