; doc/emacs/misc.texi (Network Security): Fix typo.
[emacs.git] / src / ftfont.c
blobd50fa39fa7bde6ac82344cf12c9975bccad316d4
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2018 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 (at
12 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 <https://www.gnu.org/licenses/>. */
22 #include <config.h>
23 #include <stdio.h>
24 #include <fontconfig/fontconfig.h>
25 #include <fontconfig/fcfreetype.h>
27 #include <c-strcase.h>
29 #include "lisp.h"
30 #include "dispextern.h"
31 #include "character.h"
32 #include "charset.h"
33 #include "category.h"
34 #include "composite.h"
35 #include "font.h"
36 #include "ftfont.h"
38 static struct font_driver const ftfont_driver;
40 /* Flag to tell if FcInit is already called or not. */
41 static bool fc_initialized;
43 /* Handle to a FreeType library instance. */
44 static FT_Library ft_library;
46 /* Cache for FreeType fonts. */
47 static Lisp_Object freetype_font_cache;
49 /* Cache for FT_Face and FcCharSet. */
50 static Lisp_Object ft_face_cache;
52 /* The actual structure for FreeType font that can be cast to struct
53 font. */
55 struct ftfont_info
57 struct font font;
58 #ifdef HAVE_LIBOTF
59 /* The following four members must be here in this order to be
60 compatible with struct xftfont_info (in xftfont.c). */
61 bool maybe_otf; /* Flag to tell if this may be OTF or not. */
62 OTF *otf;
63 #endif /* HAVE_LIBOTF */
64 FT_Size ft_size;
65 int index;
66 FT_Matrix matrix;
69 size_t ftfont_info_size = sizeof (struct ftfont_info);
71 enum ftfont_cache_for
73 FTFONT_CACHE_FOR_FACE,
74 FTFONT_CACHE_FOR_CHARSET,
75 FTFONT_CACHE_FOR_ENTITY
78 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
79 enum ftfont_cache_for);
81 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
83 static struct
85 /* registry name */
86 const char *name;
87 /* characters to distinguish the charset from the others */
88 int uniquifier[6];
89 /* additional constraint by language */
90 const char *lang;
91 /* set on demand */
92 FcCharSet *fc_charset;
93 } fc_charset_table[] =
94 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
95 { "iso8859-2", { 0x00A0, 0x010E }},
96 { "iso8859-3", { 0x00A0, 0x0108 }},
97 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
98 { "iso8859-5", { 0x00A0, 0x0401 }},
99 { "iso8859-6", { 0x00A0, 0x060C }},
100 { "iso8859-7", { 0x00A0, 0x0384 }},
101 { "iso8859-8", { 0x00A0, 0x05D0 }},
102 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
103 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
104 { "iso8859-11", { 0x00A0, 0x0E01 }},
105 { "iso8859-13", { 0x00A0, 0x201C }},
106 { "iso8859-14", { 0x00A0, 0x0174 }},
107 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
108 { "iso8859-16", { 0x00A0, 0x0218}},
109 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
110 { "big5-0", { 0xF6B1 }, "zh-tw" },
111 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
112 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
113 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
114 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
115 { "cns11643.1992-3", { 0x201A9 }},
116 { "cns11643.1992-4", { 0x20057 }},
117 { "cns11643.1992-5", { 0x20000 }},
118 { "cns11643.1992-6", { 0x20003 }},
119 { "cns11643.1992-7", { 0x20055 }},
120 { "gbk-0", { 0x4E06 }, "zh-cn"},
121 { "jisx0212.1990-0", { 0x4E44 }},
122 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
123 { "jisx0213.2000-2", { 0xFA49 }},
124 { "jisx0213.2004-1", { 0x20B9F }},
125 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
126 { "tis620.2529-1", { 0x0E01 }, "th"},
127 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
128 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
129 { "mulelao-1", { 0x0E81 }, "lo"},
130 { "unicode-sip", { 0x20000 }},
131 { NULL }
134 static bool
135 matching_prefix (char const *str, ptrdiff_t len, char const *pat)
137 return len == strlen (pat) && c_strncasecmp (str, pat, len) == 0;
140 /* Dirty hack for handing ADSTYLE property.
142 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
143 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
144 "Oblique", "Italic", or any non-normal SWIDTH property names
145 (e.g. SemiCondensed) are appended. In addition, if there's no
146 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
147 "Regular" is used for FC_STYLE (see the function
148 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
150 Unfortunately this behavior is not documented, so the following
151 code may fail if FreeType changes the behavior in the future. */
153 static Lisp_Object
154 get_adstyle_property (FcPattern *p)
156 FcChar8 *fcstr;
157 char *str, *end;
158 Lisp_Object adstyle;
160 #ifdef FC_FONTFORMAT
161 if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
162 && xstrcasecmp ((char *) fcstr, "bdf") != 0
163 && xstrcasecmp ((char *) fcstr, "pcf") != 0)
164 /* Not a BDF nor PCF font. */
165 return Qnil;
166 #endif
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 (matching_prefix (str, end - str, "Regular")
172 || matching_prefix (str, end - str, "Bold")
173 || matching_prefix (str, end - str, "Oblique")
174 || matching_prefix (str, end - str, "Italic"))
175 return Qnil;
176 adstyle = font_intern_prop (str, end - str, 1);
177 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
178 return Qnil;
179 return adstyle;
182 static Lisp_Object
183 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
185 Lisp_Object key, cache, entity;
186 FcChar8 *str;
187 char *file;
188 int idx;
189 int numeric;
190 double dbl;
191 FcBool b;
193 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
194 return Qnil;
195 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
196 return Qnil;
198 file = (char *) str;
199 key = Fcons (build_unibyte_string (file), make_number (idx));
200 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
201 entity = XCAR (cache);
202 if (! NILP (entity))
204 Lisp_Object val = font_make_entity ();
205 int i;
207 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
208 ASET (val, i, AREF (entity, i));
210 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
211 font_put_extra (val, QCfont_entity, key);
213 return val;
215 entity = font_make_entity ();
216 XSETCAR (cache, entity);
218 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
219 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
221 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
223 char *s = (char *) str;
224 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
226 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
228 char *s = (char *) str;
229 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
231 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
233 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
234 numeric = FC_WEIGHT_MEDIUM;
235 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
237 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
239 numeric += 100;
240 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
242 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
244 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
246 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
248 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
250 else
251 ASET (entity, FONT_SIZE_INDEX, make_number (0));
252 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
253 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
254 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
256 int dpi = dbl;
257 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
259 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
260 && b == FcTrue)
262 ASET (entity, FONT_SIZE_INDEX, make_number (0));
263 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
265 else
267 /* As this font is not scalable, perhaps this is a BDF or PCF
268 font. */
269 FT_Face ft_face;
271 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
272 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
273 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
275 BDF_PropertyRec rec;
277 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
278 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
279 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
280 FT_Done_Face (ft_face);
284 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
285 font_put_extra (entity, QCfont_entity, key);
286 return entity;
290 static Lisp_Object ftfont_generic_family_list;
292 static Lisp_Object
293 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
295 Lisp_Object slot;
296 FcPattern *match;
297 FcResult result;
298 FcLangSet *langset;
300 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
301 if (EQ (family, Qmono))
302 family = Qmonospace;
303 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
304 family = Qsans_serif;
305 slot = assq_no_quit (family, ftfont_generic_family_list);
306 if (! CONSP (slot))
307 return Qnil;
308 if (! EQ (XCDR (slot), Qt))
309 return XCDR (slot);
310 pattern = FcPatternDuplicate (pattern);
311 if (! pattern)
312 goto err;
313 FcPatternDel (pattern, FC_FOUNDRY);
314 FcPatternDel (pattern, FC_FAMILY);
315 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
316 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
318 /* This is to avoid the effect of locale. */
319 static const FcChar8 lang[] = "en";
320 langset = FcLangSetCreate ();
321 FcLangSetAdd (langset, lang);
322 FcPatternAddLangSet (pattern, FC_LANG, langset);
323 FcLangSetDestroy (langset);
325 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
326 FcDefaultSubstitute (pattern);
327 match = FcFontMatch (NULL, pattern, &result);
328 if (match)
330 FcChar8 *fam;
332 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
333 family = intern ((char *) fam);
335 else
336 family = Qnil;
337 XSETCDR (slot, family);
338 if (match) FcPatternDestroy (match);
339 err:
340 if (pattern) FcPatternDestroy (pattern);
341 return family;
344 struct ftfont_cache_data
346 FT_Face ft_face;
347 FcCharSet *fc_charset;
348 intptr_t face_refcount;
351 static Lisp_Object
352 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
354 Lisp_Object cache, val, entity;
355 struct ftfont_cache_data *cache_data;
357 if (FONT_ENTITY_P (key))
359 entity = key;
360 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
361 eassert (CONSP (val));
362 key = XCDR (val);
364 else
365 entity = Qnil;
367 if (NILP (ft_face_cache))
368 cache = Qnil;
369 else
370 cache = Fgethash (key, ft_face_cache, Qnil);
371 if (NILP (cache))
373 if (NILP (ft_face_cache))
374 ft_face_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
375 cache_data = xzalloc (sizeof *cache_data);
376 val = make_mint_ptr (cache_data);
377 cache = Fcons (Qnil, val);
378 Fputhash (key, cache, ft_face_cache);
380 else
382 val = XCDR (cache);
383 cache_data = xmint_pointer (val);
386 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
387 return cache;
389 if (cache_for == FTFONT_CACHE_FOR_FACE
390 ? ! cache_data->ft_face : ! cache_data->fc_charset)
392 char *filename = SSDATA (XCAR (key));
393 int idx = XINT (XCDR (key));
395 if (cache_for == FTFONT_CACHE_FOR_FACE)
397 if (! ft_library
398 && FT_Init_FreeType (&ft_library) != 0)
399 return Qnil;
400 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
401 != 0)
402 return Qnil;
404 else
406 FcPattern *pat = NULL;
407 FcFontSet *fontset = NULL;
408 FcObjectSet *objset = NULL;
409 FcCharSet *charset = NULL;
411 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
412 FC_INDEX, FcTypeInteger, idx, NULL);
413 if (! pat)
414 goto finish;
415 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
416 if (! objset)
417 goto finish;
418 fontset = FcFontList (NULL, pat, objset);
419 if (! fontset)
420 goto finish;
421 if (fontset && fontset->nfont > 0
422 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
423 &charset)
424 == FcResultMatch))
425 cache_data->fc_charset = FcCharSetCopy (charset);
426 else
427 cache_data->fc_charset = FcCharSetCreate ();
429 finish:
430 if (fontset)
431 FcFontSetDestroy (fontset);
432 if (objset)
433 FcObjectSetDestroy (objset);
434 if (pat)
435 FcPatternDestroy (pat);
438 return cache;
441 FcCharSet *
442 ftfont_get_fc_charset (Lisp_Object entity)
444 Lisp_Object val, cache;
445 struct ftfont_cache_data *cache_data;
447 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
448 val = XCDR (cache);
449 cache_data = xmint_pointer (val);
450 return cache_data->fc_charset;
453 #ifdef HAVE_LIBOTF
454 static OTF *
455 ftfont_get_otf (struct ftfont_info *ftfont_info)
457 OTF *otf;
459 if (ftfont_info->otf)
460 return ftfont_info->otf;
461 if (! ftfont_info->maybe_otf)
462 return NULL;
463 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
464 if (! otf || OTF_get_table (otf, "head") < 0)
466 if (otf)
467 OTF_close (otf);
468 ftfont_info->maybe_otf = 0;
469 return NULL;
471 ftfont_info->otf = otf;
472 return otf;
474 #endif /* HAVE_LIBOTF */
476 Lisp_Object
477 ftfont_get_cache (struct frame *f)
479 return freetype_font_cache;
482 static int
483 ftfont_get_charset (Lisp_Object registry)
485 char *str = SSDATA (SYMBOL_NAME (registry));
486 USE_SAFE_ALLOCA;
487 char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
488 int i, j;
490 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
492 if (str[i] == '.')
493 re[j++] = '\\';
494 else if (str[i] == '*')
495 re[j++] = '.';
496 re[j] = str[i];
497 if (re[j] == '?')
498 re[j] = '.';
500 re[j] = '\0';
501 AUTO_STRING_WITH_LEN (regexp, re, j);
502 for (i = 0; fc_charset_table[i].name; i++)
503 if (fast_c_string_match_ignore_case
504 (regexp, fc_charset_table[i].name,
505 strlen (fc_charset_table[i].name)) >= 0)
506 break;
507 SAFE_FREE ();
508 if (! fc_charset_table[i].name)
509 return -1;
510 if (! fc_charset_table[i].fc_charset)
512 FcCharSet *charset = FcCharSetCreate ();
513 int *uniquifier = fc_charset_table[i].uniquifier;
515 if (! charset)
516 return -1;
517 for (j = 0; uniquifier[j]; j++)
518 if (! FcCharSetAddChar (charset, uniquifier[j]))
520 FcCharSetDestroy (charset);
521 return -1;
523 fc_charset_table[i].fc_charset = charset;
525 return i;
528 struct OpenTypeSpec
530 Lisp_Object script;
531 unsigned int script_tag, langsys_tag;
532 int nfeatures[2];
533 unsigned int *features[2];
536 #define OTF_SYM_TAG(SYM, TAG) \
537 do { \
538 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
539 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
540 } while (0)
542 #define OTF_TAG_STR(TAG, P) \
543 do { \
544 (P)[0] = (char) (TAG >> 24); \
545 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
546 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
547 (P)[3] = (char) (TAG & 0xFF); \
548 (P)[4] = '\0'; \
549 } while (0)
551 #ifdef HAVE_LIBOTF
552 #define OTF_TAG_SYM(SYM, TAG) \
553 do { \
554 char str[5]; \
556 OTF_TAG_STR (TAG, str); \
557 (SYM) = font_intern_prop (str, 4, 1); \
558 } while (0)
559 #endif
562 static struct OpenTypeSpec *
563 ftfont_get_open_type_spec (Lisp_Object otf_spec)
565 struct OpenTypeSpec *spec = malloc (sizeof *spec);
566 Lisp_Object val;
567 int i, j;
568 bool negative;
570 if (! spec)
571 return NULL;
572 spec->script = XCAR (otf_spec);
573 if (! NILP (spec->script))
575 OTF_SYM_TAG (spec->script, spec->script_tag);
576 val = assq_no_quit (spec->script, Votf_script_alist);
577 if (CONSP (val) && SYMBOLP (XCDR (val)))
578 spec->script = XCDR (val);
579 else
580 spec->script = Qnil;
582 else
583 spec->script_tag = 0x44464C54; /* "DFLT" */
584 otf_spec = XCDR (otf_spec);
585 spec->langsys_tag = 0;
586 if (! NILP (otf_spec))
588 val = XCAR (otf_spec);
589 if (! NILP (val))
590 OTF_SYM_TAG (val, spec->langsys_tag);
591 otf_spec = XCDR (otf_spec);
593 spec->nfeatures[0] = spec->nfeatures[1] = 0;
594 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
596 Lisp_Object len;
598 val = XCAR (otf_spec);
599 if (NILP (val))
600 continue;
601 len = Flength (val);
602 spec->features[i] =
603 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
605 : malloc (XINT (len) * sizeof *spec->features[i]));
606 if (! spec->features[i])
608 if (i > 0 && spec->features[0])
609 free (spec->features[0]);
610 free (spec);
611 return NULL;
613 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
615 if (NILP (XCAR (val)))
616 negative = 1;
617 else
619 unsigned int tag;
621 OTF_SYM_TAG (XCAR (val), tag);
622 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
625 spec->nfeatures[i] = j;
627 return spec;
630 static FcPattern *
631 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
633 Lisp_Object tmp, extra;
634 FcPattern *pattern = NULL;
635 FcCharSet *charset = NULL;
636 FcLangSet *langset = NULL;
637 int n;
638 int dpi = -1;
639 int scalable = -1;
640 Lisp_Object script = Qnil;
641 Lisp_Object registry;
642 int fc_charset_idx;
644 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
645 && n < 100)
646 /* Fontconfig doesn't support reverse-italic/oblique. */
647 return NULL;
649 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
650 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
651 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
652 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
653 scalable = 1;
655 registry = AREF (spec, FONT_REGISTRY_INDEX);
656 if (NILP (registry)
657 || EQ (registry, Qascii_0)
658 || EQ (registry, Qiso10646_1)
659 || EQ (registry, Qunicode_bmp))
660 fc_charset_idx = -1;
661 else
663 FcChar8 *lang;
665 fc_charset_idx = ftfont_get_charset (registry);
666 if (fc_charset_idx < 0)
667 return NULL;
668 charset = fc_charset_table[fc_charset_idx].fc_charset;
669 *langname = fc_charset_table[fc_charset_idx].lang;
670 lang = (FcChar8 *) *langname;
671 if (lang)
673 langset = FcLangSetCreate ();
674 if (! langset)
675 goto err;
676 FcLangSetAdd (langset, lang);
680 otlayout[0] = '\0';
681 for (extra = AREF (spec, FONT_EXTRA_INDEX);
682 CONSP (extra); extra = XCDR (extra))
684 Lisp_Object key, val;
686 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
687 if (EQ (key, QCdpi))
689 if (INTEGERP (val))
690 dpi = XINT (val);
692 else if (EQ (key, QClang))
694 if (! langset)
695 langset = FcLangSetCreate ();
696 if (! langset)
697 goto err;
698 if (SYMBOLP (val))
700 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
701 goto err;
703 else
704 for (; CONSP (val); val = XCDR (val))
705 if (SYMBOLP (XCAR (val))
706 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
707 goto err;
709 else if (EQ (key, QCotf))
711 if (CONSP (val))
713 *otspec = ftfont_get_open_type_spec (val);
714 if (! *otspec)
715 return NULL;
716 strcpy (otlayout, "otlayout:");
717 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
718 script = (*otspec)->script;
721 else if (EQ (key, QCscript))
722 script = val;
723 else if (EQ (key, QCscalable))
724 scalable = ! NILP (val);
727 if (! NILP (script) && ! charset)
729 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
731 if (CONSP (chars) && CONSP (CDR (chars)))
733 charset = FcCharSetCreate ();
734 if (! charset)
735 goto err;
736 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
737 if (CHARACTERP (XCAR (chars))
738 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
739 goto err;
743 pattern = FcPatternCreate ();
744 if (! pattern)
745 goto err;
746 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
747 if (! NILP (tmp)
748 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
749 goto err;
750 tmp = AREF (spec, FONT_FAMILY_INDEX);
751 if (! NILP (tmp)
752 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
753 goto err;
754 if (charset
755 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
756 goto err;
757 if (langset
758 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
759 goto err;
760 if (dpi >= 0
761 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
762 goto err;
763 if (scalable >= 0
764 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
765 goto err;
766 #if defined HAVE_XFT && defined FC_COLOR
767 /* We really don't like color fonts, they cause Xft crashes. See
768 Bug#30874. */
769 if (Vxft_ignore_color_fonts
770 && ! FcPatternAddBool (pattern, FC_COLOR, FcFalse))
771 goto err;
772 #endif
774 goto finish;
776 err:
777 /* We come here because of unexpected error in fontconfig API call
778 (usually insufficient memory). */
779 if (pattern)
781 FcPatternDestroy (pattern);
782 pattern = NULL;
784 if (*otspec)
786 if ((*otspec)->nfeatures[0] > 0)
787 free ((*otspec)->features[0]);
788 if ((*otspec)->nfeatures[1] > 0)
789 free ((*otspec)->features[1]);
790 free (*otspec);
791 *otspec = NULL;
794 finish:
795 if (langset) FcLangSetDestroy (langset);
796 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
797 return pattern;
800 Lisp_Object
801 ftfont_list (struct frame *f, Lisp_Object spec)
803 Lisp_Object val = Qnil, family, adstyle;
804 int i;
805 FcPattern *pattern;
806 FcFontSet *fontset = NULL;
807 FcObjectSet *objset = NULL;
808 FcCharSet *charset;
809 Lisp_Object chars = Qnil;
810 char otlayout[15]; /* For "otlayout:XXXX" */
811 struct OpenTypeSpec *otspec = NULL;
812 int spacing = -1;
813 const char *langname = NULL;
815 if (! fc_initialized)
817 FcInit ();
818 fc_initialized = 1;
821 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
822 if (! pattern)
823 return Qnil;
824 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
826 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
827 if (! NILP (val))
829 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
830 if (CONSP (val) && VECTORP (XCDR (val)))
831 chars = XCDR (val);
833 val = Qnil;
835 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
836 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
837 family = AREF (spec, FONT_FAMILY_INDEX);
838 if (! NILP (family))
840 Lisp_Object resolved;
842 resolved = ftfont_resolve_generic_family (family, pattern);
843 if (! NILP (resolved))
845 FcPatternDel (pattern, FC_FAMILY);
846 if (! FcPatternAddString (pattern, FC_FAMILY,
847 SYMBOL_FcChar8 (resolved)))
848 goto err;
851 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
852 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
853 adstyle = Qnil;
854 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
855 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
856 FC_STYLE, FC_FILE, FC_INDEX,
857 #ifdef FC_CAPABILITY
858 FC_CAPABILITY,
859 #endif /* FC_CAPABILITY */
860 #ifdef FC_FONTFORMAT
861 FC_FONTFORMAT,
862 #endif
863 NULL);
864 if (! objset)
865 goto err;
866 if (! NILP (chars))
867 FcObjectSetAdd (objset, FC_CHARSET);
869 fontset = FcFontList (NULL, pattern, objset);
870 if (! fontset || fontset->nfont == 0)
871 goto finish;
872 #if 0
873 /* Need fix because this finds any fonts. */
874 if (fontset->nfont == 0 && ! NILP (family))
876 /* Try matching with configuration. For instance, the
877 configuration may specify "Nimbus Mono L" as an alias of
878 "Courier". */
879 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
880 SYMBOL_FcChar8 (family), NULL);
881 FcChar8 *fam;
883 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
885 for (i = 0;
886 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
887 i++)
889 FcPatternDel (pattern, FC_FAMILY);
890 FcPatternAddString (pattern, FC_FAMILY, fam);
891 FcFontSetDestroy (fontset);
892 fontset = FcFontList (NULL, pattern, objset);
893 if (fontset && fontset->nfont > 0)
894 break;
898 #endif
899 for (i = 0; i < fontset->nfont; i++)
901 Lisp_Object entity;
903 if (spacing >= 0)
905 int this;
907 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
908 == FcResultMatch)
909 && spacing != this)
910 continue;
913 #ifdef FC_CAPABILITY
914 if (otlayout[0])
916 FcChar8 *this;
918 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
919 != FcResultMatch
920 || ! strstr ((char *) this, otlayout))
921 continue;
923 #endif /* FC_CAPABILITY */
924 #ifdef HAVE_LIBOTF
925 if (otspec)
927 FcChar8 *file;
928 bool passed;
929 OTF *otf;
931 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
932 != FcResultMatch)
933 continue;
934 otf = OTF_open ((char *) file);
935 if (! otf)
936 continue;
937 passed = (OTF_check_features (otf, 1, otspec->script_tag,
938 otspec->langsys_tag,
939 otspec->features[0],
940 otspec->nfeatures[0]) == 1
941 && OTF_check_features (otf, 0, otspec->script_tag,
942 otspec->langsys_tag,
943 otspec->features[1],
944 otspec->nfeatures[1]) == 1);
945 OTF_close (otf);
946 if (!passed)
947 continue;
949 #endif /* HAVE_LIBOTF */
950 if (VECTORP (chars))
952 ptrdiff_t j;
954 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
955 != FcResultMatch)
956 continue;
957 for (j = 0; j < ASIZE (chars); j++)
958 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
959 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
960 break;
961 if (j == ASIZE (chars))
962 continue;
964 if (! NILP (adstyle) || langname)
966 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
968 if (! NILP (adstyle)
969 && (NILP (this_adstyle)
970 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
971 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
972 continue;
973 if (langname
974 && ! NILP (this_adstyle)
975 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
976 continue;
978 entity = ftfont_pattern_entity (fontset->fonts[i],
979 AREF (spec, FONT_EXTRA_INDEX));
980 if (! NILP (entity))
981 val = Fcons (entity, val);
983 val = Fnreverse (val);
984 goto finish;
986 err:
987 /* We come here because of unexpected error in fontconfig API call
988 (usually insufficient memory). */
989 val = Qnil;
991 finish:
992 FONT_ADD_LOG ("ftfont-list", spec, val);
993 if (objset) FcObjectSetDestroy (objset);
994 if (fontset) FcFontSetDestroy (fontset);
995 if (pattern) FcPatternDestroy (pattern);
996 return val;
999 Lisp_Object
1000 ftfont_match (struct frame *f, Lisp_Object spec)
1002 Lisp_Object entity = Qnil;
1003 FcPattern *pattern, *match = NULL;
1004 FcResult result;
1005 char otlayout[15]; /* For "otlayout:XXXX" */
1006 struct OpenTypeSpec *otspec = NULL;
1007 const char *langname = NULL;
1009 if (! fc_initialized)
1011 FcInit ();
1012 fc_initialized = 1;
1015 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1016 if (! pattern)
1017 return Qnil;
1019 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1021 FcValue value;
1023 value.type = FcTypeDouble;
1024 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1025 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1027 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1029 FcDefaultSubstitute (pattern);
1030 match = FcFontMatch (NULL, pattern, &result);
1031 if (match)
1033 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1034 FcPatternDestroy (match);
1035 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1036 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1037 ftfont_generic_family_list))
1038 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1039 AREF (entity, FONT_FAMILY_INDEX))))
1040 entity = Qnil;
1043 FcPatternDestroy (pattern);
1045 FONT_ADD_LOG ("ftfont-match", spec, entity);
1046 return entity;
1049 Lisp_Object
1050 ftfont_list_family (struct frame *f)
1052 Lisp_Object list = Qnil;
1053 FcPattern *pattern = NULL;
1054 FcFontSet *fontset = NULL;
1055 FcObjectSet *objset = NULL;
1056 int i;
1058 if (! fc_initialized)
1060 FcInit ();
1061 fc_initialized = 1;
1064 pattern = FcPatternCreate ();
1065 if (! pattern)
1066 goto finish;
1067 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1068 if (! objset)
1069 goto finish;
1070 fontset = FcFontList (NULL, pattern, objset);
1071 if (! fontset)
1072 goto finish;
1074 for (i = 0; i < fontset->nfont; i++)
1076 FcPattern *pat = fontset->fonts[i];
1077 FcChar8 *str;
1079 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1080 list = Fcons (intern ((char *) str), list);
1083 finish:
1084 if (objset) FcObjectSetDestroy (objset);
1085 if (fontset) FcFontSetDestroy (fontset);
1086 if (pattern) FcPatternDestroy (pattern);
1088 return list;
1092 Lisp_Object
1093 ftfont_open2 (struct frame *f,
1094 Lisp_Object entity,
1095 int pixel_size,
1096 Lisp_Object font_object)
1098 struct ftfont_info *ftfont_info;
1099 struct font *font;
1100 struct ftfont_cache_data *cache_data;
1101 FT_Face ft_face;
1102 FT_Size ft_size;
1103 FT_UInt size;
1104 Lisp_Object val, filename, idx, cache;
1105 bool scalable;
1106 int spacing;
1107 int i;
1108 double upEM;
1110 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1111 if (! CONSP (val))
1112 return Qnil;
1113 val = XCDR (val);
1114 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1115 if (NILP (cache))
1116 return Qnil;
1117 filename = XCAR (val);
1118 idx = XCDR (val);
1119 val = XCDR (cache);
1120 cache_data = xmint_pointer (XCDR (cache));
1121 ft_face = cache_data->ft_face;
1122 if (cache_data->face_refcount > 0)
1124 /* FT_Face in this cache is already used by the different size. */
1125 if (FT_New_Size (ft_face, &ft_size) != 0)
1126 return Qnil;
1127 if (FT_Activate_Size (ft_size) != 0)
1129 FT_Done_Size (ft_size);
1130 return Qnil;
1133 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1134 if (size == 0)
1135 size = pixel_size;
1136 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1138 if (cache_data->face_refcount == 0)
1140 FT_Done_Face (ft_face);
1141 cache_data->ft_face = NULL;
1143 return Qnil;
1145 cache_data->face_refcount++;
1147 ASET (font_object, FONT_FILE_INDEX, filename);
1148 font = XFONT_OBJECT (font_object);
1149 ftfont_info = (struct ftfont_info *) font;
1150 ftfont_info->ft_size = ft_face->size;
1151 ftfont_info->index = XINT (idx);
1152 #ifdef HAVE_LIBOTF
1153 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1154 ftfont_info->otf = NULL;
1155 #endif /* HAVE_LIBOTF */
1156 /* This means that there's no need of transformation. */
1157 ftfont_info->matrix.xx = 0;
1158 font->pixel_size = size;
1159 font->driver = &ftfont_driver;
1160 font->encoding_charset = font->repertory_charset = -1;
1162 upEM = ft_face->units_per_EM;
1163 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1164 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1165 if (scalable)
1167 font->ascent = ft_face->ascender * size / upEM + 0.5;
1168 font->descent = - ft_face->descender * size / upEM + 0.5;
1169 font->height = ft_face->height * size / upEM + 0.5;
1171 else
1173 font->ascent = ft_face->size->metrics.ascender >> 6;
1174 font->descent = - ft_face->size->metrics.descender >> 6;
1175 font->height = ft_face->size->metrics.height >> 6;
1177 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1178 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1179 else
1180 spacing = FC_PROPORTIONAL;
1181 if (spacing != FC_PROPORTIONAL
1182 #ifdef FC_DUAL
1183 && spacing != FC_DUAL
1184 #endif /* FC_DUAL */
1186 font->min_width = font->average_width = font->space_width
1187 = (scalable ? ft_face->max_advance_width * size / upEM + 0.5
1188 : ft_face->size->metrics.max_advance >> 6);
1189 else
1191 int n;
1193 font->min_width = font->average_width = font->space_width = 0;
1194 for (i = 32, n = 0; i < 127; i++)
1195 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1197 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1199 if (this_width > 0
1200 && (! font->min_width || font->min_width > this_width))
1201 font->min_width = this_width;
1202 if (i == 32)
1203 font->space_width = this_width;
1204 font->average_width += this_width;
1205 n++;
1207 if (n > 0)
1208 font->average_width /= n;
1211 font->baseline_offset = 0;
1212 font->relative_compose = 0;
1213 font->default_ascent = 0;
1214 font->vertical_centering = 0;
1215 if (scalable)
1217 font->underline_position = (-ft_face->underline_position * size / upEM
1218 + 0.5);
1219 font->underline_thickness = (ft_face->underline_thickness * size / upEM
1220 + 0.5);
1222 else
1224 font->underline_position = -1;
1225 font->underline_thickness = 0;
1228 return font_object;
1231 Lisp_Object
1232 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1234 Lisp_Object font_object;
1235 FT_UInt size;
1236 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1237 if (size == 0)
1238 size = pixel_size;
1239 font_object = font_build_object (VECSIZE (struct ftfont_info),
1240 Qfreetype, entity, size);
1241 return ftfont_open2 (f, entity, pixel_size, font_object);
1244 void
1245 ftfont_close (struct font *font)
1247 if (font_data_structures_may_be_ill_formed ())
1248 return;
1250 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1251 Lisp_Object val, cache;
1253 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1254 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1255 eassert (CONSP (cache));
1256 val = XCDR (cache);
1257 struct ftfont_cache_data *cache_data = xmint_pointer (val);
1258 cache_data->face_refcount--;
1259 if (cache_data->face_refcount == 0)
1261 FT_Done_Face (cache_data->ft_face);
1262 #ifdef HAVE_LIBOTF
1263 if (ftfont_info->otf)
1264 OTF_close (ftfont_info->otf);
1265 #endif
1266 cache_data->ft_face = NULL;
1268 else
1269 FT_Done_Size (ftfont_info->ft_size);
1273 ftfont_has_char (Lisp_Object font, int c)
1275 struct charset *cs = NULL;
1277 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1278 && charset_jisx0208 >= 0)
1279 cs = CHARSET_FROM_ID (charset_jisx0208);
1280 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1281 && charset_ksc5601 >= 0)
1282 cs = CHARSET_FROM_ID (charset_ksc5601);
1283 if (cs)
1284 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1286 if (FONT_ENTITY_P (font))
1288 FcCharSet *charset = ftfont_get_fc_charset (font);
1290 return (FcCharSetHasChar (charset, c) == FcTrue);
1292 else
1294 struct ftfont_info *ftfont_info;
1296 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1297 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1298 != 0);
1302 unsigned
1303 ftfont_encode_char (struct font *font, int c)
1305 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1306 FT_Face ft_face = ftfont_info->ft_size->face;
1307 FT_ULong charcode = c;
1308 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1310 return (code > 0 ? code : FONT_INVALID_CODE);
1313 void
1314 ftfont_text_extents (struct font *font, unsigned int *code,
1315 int nglyphs, struct font_metrics *metrics)
1317 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1318 FT_Face ft_face = ftfont_info->ft_size->face;
1319 int i, width = 0;
1320 bool first;
1322 if (ftfont_info->ft_size != ft_face->size)
1323 FT_Activate_Size (ftfont_info->ft_size);
1325 for (i = 0, first = 1; i < nglyphs; i++)
1327 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1329 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1331 if (first)
1333 metrics->lbearing = m->horiBearingX >> 6;
1334 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1335 metrics->ascent = m->horiBearingY >> 6;
1336 metrics->descent = (m->height - m->horiBearingY) >> 6;
1337 first = 0;
1339 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1340 metrics->lbearing = width + (m->horiBearingX >> 6);
1341 if (metrics->rbearing
1342 < width + ((m->horiBearingX + m->width) >> 6))
1343 metrics->rbearing
1344 = width + ((m->horiBearingX + m->width) >> 6);
1345 if (metrics->ascent < (m->horiBearingY >> 6))
1346 metrics->ascent = m->horiBearingY >> 6;
1347 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1348 metrics->descent = (m->height - m->horiBearingY) >> 6;
1349 width += m->horiAdvance >> 6;
1351 else
1352 width += font->space_width;
1354 metrics->width = width;
1358 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1360 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1361 FT_Face ft_face = ftfont_info->ft_size->face;
1362 FT_Int32 load_flags = FT_LOAD_RENDER;
1364 if (ftfont_info->ft_size != ft_face->size)
1365 FT_Activate_Size (ftfont_info->ft_size);
1366 if (bits_per_pixel == 1)
1368 #ifdef FT_LOAD_TARGET_MONO
1369 load_flags |= FT_LOAD_TARGET_MONO;
1370 #else
1371 load_flags |= FT_LOAD_MONOCHROME;
1372 #endif
1374 else if (bits_per_pixel != 8)
1375 /* We don't support such a rendering. */
1376 return -1;
1378 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1379 return -1;
1380 bitmap->bits_per_pixel
1381 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1382 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1383 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1384 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1385 : -1);
1386 if (bitmap->bits_per_pixel < 0)
1387 /* We don't support that kind of pixel mode. */
1388 return -1;
1389 bitmap->rows = ft_face->glyph->bitmap.rows;
1390 bitmap->width = ft_face->glyph->bitmap.width;
1391 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1392 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1393 bitmap->left = ft_face->glyph->bitmap_left;
1394 bitmap->top = ft_face->glyph->bitmap_top;
1395 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1397 return 0;
1401 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1402 int *x, int *y)
1404 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1405 FT_Face ft_face = ftfont_info->ft_size->face;
1407 if (ftfont_info->ft_size != ft_face->size)
1408 FT_Activate_Size (ftfont_info->ft_size);
1409 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1410 return -1;
1411 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1412 return -1;
1413 if (idx >= ft_face->glyph->outline.n_points)
1414 return -1;
1415 *x = ft_face->glyph->outline.points[idx].x;
1416 *y = ft_face->glyph->outline.points[idx].y;
1417 return 0;
1420 #ifdef HAVE_LIBOTF
1422 static Lisp_Object
1423 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1425 Lisp_Object scripts, langsyses, features, sym;
1426 int i, j, k, l;
1428 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1430 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1432 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1434 OTF_LangSys *otf_langsys;
1436 if (j >= 0)
1437 otf_langsys = otf_script->LangSys + j;
1438 else if (otf_script->DefaultLangSysOffset)
1439 otf_langsys = &otf_script->DefaultLangSys;
1440 else
1441 break;
1443 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1445 l = otf_langsys->FeatureIndex[k];
1446 if (l >= gsub_gpos->FeatureList.FeatureCount)
1447 continue;
1448 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1449 features = Fcons (sym, features);
1451 if (j >= 0)
1452 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1453 else
1454 sym = Qnil;
1455 langsyses = Fcons (Fcons (sym, features), langsyses);
1458 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1459 scripts = Fcons (Fcons (sym, langsyses), scripts);
1461 return scripts;
1466 Lisp_Object
1467 ftfont_otf_capability (struct font *font)
1469 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1470 OTF *otf = ftfont_get_otf (ftfont_info);
1471 Lisp_Object gsub_gpos;
1473 if (! otf)
1474 return Qnil;
1475 gsub_gpos = Fcons (Qnil, Qnil);
1476 if (OTF_get_table (otf, "GSUB") == 0
1477 && otf->gsub->FeatureList.FeatureCount > 0)
1478 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1479 if (OTF_get_table (otf, "GPOS") == 0
1480 && otf->gpos->FeatureList.FeatureCount > 0)
1481 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1482 return gsub_gpos;
1485 #ifdef HAVE_M17N_FLT
1487 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1488 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1489 /* We can use the new feature of libotf and m17n-flt to handle the
1490 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1491 some Agian scripts. */
1492 #define M17N_FLT_USE_NEW_FEATURE
1493 #endif
1495 struct MFLTFontFT
1497 MFLTFont flt_font;
1498 struct font *font;
1499 FT_Face ft_face;
1500 OTF *otf;
1501 FT_Matrix *matrix;
1504 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1505 We use this structure instead of MFLTGlyph to utilize the new
1506 feature of libotf ver.0.9.15 which requires saving and restoring
1507 the value of OTF_GlyphString.positioning_type in the succeeding
1508 calls of the callback function MFLTFont.drive_otf (which is set to
1509 ftfont_drive_otf). */
1511 typedef struct {
1512 MFLTGlyph g;
1513 unsigned int libotf_positioning_type;
1514 } MFLTGlyphFT;
1516 static int
1517 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1518 int from, int to)
1520 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1521 FT_Face ft_face = flt_font_ft->ft_face;
1522 MFLTGlyphFT *g;
1524 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1525 if (! g->g.encoded)
1527 FT_UInt code = FT_Get_Char_Index (ft_face, g->g.code);
1529 g->g.code = code > 0 ? code : FONT_INVALID_CODE;
1530 g->g.encoded = 1;
1532 return 0;
1535 /* Operators for 26.6 fixed fractional pixel format */
1537 #define FLOOR(x) ((x) & -64)
1538 #define CEIL(x) (((x)+63) & -64)
1539 #define ROUND(x) (((x)+32) & -64)
1541 static int
1542 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1543 int from, int to)
1545 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1546 FT_Face ft_face = flt_font_ft->ft_face;
1547 MFLTGlyphFT *g;
1549 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1550 if (! g->g.measured)
1552 if (g->g.code != FONT_INVALID_CODE)
1554 FT_Glyph_Metrics *m;
1556 if (FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_DEFAULT) != 0
1557 && FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_NO_HINTING) != 0)
1558 emacs_abort ();
1559 m = &ft_face->glyph->metrics;
1560 if (flt_font_ft->matrix)
1562 FT_Vector v[4];
1563 int i;
1565 v[0].x = v[1].x = m->horiBearingX;
1566 v[2].x = v[3].x = m->horiBearingX + m->width;
1567 v[0].y = v[2].y = m->horiBearingY;
1568 v[1].y = v[3].y = m->horiBearingY - m->height;
1569 for (i = 0; i < 4; i++)
1570 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1571 g->g.lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1572 g->g.rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1573 g->g.ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1574 g->g.descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1576 else
1578 g->g.lbearing = FLOOR (m->horiBearingX);
1579 g->g.rbearing = CEIL (m->horiBearingX + m->width);
1580 g->g.ascent = CEIL (m->horiBearingY);
1581 g->g.descent = - FLOOR (m->horiBearingY - m->height);
1583 g->g.xadv = ROUND (ft_face->glyph->advance.x);
1585 else
1587 g->g.lbearing = 0;
1588 g->g.rbearing = g->g.xadv = flt_font_ft->font->space_width << 6;
1589 g->g.ascent = flt_font_ft->font->ascent << 6;
1590 g->g.descent = flt_font_ft->font->descent << 6;
1592 g->g.yadv = 0;
1593 g->g.measured = 1;
1595 return 0;
1598 static int
1599 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1601 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1603 #define FEATURE_ANY(IDX) \
1604 (spec->features[IDX] \
1605 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1607 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1608 OTF *otf = flt_font_ft->otf;
1609 OTF_Tag *tags;
1610 int i, n;
1611 bool negative;
1613 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1614 /* Return true iff any of GSUB or GPOS support the script (and
1615 language). */
1616 return (otf
1617 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1618 NULL, 0) > 0
1619 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1620 NULL, 0) > 0));
1622 for (i = 0; i < 2; i++)
1623 if (! FEATURE_ANY (i))
1625 if (FEATURE_NONE (i))
1627 if (otf
1628 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1629 NULL, 0) > 0)
1630 return 0;
1631 continue;
1633 if (spec->features[i][0] == 0xFFFFFFFF)
1635 if (! otf
1636 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1637 NULL, 0) <= 0)
1638 continue;
1640 else if (! otf)
1641 return 0;
1642 for (n = 1; spec->features[i][n]; n++);
1643 USE_SAFE_ALLOCA;
1644 SAFE_NALLOCA (tags, 1, n);
1645 for (n = 0, negative = 0; spec->features[i][n]; n++)
1647 if (spec->features[i][n] == 0xFFFFFFFF)
1648 negative = 1;
1649 else if (negative)
1650 tags[n - 1] = spec->features[i][n] | 0x80000000;
1651 else
1652 tags[n] = spec->features[i][n];
1654 bool passed = true;
1655 #ifndef M17N_FLT_USE_NEW_FEATURE
1656 passed = n - negative > 0;
1657 #endif
1658 if (passed)
1659 passed = (OTF_check_features (otf, i == 0, spec->script,
1660 spec->langsys, tags, n - negative)
1661 != 1);
1662 SAFE_FREE ();
1663 if (passed)
1664 return 0;
1666 return 1;
1667 #undef FEATURE_NONE
1668 #undef FEATURE_ANY
1671 #define DEVICE_DELTA(table, size) \
1672 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1673 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1674 : 0)
1676 static void
1677 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1678 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1680 if (anchor->AnchorFormat == 2)
1682 FT_Outline *outline;
1683 int ap = anchor->f.f1.AnchorPoint;
1685 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1686 outline = &ft_face->glyph->outline;
1687 if (ap < outline->n_points)
1689 *x = outline->points[ap].x << 6;
1690 *y = outline->points[ap].y << 6;
1693 else if (anchor->AnchorFormat == 3)
1695 if (anchor->f.f2.XDeviceTable.offset
1696 && anchor->f.f2.XDeviceTable.DeltaValue)
1697 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1698 if (anchor->f.f2.YDeviceTable.offset
1699 && anchor->f.f2.YDeviceTable.DeltaValue)
1700 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1704 static OTF_GlyphString otf_gstring;
1706 static void
1707 setup_otf_gstring (int size)
1709 if (otf_gstring.size < size)
1711 ptrdiff_t new_size = otf_gstring.size;
1712 xfree (otf_gstring.glyphs);
1713 otf_gstring.glyphs = xpalloc (NULL, &new_size, size - otf_gstring.size,
1714 INT_MAX, sizeof *otf_gstring.glyphs);
1715 otf_gstring.size = new_size;
1717 otf_gstring.used = size;
1718 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1721 #ifdef M17N_FLT_USE_NEW_FEATURE
1723 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1724 #define PACK_OTF_TAG(TAG) \
1725 ((((TAG) & 0x7F000000) >> 3) \
1726 | (((TAG) & 0x7F0000) >> 2) \
1727 | (((TAG) & 0x7F00) >> 1) \
1728 | ((TAG) & 0x7F))
1730 /* Assuming that FONT is an OpenType font, apply OpenType features
1731 specified in SPEC on glyphs between FROM and TO of IN, and record
1732 the lastly applied feature in each glyph of IN. If OUT is not
1733 NULL, append the resulting glyphs to OUT while storing glyph
1734 position adjustment information in ADJUSTMENT. */
1736 static int
1737 ftfont_drive_otf (MFLTFont *font,
1738 MFLTOtfSpec *spec,
1739 MFLTGlyphString *in,
1740 int from,
1741 int to,
1742 MFLTGlyphString *out,
1743 MFLTGlyphAdjustment *adjustment)
1745 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1746 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
1747 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
1748 FT_Face ft_face = flt_font_ft->ft_face;
1749 OTF *otf = flt_font_ft->otf;
1750 int len = to - from;
1751 int i, j, gidx;
1752 OTF_Glyph *otfg;
1753 char script[5], *langsys = NULL;
1754 char *gsub_features = NULL, *gpos_features = NULL;
1755 OTF_Feature *features;
1757 if (len == 0)
1758 return from;
1759 OTF_tag_name (spec->script, script);
1761 char langsysbuf[5];
1762 if (spec->langsys)
1764 langsys = langsysbuf;
1765 OTF_tag_name (spec->langsys, langsys);
1768 USE_SAFE_ALLOCA;
1769 for (i = 0; i < 2; i++)
1771 char *p;
1773 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1775 for (j = 0; spec->features[i][j]; j++);
1776 SAFE_NALLOCA (p, 6, j);
1777 if (i == 0)
1778 gsub_features = p;
1779 else
1780 gpos_features = p;
1781 for (j = 0; spec->features[i][j]; j++)
1783 if (spec->features[i][j] == 0xFFFFFFFF)
1784 *p++ = '*', *p++ = ',';
1785 else
1787 OTF_tag_name (spec->features[i][j], p);
1788 p[4] = ',';
1789 p += 5;
1792 *--p = '\0';
1796 setup_otf_gstring (len);
1797 for (i = 0; i < len; i++)
1799 otf_gstring.glyphs[i].c = in_glyphs[i].g.c & 0x11FFFF;
1800 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
1801 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1802 otf_gstring.glyphs[i].positioning_type = in_glyphs[i].libotf_positioning_type;
1803 #endif
1806 OTF_drive_gdef (otf, &otf_gstring);
1807 gidx = out ? out->used : from;
1809 if (gsub_features && out)
1811 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1812 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1813 gsub_features) < 0)
1814 goto simple_copy;
1815 #else
1816 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1817 gsub_features) < 0)
1818 goto simple_copy;
1819 #endif
1820 if (out->allocated < out->used + otf_gstring.used)
1822 SAFE_FREE ();
1823 return -2;
1825 features = otf->gsub->FeatureList.Feature;
1826 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1828 MFLTGlyphFT *g;
1829 int min_from, max_to;
1830 int feature_idx;
1832 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1833 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1834 #else
1835 feature_idx = otfg->positioning_type >> 4;
1836 #endif
1837 g = out_glyphs + out->used;
1838 *g = in_glyphs[otfg->f.index.from];
1839 if (g->g.code != otfg->glyph_id)
1841 g->g.c = 0;
1842 g->g.code = otfg->glyph_id;
1843 g->g.measured = 0;
1845 out->used++;
1846 min_from = g->g.from;
1847 max_to = g->g.to;
1848 if (otfg->f.index.from < otfg->f.index.to)
1850 /* OTFG substitutes multiple glyphs in IN. */
1851 for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
1853 if (min_from > in_glyphs[j].g.from)
1854 min_from = in_glyphs[j].g.from;
1855 if (max_to < in_glyphs[j].g.to)
1856 max_to = in_glyphs[j].g.to;
1858 g->g.from = min_from;
1859 g->g.to = max_to;
1861 if (feature_idx)
1863 unsigned int tag = features[feature_idx - 1].FeatureTag;
1864 tag = PACK_OTF_TAG (tag);
1865 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1867 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1868 g->libotf_positioning_type
1869 = otfg->positioning_type & OTF_positioning_type_components_mask;
1870 #endif
1871 for (i++, otfg++; (i < otf_gstring.used
1872 && otfg->f.index.from == otfg[-1].f.index.from);
1873 i++, otfg++)
1875 g = out_glyphs + out->used;
1876 *g = in_glyphs[otfg->f.index.to];
1877 if (g->g.code != otfg->glyph_id)
1879 g->g.c = 0;
1880 g->g.code = otfg->glyph_id;
1881 g->g.measured = 0;
1883 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1884 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1885 #else
1886 feature_idx = otfg->positioning_type >> 4;
1887 #endif
1888 if (feature_idx)
1890 unsigned int tag = features[feature_idx - 1].FeatureTag;
1891 tag = PACK_OTF_TAG (tag);
1892 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1894 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1895 g->libotf_positioning_type
1896 = otfg->positioning_type & OTF_positioning_type_components_mask;
1897 #endif
1898 out->used++;
1902 else if (gsub_features)
1904 /* Just for checking which features will be applied. */
1905 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1906 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1907 gsub_features) < 0)
1908 goto simple_copy;
1909 #else
1910 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1911 gsub_features) < 0)
1912 goto simple_copy;
1913 #endif
1914 features = otf->gsub->FeatureList.Feature;
1915 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1916 otfg++)
1918 int feature_idx;
1919 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1920 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1921 #else
1922 feature_idx = otfg->positioning_type >> 4;
1923 #endif
1924 if (feature_idx)
1926 unsigned int tag = features[feature_idx - 1].FeatureTag;
1927 tag = PACK_OTF_TAG (tag);
1928 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1930 MFLTGlyphFT *g = in_glyphs + j;
1931 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1936 else if (out)
1938 if (out->allocated < out->used + len)
1940 SAFE_FREE ();
1941 return -2;
1943 for (i = 0; i < len; i++)
1944 out_glyphs[out->used++] = in_glyphs[i];
1947 if (gpos_features && out)
1949 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
1950 int x_ppem, y_ppem, x_scale, y_scale;
1952 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1953 if (OTF_drive_gpos_features (otf, &otf_gstring, script, langsys,
1954 gpos_features) < 0)
1956 SAFE_FREE ();
1957 return to;
1959 #else
1960 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1961 gpos_features) < 0)
1963 SAFE_FREE ();
1964 return to;
1966 #endif
1967 features = otf->gpos->FeatureList.Feature;
1968 x_ppem = ft_face->size->metrics.x_ppem;
1969 y_ppem = ft_face->size->metrics.y_ppem;
1970 x_scale = ft_face->size->metrics.x_scale;
1971 y_scale = ft_face->size->metrics.y_scale;
1973 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
1974 i < otf_gstring.used; i++, otfg++)
1976 MFLTGlyphAdjustment *adjust = adjustment;
1977 MFLTGlyphFT *prev;
1978 int positioning_type, feature_idx;
1980 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1981 positioning_type = OTF_POSITIONING_TYPE_GET_FORMAT (otfg);
1982 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1983 #else
1984 positioning_type = otfg->positioning_type & 0xF;
1985 feature_idx = otfg->positioning_type >> 4;
1986 #endif
1987 if (feature_idx)
1989 unsigned int tag = features[feature_idx - 1].FeatureTag;
1990 tag = PACK_OTF_TAG (tag);
1991 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1994 if (! otfg->glyph_id)
1995 /* This is a pseudo glyph that contains positioning
1996 information to be accumulated to a real glyph. */
1997 adjust--;
1998 switch (positioning_type)
2000 case 0:
2001 break;
2002 case 1: /* Single */
2003 case 2: /* Pair */
2005 int format = otfg->f.f1.format;
2007 if (format & OTF_XPlacement)
2008 adjust->xoff
2009 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2010 if (format & OTF_XPlaDevice)
2011 adjust->xoff
2012 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2013 if (format & OTF_YPlacement)
2014 adjust->yoff
2015 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2016 if (format & OTF_YPlaDevice)
2017 adjust->yoff
2018 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2019 if (format & OTF_XAdvance)
2020 adjust->xadv
2021 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2022 if (format & OTF_XAdvDevice)
2023 adjust->xadv
2024 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2025 if (format & OTF_YAdvance)
2026 adjust->yadv
2027 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2028 if (format & OTF_YAdvDevice)
2029 adjust->yadv
2030 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2031 adjust->set = 1;
2033 break;
2034 case 3: /* Cursive */
2035 /* Not yet supported. */
2036 break;
2037 case 4: /* Mark-to-Base */
2038 case 5: /* Mark-to-Ligature */
2039 if (! base)
2040 break;
2041 prev = base;
2042 goto label_adjust_anchor;
2043 default: /* i.e. case 6 Mark-to-Mark */
2044 if (! mark)
2045 break;
2046 prev = mark;
2047 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2049 int distance = OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg);
2051 if (distance > 0)
2053 prev = g - distance;
2054 if (prev < out_glyphs)
2055 prev = mark;
2058 #endif
2060 label_adjust_anchor:
2062 int base_x, base_y, mark_x, mark_y;
2063 int this_from, this_to;
2065 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2066 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2067 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2068 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2070 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2071 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2072 x_ppem, y_ppem, &base_x, &base_y);
2073 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2074 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2075 x_ppem, y_ppem, &mark_x, &mark_y);
2076 adjust->xoff = (base_x - mark_x);
2077 adjust->yoff = - (base_y - mark_y);
2078 adjust->back = (g - prev);
2079 adjust->xadv = 0;
2080 adjust->advance_is_absolute = 1;
2081 adjust->set = 1;
2082 this_from = g->g.from;
2083 this_to = g->g.to;
2084 for (j = 0; prev + j < g; j++)
2086 if (this_from > prev[j].g.from)
2087 this_from = prev[j].g.from;
2088 if (this_to < prev[j].g.to)
2089 this_to = prev[j].g.to;
2091 for (; prev <= g; prev++)
2093 prev->g.from = this_from;
2094 prev->g.to = this_to;
2098 if (otfg->glyph_id)
2100 if (otfg->GlyphClass == OTF_GlyphClass0)
2101 base = mark = g;
2102 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2103 mark = g;
2104 else
2105 base = g;
2106 g++, adjustment++;
2110 else if (gpos_features)
2112 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2113 gpos_features) < 0)
2115 SAFE_FREE ();
2116 return to;
2118 features = otf->gpos->FeatureList.Feature;
2119 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2120 i++, otfg++)
2121 if (otfg->positioning_type & 0xF)
2123 int feature_idx = otfg->positioning_type >> 4;
2125 if (feature_idx)
2127 unsigned int tag = features[feature_idx - 1].FeatureTag;
2128 tag = PACK_OTF_TAG (tag);
2129 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2131 MFLTGlyphFT *g = in_glyphs + j;
2132 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2137 SAFE_FREE ();
2138 return to;
2140 simple_copy:
2141 SAFE_FREE ();
2142 if (! out)
2143 return to;
2144 if (out->allocated < out->used + len)
2145 return -2;
2146 font->get_metrics (font, in, from, to);
2147 memcpy (out->glyphs + out->used, in_glyphs, sizeof (MFLTGlyphFT) * len);
2148 out->used += len;
2149 return to;
2152 static int
2153 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2154 MFLTGlyphString *in, int from, int to)
2156 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2159 #else /* not M17N_FLT_USE_NEW_FEATURE */
2161 static int
2162 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2163 int from, int to,
2164 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2166 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2167 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
2168 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
2169 FT_Face ft_face = flt_font_ft->ft_face;
2170 OTF *otf = flt_font_ft->otf;
2171 int len = to - from;
2172 int i, j, gidx;
2173 OTF_Glyph *otfg;
2174 char script[5], *langsys = NULL;
2175 char *gsub_features = NULL, *gpos_features = NULL;
2177 if (len == 0)
2178 return from;
2179 OTF_tag_name (spec->script, script);
2181 char langsysbuf[5];
2182 if (spec->langsys)
2184 langsys = langsysbuf;
2185 OTF_tag_name (spec->langsys, langsys);
2188 USE_SAFE_ALLOCA;
2189 for (i = 0; i < 2; i++)
2191 char *p;
2193 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2195 for (j = 0; spec->features[i][j]; j++);
2196 SAFE_NALLOCA (p, 6, j);
2197 if (i == 0)
2198 gsub_features = p;
2199 else
2200 gpos_features = p;
2201 for (j = 0; spec->features[i][j]; j++)
2203 if (spec->features[i][j] == 0xFFFFFFFF)
2204 *p++ = '*', *p++ = ',';
2205 else
2207 OTF_tag_name (spec->features[i][j], p);
2208 p[4] = ',';
2209 p += 5;
2212 *--p = '\0';
2216 setup_otf_gstring (len);
2217 for (i = 0; i < len; i++)
2219 otf_gstring.glyphs[i].c = in_glyphs[i].g.c;
2220 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
2223 OTF_drive_gdef (otf, &otf_gstring);
2224 gidx = out->used;
2226 if (gsub_features)
2228 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2229 < 0)
2230 goto simple_copy;
2231 if (out->allocated < out->used + otf_gstring.used)
2233 SAFE_FREE ();
2234 return -2;
2236 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2238 MFLTGlyphFT *g;
2239 int min_from, max_to;
2240 int j;
2242 g = out_glyphs + out->used;
2243 *g = in_glyphs[otfg->f.index.from];
2244 if (g->g.code != otfg->glyph_id)
2246 g->g.c = 0;
2247 g->g.code = otfg->glyph_id;
2248 g->g.measured = 0;
2250 out->used++;
2251 min_from = g->g.from;
2252 max_to = g->g.to;
2253 if (otfg->f.index.from < otfg->f.index.to)
2255 /* OTFG substitutes multiple glyphs in IN. */
2256 for (j = from + otfg->f.index.from + 1;
2257 j <= from + otfg->f.index.to; j++)
2259 if (min_from > in->glyphs[j].from)
2260 min_from = in->glyphs[j].from;
2261 if (max_to < in->glyphs[j].to)
2262 max_to = in->glyphs[j].to;
2264 g->g.from = min_from;
2265 g->g.to = max_to;
2267 for (i++, otfg++; (i < otf_gstring.used
2268 && otfg->f.index.from == otfg[-1].f.index.from);
2269 i++, otfg++)
2271 g = out_glyphs + out->used;
2272 *g = in_glyphs[otfg->f.index.to];
2273 if (g->g.code != otfg->glyph_id)
2275 g->g.c = 0;
2276 g->g.code = otfg->glyph_id;
2277 g->g.measured = 0;
2279 out->used++;
2283 else
2285 if (out->allocated < out->used + len)
2287 SAFE_FREE ();
2288 return -2;
2290 for (i = 0; i < len; i++)
2291 out_glyphs[out->used++] = in_glyphs[i];
2294 if (gpos_features)
2296 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
2297 int x_ppem, y_ppem, x_scale, y_scale;
2299 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2300 < 0)
2302 SAFE_FREE ();
2303 return to;
2306 x_ppem = ft_face->size->metrics.x_ppem;
2307 y_ppem = ft_face->size->metrics.y_ppem;
2308 x_scale = ft_face->size->metrics.x_scale;
2309 y_scale = ft_face->size->metrics.y_scale;
2311 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2312 i < otf_gstring.used; i++, otfg++, g++)
2314 MFLTGlyphFT *prev;
2316 if (! otfg->glyph_id)
2317 continue;
2318 switch (otfg->positioning_type)
2320 case 0:
2321 break;
2322 case 1: /* Single */
2323 case 2: /* Pair */
2325 int format = otfg->f.f1.format;
2327 if (format & OTF_XPlacement)
2328 adjustment[i].xoff
2329 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2330 if (format & OTF_XPlaDevice)
2331 adjustment[i].xoff
2332 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2333 if (format & OTF_YPlacement)
2334 adjustment[i].yoff
2335 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2336 if (format & OTF_YPlaDevice)
2337 adjustment[i].yoff
2338 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2339 if (format & OTF_XAdvance)
2340 adjustment[i].xadv
2341 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2342 if (format & OTF_XAdvDevice)
2343 adjustment[i].xadv
2344 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2345 if (format & OTF_YAdvance)
2346 adjustment[i].yadv
2347 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2348 if (format & OTF_YAdvDevice)
2349 adjustment[i].yadv
2350 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2351 adjustment[i].set = 1;
2353 break;
2354 case 3: /* Cursive */
2355 /* Not yet supported. */
2356 break;
2357 case 4: /* Mark-to-Base */
2358 case 5: /* Mark-to-Ligature */
2359 if (! base)
2360 break;
2361 prev = base;
2362 goto label_adjust_anchor;
2363 default: /* i.e. case 6 Mark-to-Mark */
2364 if (! mark)
2365 break;
2366 prev = mark;
2368 label_adjust_anchor:
2370 int base_x, base_y, mark_x, mark_y;
2371 int this_from, this_to;
2373 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2374 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2375 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2376 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2378 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2379 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2380 x_ppem, y_ppem, &base_x, &base_y);
2381 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2382 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2383 x_ppem, y_ppem, &mark_x, &mark_y);
2384 adjustment[i].xoff = (base_x - mark_x);
2385 adjustment[i].yoff = - (base_y - mark_y);
2386 adjustment[i].back = (g - prev);
2387 adjustment[i].xadv = 0;
2388 adjustment[i].advance_is_absolute = 1;
2389 adjustment[i].set = 1;
2390 this_from = g->g.from;
2391 this_to = g->g.to;
2392 for (j = 0; prev + j < g; j++)
2394 if (this_from > prev[j].g.from)
2395 this_from = prev[j].g.from;
2396 if (this_to < prev[j].g.to)
2397 this_to = prev[j].g.to;
2399 for (; prev <= g; prev++)
2401 prev->g.from = this_from;
2402 prev->g.to = this_to;
2406 if (otfg->GlyphClass == OTF_GlyphClass0)
2407 base = mark = g;
2408 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2409 mark = g;
2410 else
2411 base = g;
2414 SAFE_FREE ();
2415 return to;
2417 simple_copy:
2418 SAFE_FREE ();
2419 if (out->allocated < out->used + len)
2420 return -2;
2421 font->get_metrics (font, in, from, to);
2422 memcpy (out_glyphs + out->used, in_glyphs,
2423 sizeof (MFLTGlyphFT) * len);
2424 out->used += len;
2425 return to;
2428 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2430 static MFLTGlyphString gstring;
2432 static bool m17n_flt_initialized;
2434 static Lisp_Object
2435 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2436 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2438 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2439 ptrdiff_t i;
2440 struct MFLTFontFT flt_font_ft;
2441 MFLT *flt = NULL;
2442 bool with_variation_selector = false;
2444 if (! m17n_flt_initialized)
2446 M17N_INIT ();
2447 #ifdef M17N_FLT_USE_NEW_FEATURE
2448 mflt_enable_new_feature = 1;
2449 mflt_try_otf = ftfont_try_otf;
2450 #endif /* M17N_FLT_USE_NEW_FEATURE */
2451 m17n_flt_initialized = 1;
2454 for (i = 0; i < len; i++)
2456 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2457 int c;
2459 if (NILP (g))
2460 break;
2461 c = LGLYPH_CHAR (g);
2462 if (CHAR_VARIATION_SELECTOR_P (c))
2463 with_variation_selector = true;
2466 len = i;
2468 if (otf && with_variation_selector)
2470 setup_otf_gstring (len);
2471 for (i = 0; i < len; i++)
2473 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2475 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2476 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2477 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2479 OTF_drive_cmap (otf, &otf_gstring);
2480 for (i = 0; i < otf_gstring.used; i++)
2482 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2483 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2484 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2486 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2487 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2488 LGSTRING_SET_GLYPH (lgstring, i, g0);
2490 if (len > otf_gstring.used)
2492 len = otf_gstring.used;
2493 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2498 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2500 if (NILP (family))
2501 flt_font_ft.flt_font.family = Mnil;
2502 else
2503 flt_font_ft.flt_font.family
2504 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2506 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2507 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2508 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2509 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2510 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2511 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2512 flt_font_ft.flt_font.internal = NULL;
2513 flt_font_ft.font = font;
2514 flt_font_ft.ft_face = ft_face;
2515 flt_font_ft.otf = otf;
2516 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2518 if (1 < len)
2520 /* A little bit ad hoc. Perhaps, shaper must get script and
2521 language information, and select a proper flt for them
2522 here. */
2523 int c1 = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 1));
2524 /* For the combining characters in the range U+300..U+36F,
2525 "combining" is the sole FLT provided by the m17n-lib. In
2526 addition, it is the sole FLT that can handle the other
2527 combining characters with non-OTF fonts. */
2528 if ((0x300 <= c1 && c1 <= 0x36F)
2529 || (! otf && CHAR_HAS_CATEGORY (c1, '^')))
2530 flt = mflt_get (msymbol ("combining"));
2532 if (! flt && ! otf)
2534 flt = mflt_find (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 0)),
2535 &flt_font_ft.flt_font);
2536 if (! flt)
2537 return make_number (0);
2540 MFLTGlyphFT *glyphs = (MFLTGlyphFT *) gstring.glyphs;
2541 ptrdiff_t allocated = gstring.allocated;
2542 ptrdiff_t incr_min = len - allocated;
2546 if (0 < incr_min)
2548 xfree (glyphs);
2549 glyphs = xpalloc (NULL, &allocated, incr_min, INT_MAX, sizeof *glyphs);
2551 incr_min = 1;
2553 for (i = 0; i < len; i++)
2555 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2556 memset (&glyphs[i], 0, sizeof glyphs[i]);
2557 glyphs[i].g.c = LGLYPH_CHAR (g);
2558 if (with_variation_selector)
2560 glyphs[i].g.code = LGLYPH_CODE (g);
2561 glyphs[i].g.encoded = 1;
2565 gstring.glyph_size = sizeof *glyphs;
2566 gstring.glyphs = (MFLTGlyph *) glyphs;
2567 gstring.allocated = allocated;
2568 gstring.used = len;
2569 gstring.r2l = 0;
2571 while (mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt) == -2);
2573 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2574 return Qnil;
2575 for (i = 0; i < gstring.used; i++)
2577 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2579 g->g.from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->g.from));
2580 g->g.to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->g.to));
2583 for (i = 0; i < gstring.used; i++)
2585 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2586 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2588 if (NILP (lglyph))
2590 lglyph = LGLYPH_NEW ();
2591 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2593 LGLYPH_SET_FROM (lglyph, g->g.from);
2594 LGLYPH_SET_TO (lglyph, g->g.to);
2595 LGLYPH_SET_CHAR (lglyph, g->g.c);
2596 LGLYPH_SET_CODE (lglyph, g->g.code);
2597 LGLYPH_SET_WIDTH (lglyph, g->g.xadv >> 6);
2598 LGLYPH_SET_LBEARING (lglyph, g->g.lbearing >> 6);
2599 LGLYPH_SET_RBEARING (lglyph, g->g.rbearing >> 6);
2600 LGLYPH_SET_ASCENT (lglyph, g->g.ascent >> 6);
2601 LGLYPH_SET_DESCENT (lglyph, g->g.descent >> 6);
2602 if (g->g.adjusted)
2604 Lisp_Object vec = make_uninit_vector (3);
2606 ASET (vec, 0, make_number (g->g.xoff >> 6));
2607 ASET (vec, 1, make_number (g->g.yoff >> 6));
2608 ASET (vec, 2, make_number (g->g.xadv >> 6));
2609 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2612 return make_number (i);
2615 Lisp_Object
2616 ftfont_shape (Lisp_Object lgstring)
2618 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2619 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2620 OTF *otf = ftfont_get_otf (ftfont_info);
2622 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2623 &ftfont_info->matrix);
2626 #endif /* HAVE_M17N_FLT */
2628 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2631 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2633 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2634 OTF *otf = ftfont_get_otf (ftfont_info);
2636 if (! otf)
2637 return 0;
2638 return OTF_get_variation_glyphs (otf, c, variations);
2641 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2642 #endif /* HAVE_LIBOTF */
2644 static const char *const ftfont_booleans [] = {
2645 ":antialias",
2646 ":hinting",
2647 ":verticallayout",
2648 ":autohint",
2649 ":globaladvance",
2650 ":outline",
2651 ":scalable",
2652 ":minspace",
2653 ":embolden",
2654 NULL,
2657 static const char *const ftfont_non_booleans [] = {
2658 ":family",
2659 ":familylang",
2660 ":style",
2661 ":stylelang",
2662 ":fullname",
2663 ":fullnamelang",
2664 ":slant",
2665 ":weight",
2666 ":size",
2667 ":width",
2668 ":aspect",
2669 ":pixelsize",
2670 ":spacing",
2671 ":foundry",
2672 ":hintstyle",
2673 ":file",
2674 ":index",
2675 ":ftface",
2676 ":rasterizer",
2677 ":scale",
2678 ":dpi",
2679 ":rgba",
2680 ":lcdfilter",
2681 ":charset",
2682 ":lang",
2683 ":fontversion",
2684 ":capability",
2685 NULL,
2688 void
2689 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2691 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2695 Lisp_Object
2696 ftfont_combining_capability (struct font *font)
2698 #ifdef HAVE_M17N_FLT
2699 return Qt;
2700 #else
2701 return Qnil;
2702 #endif
2705 static struct font_driver const ftfont_driver =
2707 /* We can't draw a text without device dependent functions. */
2708 .type = LISPSYM_INITIALLY (Qfreetype),
2709 .get_cache = ftfont_get_cache,
2710 .list = ftfont_list,
2711 .match = ftfont_match,
2712 .list_family = ftfont_list_family,
2713 .open = ftfont_open,
2714 .close = ftfont_close,
2715 .has_char = ftfont_has_char,
2716 .encode_char = ftfont_encode_char,
2717 .text_extents = ftfont_text_extents,
2718 .get_bitmap = ftfont_get_bitmap,
2719 .anchor_point = ftfont_anchor_point,
2720 #ifdef HAVE_LIBOTF
2721 .otf_capability = ftfont_otf_capability,
2722 #endif
2723 #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
2724 .shape = ftfont_shape,
2725 #endif
2726 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2727 .get_variation_glyphs = ftfont_variation_glyphs,
2728 #endif
2729 .filter_properties = ftfont_filter_properties,
2730 .combining_capability = ftfont_combining_capability,
2733 void
2734 syms_of_ftfont (void)
2736 /* Symbolic type of this font-driver. */
2737 DEFSYM (Qfreetype, "freetype");
2739 /* Fontconfig's generic families and their aliases. */
2740 DEFSYM (Qmonospace, "monospace");
2741 DEFSYM (Qsans_serif, "sans-serif");
2742 DEFSYM (Qsans, "sans");
2743 DEFSYM (Qsans__serif, "sans serif");
2745 staticpro (&freetype_font_cache);
2746 freetype_font_cache = list1 (Qt);
2748 staticpro (&ftfont_generic_family_list);
2749 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2750 Fcons (Qsans_serif, Qt),
2751 Fcons (Qsans, Qt));
2753 staticpro (&ft_face_cache);
2754 ft_face_cache = Qnil;
2756 register_font_driver (&ftfont_driver, NULL);