Tell user about read-integer-overflow-as-float
[emacs.git] / src / ftfont.c
blob9a8777ef078a660d7fc4d4e4f7b8815cf78f3245
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;
350 static Lisp_Object
351 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
353 Lisp_Object cache, val, entity;
354 struct ftfont_cache_data *cache_data;
356 if (FONT_ENTITY_P (key))
358 entity = key;
359 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
360 eassert (CONSP (val));
361 key = XCDR (val);
363 else
364 entity = Qnil;
366 if (NILP (ft_face_cache))
367 cache = Qnil;
368 else
369 cache = Fgethash (key, ft_face_cache, Qnil);
370 if (NILP (cache))
372 if (NILP (ft_face_cache))
373 ft_face_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
374 cache_data = xmalloc (sizeof *cache_data);
375 cache_data->ft_face = NULL;
376 cache_data->fc_charset = NULL;
377 val = make_save_ptr_int (cache_data, 0);
378 cache = Fcons (Qnil, val);
379 Fputhash (key, cache, ft_face_cache);
381 else
383 val = XCDR (cache);
384 cache_data = XSAVE_POINTER (val, 0);
387 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
388 return cache;
390 if (cache_for == FTFONT_CACHE_FOR_FACE
391 ? ! cache_data->ft_face : ! cache_data->fc_charset)
393 char *filename = SSDATA (XCAR (key));
394 int idx = XINT (XCDR (key));
396 if (cache_for == FTFONT_CACHE_FOR_FACE)
398 if (! ft_library
399 && FT_Init_FreeType (&ft_library) != 0)
400 return Qnil;
401 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
402 != 0)
403 return Qnil;
405 else
407 FcPattern *pat = NULL;
408 FcFontSet *fontset = NULL;
409 FcObjectSet *objset = NULL;
410 FcCharSet *charset = NULL;
412 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
413 FC_INDEX, FcTypeInteger, idx, NULL);
414 if (! pat)
415 goto finish;
416 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
417 if (! objset)
418 goto finish;
419 fontset = FcFontList (NULL, pat, objset);
420 if (! fontset)
421 goto finish;
422 if (fontset && fontset->nfont > 0
423 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
424 &charset)
425 == FcResultMatch))
426 cache_data->fc_charset = FcCharSetCopy (charset);
427 else
428 cache_data->fc_charset = FcCharSetCreate ();
430 finish:
431 if (fontset)
432 FcFontSetDestroy (fontset);
433 if (objset)
434 FcObjectSetDestroy (objset);
435 if (pat)
436 FcPatternDestroy (pat);
439 return cache;
442 FcCharSet *
443 ftfont_get_fc_charset (Lisp_Object entity)
445 Lisp_Object val, cache;
446 struct ftfont_cache_data *cache_data;
448 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
449 val = XCDR (cache);
450 cache_data = XSAVE_POINTER (val, 0);
451 return cache_data->fc_charset;
454 #ifdef HAVE_LIBOTF
455 static OTF *
456 ftfont_get_otf (struct ftfont_info *ftfont_info)
458 OTF *otf;
460 if (ftfont_info->otf)
461 return ftfont_info->otf;
462 if (! ftfont_info->maybe_otf)
463 return NULL;
464 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
465 if (! otf || OTF_get_table (otf, "head") < 0)
467 if (otf)
468 OTF_close (otf);
469 ftfont_info->maybe_otf = 0;
470 return NULL;
472 ftfont_info->otf = otf;
473 return otf;
475 #endif /* HAVE_LIBOTF */
477 Lisp_Object
478 ftfont_get_cache (struct frame *f)
480 return freetype_font_cache;
483 static int
484 ftfont_get_charset (Lisp_Object registry)
486 char *str = SSDATA (SYMBOL_NAME (registry));
487 USE_SAFE_ALLOCA;
488 char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
489 int i, j;
491 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
493 if (str[i] == '.')
494 re[j++] = '\\';
495 else if (str[i] == '*')
496 re[j++] = '.';
497 re[j] = str[i];
498 if (re[j] == '?')
499 re[j] = '.';
501 re[j] = '\0';
502 AUTO_STRING_WITH_LEN (regexp, re, j);
503 for (i = 0; fc_charset_table[i].name; i++)
504 if (fast_c_string_match_ignore_case
505 (regexp, fc_charset_table[i].name,
506 strlen (fc_charset_table[i].name)) >= 0)
507 break;
508 SAFE_FREE ();
509 if (! fc_charset_table[i].name)
510 return -1;
511 if (! fc_charset_table[i].fc_charset)
513 FcCharSet *charset = FcCharSetCreate ();
514 int *uniquifier = fc_charset_table[i].uniquifier;
516 if (! charset)
517 return -1;
518 for (j = 0; uniquifier[j]; j++)
519 if (! FcCharSetAddChar (charset, uniquifier[j]))
521 FcCharSetDestroy (charset);
522 return -1;
524 fc_charset_table[i].fc_charset = charset;
526 return i;
529 struct OpenTypeSpec
531 Lisp_Object script;
532 unsigned int script_tag, langsys_tag;
533 int nfeatures[2];
534 unsigned int *features[2];
537 #define OTF_SYM_TAG(SYM, TAG) \
538 do { \
539 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
540 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
541 } while (0)
543 #define OTF_TAG_STR(TAG, P) \
544 do { \
545 (P)[0] = (char) (TAG >> 24); \
546 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
547 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
548 (P)[3] = (char) (TAG & 0xFF); \
549 (P)[4] = '\0'; \
550 } while (0)
552 #ifdef HAVE_LIBOTF
553 #define OTF_TAG_SYM(SYM, TAG) \
554 do { \
555 char str[5]; \
557 OTF_TAG_STR (TAG, str); \
558 (SYM) = font_intern_prop (str, 4, 1); \
559 } while (0)
560 #endif
563 static struct OpenTypeSpec *
564 ftfont_get_open_type_spec (Lisp_Object otf_spec)
566 struct OpenTypeSpec *spec = malloc (sizeof *spec);
567 Lisp_Object val;
568 int i, j;
569 bool negative;
571 if (! spec)
572 return NULL;
573 spec->script = XCAR (otf_spec);
574 if (! NILP (spec->script))
576 OTF_SYM_TAG (spec->script, spec->script_tag);
577 val = assq_no_quit (spec->script, Votf_script_alist);
578 if (CONSP (val) && SYMBOLP (XCDR (val)))
579 spec->script = XCDR (val);
580 else
581 spec->script = Qnil;
583 else
584 spec->script_tag = 0x44464C54; /* "DFLT" */
585 otf_spec = XCDR (otf_spec);
586 spec->langsys_tag = 0;
587 if (! NILP (otf_spec))
589 val = XCAR (otf_spec);
590 if (! NILP (val))
591 OTF_SYM_TAG (val, spec->langsys_tag);
592 otf_spec = XCDR (otf_spec);
594 spec->nfeatures[0] = spec->nfeatures[1] = 0;
595 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
597 Lisp_Object len;
599 val = XCAR (otf_spec);
600 if (NILP (val))
601 continue;
602 len = Flength (val);
603 spec->features[i] =
604 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
606 : malloc (XINT (len) * sizeof *spec->features[i]));
607 if (! spec->features[i])
609 if (i > 0 && spec->features[0])
610 free (spec->features[0]);
611 free (spec);
612 return NULL;
614 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
616 if (NILP (XCAR (val)))
617 negative = 1;
618 else
620 unsigned int tag;
622 OTF_SYM_TAG (XCAR (val), tag);
623 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
626 spec->nfeatures[i] = j;
628 return spec;
631 static FcPattern *
632 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
634 Lisp_Object tmp, extra;
635 FcPattern *pattern = NULL;
636 FcCharSet *charset = NULL;
637 FcLangSet *langset = NULL;
638 int n;
639 int dpi = -1;
640 int scalable = -1;
641 Lisp_Object script = Qnil;
642 Lisp_Object registry;
643 int fc_charset_idx;
645 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
646 && n < 100)
647 /* Fontconfig doesn't support reverse-italic/oblique. */
648 return NULL;
650 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
651 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
652 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
653 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
654 scalable = 1;
656 registry = AREF (spec, FONT_REGISTRY_INDEX);
657 if (NILP (registry)
658 || EQ (registry, Qascii_0)
659 || EQ (registry, Qiso10646_1)
660 || EQ (registry, Qunicode_bmp))
661 fc_charset_idx = -1;
662 else
664 FcChar8 *lang;
666 fc_charset_idx = ftfont_get_charset (registry);
667 if (fc_charset_idx < 0)
668 return NULL;
669 charset = fc_charset_table[fc_charset_idx].fc_charset;
670 *langname = fc_charset_table[fc_charset_idx].lang;
671 lang = (FcChar8 *) *langname;
672 if (lang)
674 langset = FcLangSetCreate ();
675 if (! langset)
676 goto err;
677 FcLangSetAdd (langset, lang);
681 otlayout[0] = '\0';
682 for (extra = AREF (spec, FONT_EXTRA_INDEX);
683 CONSP (extra); extra = XCDR (extra))
685 Lisp_Object key, val;
687 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
688 if (EQ (key, QCdpi))
690 if (INTEGERP (val))
691 dpi = XINT (val);
693 else if (EQ (key, QClang))
695 if (! langset)
696 langset = FcLangSetCreate ();
697 if (! langset)
698 goto err;
699 if (SYMBOLP (val))
701 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
702 goto err;
704 else
705 for (; CONSP (val); val = XCDR (val))
706 if (SYMBOLP (XCAR (val))
707 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
708 goto err;
710 else if (EQ (key, QCotf))
712 if (CONSP (val))
714 *otspec = ftfont_get_open_type_spec (val);
715 if (! *otspec)
716 return NULL;
717 strcpy (otlayout, "otlayout:");
718 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
719 script = (*otspec)->script;
722 else if (EQ (key, QCscript))
723 script = val;
724 else if (EQ (key, QCscalable))
725 scalable = ! NILP (val);
728 if (! NILP (script) && ! charset)
730 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
732 if (CONSP (chars) && CONSP (CDR (chars)))
734 charset = FcCharSetCreate ();
735 if (! charset)
736 goto err;
737 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
738 if (CHARACTERP (XCAR (chars))
739 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
740 goto err;
744 pattern = FcPatternCreate ();
745 if (! pattern)
746 goto err;
747 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
748 if (! NILP (tmp)
749 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
750 goto err;
751 tmp = AREF (spec, FONT_FAMILY_INDEX);
752 if (! NILP (tmp)
753 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
754 goto err;
755 if (charset
756 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
757 goto err;
758 if (langset
759 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
760 goto err;
761 if (dpi >= 0
762 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
763 goto err;
764 if (scalable >= 0
765 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
766 goto err;
767 #if defined HAVE_XFT && defined FC_COLOR
768 /* We really don't like color fonts, they cause Xft crashes. See
769 Bug#30874. */
770 if (Vxft_ignore_color_fonts
771 && ! FcPatternAddBool (pattern, FC_COLOR, FcFalse))
772 goto err;
773 #endif
775 goto finish;
777 err:
778 /* We come here because of unexpected error in fontconfig API call
779 (usually insufficient memory). */
780 if (pattern)
782 FcPatternDestroy (pattern);
783 pattern = NULL;
785 if (*otspec)
787 if ((*otspec)->nfeatures[0] > 0)
788 free ((*otspec)->features[0]);
789 if ((*otspec)->nfeatures[1] > 0)
790 free ((*otspec)->features[1]);
791 free (*otspec);
792 *otspec = NULL;
795 finish:
796 if (langset) FcLangSetDestroy (langset);
797 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
798 return pattern;
801 Lisp_Object
802 ftfont_list (struct frame *f, Lisp_Object spec)
804 Lisp_Object val = Qnil, family, adstyle;
805 int i;
806 FcPattern *pattern;
807 FcFontSet *fontset = NULL;
808 FcObjectSet *objset = NULL;
809 FcCharSet *charset;
810 Lisp_Object chars = Qnil;
811 char otlayout[15]; /* For "otlayout:XXXX" */
812 struct OpenTypeSpec *otspec = NULL;
813 int spacing = -1;
814 const char *langname = NULL;
816 if (! fc_initialized)
818 FcInit ();
819 fc_initialized = 1;
822 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
823 if (! pattern)
824 return Qnil;
825 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
827 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
828 if (! NILP (val))
830 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
831 if (CONSP (val) && VECTORP (XCDR (val)))
832 chars = XCDR (val);
834 val = Qnil;
836 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
837 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
838 family = AREF (spec, FONT_FAMILY_INDEX);
839 if (! NILP (family))
841 Lisp_Object resolved;
843 resolved = ftfont_resolve_generic_family (family, pattern);
844 if (! NILP (resolved))
846 FcPatternDel (pattern, FC_FAMILY);
847 if (! FcPatternAddString (pattern, FC_FAMILY,
848 SYMBOL_FcChar8 (resolved)))
849 goto err;
852 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
853 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
854 adstyle = Qnil;
855 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
856 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
857 FC_STYLE, FC_FILE, FC_INDEX,
858 #ifdef FC_CAPABILITY
859 FC_CAPABILITY,
860 #endif /* FC_CAPABILITY */
861 #ifdef FC_FONTFORMAT
862 FC_FONTFORMAT,
863 #endif
864 NULL);
865 if (! objset)
866 goto err;
867 if (! NILP (chars))
868 FcObjectSetAdd (objset, FC_CHARSET);
870 fontset = FcFontList (NULL, pattern, objset);
871 if (! fontset || fontset->nfont == 0)
872 goto finish;
873 #if 0
874 /* Need fix because this finds any fonts. */
875 if (fontset->nfont == 0 && ! NILP (family))
877 /* Try matching with configuration. For instance, the
878 configuration may specify "Nimbus Mono L" as an alias of
879 "Courier". */
880 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
881 SYMBOL_FcChar8 (family), NULL);
882 FcChar8 *fam;
884 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
886 for (i = 0;
887 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
888 i++)
890 FcPatternDel (pattern, FC_FAMILY);
891 FcPatternAddString (pattern, FC_FAMILY, fam);
892 FcFontSetDestroy (fontset);
893 fontset = FcFontList (NULL, pattern, objset);
894 if (fontset && fontset->nfont > 0)
895 break;
899 #endif
900 for (i = 0; i < fontset->nfont; i++)
902 Lisp_Object entity;
904 if (spacing >= 0)
906 int this;
908 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
909 == FcResultMatch)
910 && spacing != this)
911 continue;
914 #ifdef FC_CAPABILITY
915 if (otlayout[0])
917 FcChar8 *this;
919 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
920 != FcResultMatch
921 || ! strstr ((char *) this, otlayout))
922 continue;
924 #endif /* FC_CAPABILITY */
925 #ifdef HAVE_LIBOTF
926 if (otspec)
928 FcChar8 *file;
929 bool passed;
930 OTF *otf;
932 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
933 != FcResultMatch)
934 continue;
935 otf = OTF_open ((char *) file);
936 if (! otf)
937 continue;
938 passed = (OTF_check_features (otf, 1, otspec->script_tag,
939 otspec->langsys_tag,
940 otspec->features[0],
941 otspec->nfeatures[0]) == 1
942 && OTF_check_features (otf, 0, otspec->script_tag,
943 otspec->langsys_tag,
944 otspec->features[1],
945 otspec->nfeatures[1]) == 1);
946 OTF_close (otf);
947 if (!passed)
948 continue;
950 #endif /* HAVE_LIBOTF */
951 if (VECTORP (chars))
953 ptrdiff_t j;
955 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
956 != FcResultMatch)
957 continue;
958 for (j = 0; j < ASIZE (chars); j++)
959 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
960 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
961 break;
962 if (j == ASIZE (chars))
963 continue;
965 if (! NILP (adstyle) || langname)
967 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
969 if (! NILP (adstyle)
970 && (NILP (this_adstyle)
971 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
972 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
973 continue;
974 if (langname
975 && ! NILP (this_adstyle)
976 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
977 continue;
979 entity = ftfont_pattern_entity (fontset->fonts[i],
980 AREF (spec, FONT_EXTRA_INDEX));
981 if (! NILP (entity))
982 val = Fcons (entity, val);
984 val = Fnreverse (val);
985 goto finish;
987 err:
988 /* We come here because of unexpected error in fontconfig API call
989 (usually insufficient memory). */
990 val = Qnil;
992 finish:
993 FONT_ADD_LOG ("ftfont-list", spec, val);
994 if (objset) FcObjectSetDestroy (objset);
995 if (fontset) FcFontSetDestroy (fontset);
996 if (pattern) FcPatternDestroy (pattern);
997 return val;
1000 Lisp_Object
1001 ftfont_match (struct frame *f, Lisp_Object spec)
1003 Lisp_Object entity = Qnil;
1004 FcPattern *pattern, *match = NULL;
1005 FcResult result;
1006 char otlayout[15]; /* For "otlayout:XXXX" */
1007 struct OpenTypeSpec *otspec = NULL;
1008 const char *langname = NULL;
1010 if (! fc_initialized)
1012 FcInit ();
1013 fc_initialized = 1;
1016 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1017 if (! pattern)
1018 return Qnil;
1020 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1022 FcValue value;
1024 value.type = FcTypeDouble;
1025 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1026 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1028 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1030 FcDefaultSubstitute (pattern);
1031 match = FcFontMatch (NULL, pattern, &result);
1032 if (match)
1034 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1035 FcPatternDestroy (match);
1036 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1037 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1038 ftfont_generic_family_list))
1039 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1040 AREF (entity, FONT_FAMILY_INDEX))))
1041 entity = Qnil;
1044 FcPatternDestroy (pattern);
1046 FONT_ADD_LOG ("ftfont-match", spec, entity);
1047 return entity;
1050 Lisp_Object
1051 ftfont_list_family (struct frame *f)
1053 Lisp_Object list = Qnil;
1054 FcPattern *pattern = NULL;
1055 FcFontSet *fontset = NULL;
1056 FcObjectSet *objset = NULL;
1057 int i;
1059 if (! fc_initialized)
1061 FcInit ();
1062 fc_initialized = 1;
1065 pattern = FcPatternCreate ();
1066 if (! pattern)
1067 goto finish;
1068 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1069 if (! objset)
1070 goto finish;
1071 fontset = FcFontList (NULL, pattern, objset);
1072 if (! fontset)
1073 goto finish;
1075 for (i = 0; i < fontset->nfont; i++)
1077 FcPattern *pat = fontset->fonts[i];
1078 FcChar8 *str;
1080 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1081 list = Fcons (intern ((char *) str), list);
1084 finish:
1085 if (objset) FcObjectSetDestroy (objset);
1086 if (fontset) FcFontSetDestroy (fontset);
1087 if (pattern) FcPatternDestroy (pattern);
1089 return list;
1093 Lisp_Object
1094 ftfont_open2 (struct frame *f,
1095 Lisp_Object entity,
1096 int pixel_size,
1097 Lisp_Object font_object)
1099 struct ftfont_info *ftfont_info;
1100 struct font *font;
1101 struct ftfont_cache_data *cache_data;
1102 FT_Face ft_face;
1103 FT_Size ft_size;
1104 FT_UInt size;
1105 Lisp_Object val, filename, idx, cache;
1106 bool scalable;
1107 int spacing;
1108 int i;
1109 double upEM;
1111 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1112 if (! CONSP (val))
1113 return Qnil;
1114 val = XCDR (val);
1115 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1116 if (NILP (cache))
1117 return Qnil;
1118 filename = XCAR (val);
1119 idx = XCDR (val);
1120 val = XCDR (cache);
1121 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1122 ft_face = cache_data->ft_face;
1123 if (XSAVE_INTEGER (val, 1) > 0)
1125 /* FT_Face in this cache is already used by the different size. */
1126 if (FT_New_Size (ft_face, &ft_size) != 0)
1127 return Qnil;
1128 if (FT_Activate_Size (ft_size) != 0)
1130 FT_Done_Size (ft_size);
1131 return Qnil;
1134 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1135 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1136 if (size == 0)
1137 size = pixel_size;
1138 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1140 if (XSAVE_INTEGER (val, 1) == 0)
1141 FT_Done_Face (ft_face);
1142 return Qnil;
1145 ASET (font_object, FONT_FILE_INDEX, filename);
1146 font = XFONT_OBJECT (font_object);
1147 ftfont_info = (struct ftfont_info *) font;
1148 ftfont_info->ft_size = ft_face->size;
1149 ftfont_info->index = XINT (idx);
1150 #ifdef HAVE_LIBOTF
1151 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1152 ftfont_info->otf = NULL;
1153 #endif /* HAVE_LIBOTF */
1154 /* This means that there's no need of transformation. */
1155 ftfont_info->matrix.xx = 0;
1156 font->pixel_size = size;
1157 font->driver = &ftfont_driver;
1158 font->encoding_charset = font->repertory_charset = -1;
1160 upEM = ft_face->units_per_EM;
1161 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1162 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1163 if (scalable)
1165 font->ascent = ft_face->ascender * size / upEM + 0.5;
1166 font->descent = - ft_face->descender * size / upEM + 0.5;
1167 font->height = ft_face->height * size / upEM + 0.5;
1169 else
1171 font->ascent = ft_face->size->metrics.ascender >> 6;
1172 font->descent = - ft_face->size->metrics.descender >> 6;
1173 font->height = ft_face->size->metrics.height >> 6;
1175 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1176 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1177 else
1178 spacing = FC_PROPORTIONAL;
1179 if (spacing != FC_PROPORTIONAL
1180 #ifdef FC_DUAL
1181 && spacing != FC_DUAL
1182 #endif /* FC_DUAL */
1184 font->min_width = font->average_width = font->space_width
1185 = (scalable ? ft_face->max_advance_width * size / upEM + 0.5
1186 : ft_face->size->metrics.max_advance >> 6);
1187 else
1189 int n;
1191 font->min_width = font->average_width = font->space_width = 0;
1192 for (i = 32, n = 0; i < 127; i++)
1193 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1195 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1197 if (this_width > 0
1198 && (! font->min_width || font->min_width > this_width))
1199 font->min_width = this_width;
1200 if (i == 32)
1201 font->space_width = this_width;
1202 font->average_width += this_width;
1203 n++;
1205 if (n > 0)
1206 font->average_width /= n;
1209 font->baseline_offset = 0;
1210 font->relative_compose = 0;
1211 font->default_ascent = 0;
1212 font->vertical_centering = 0;
1213 if (scalable)
1215 font->underline_position = (-ft_face->underline_position * size / upEM
1216 + 0.5);
1217 font->underline_thickness = (ft_face->underline_thickness * size / upEM
1218 + 0.5);
1220 else
1222 font->underline_position = -1;
1223 font->underline_thickness = 0;
1226 return font_object;
1229 Lisp_Object
1230 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1232 Lisp_Object font_object;
1233 FT_UInt size;
1234 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1235 if (size == 0)
1236 size = pixel_size;
1237 font_object = font_build_object (VECSIZE (struct ftfont_info),
1238 Qfreetype, entity, size);
1239 return ftfont_open2 (f, entity, pixel_size, font_object);
1242 void
1243 ftfont_close (struct font *font)
1245 if (font_data_structures_may_be_ill_formed ())
1246 return;
1248 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1249 Lisp_Object val, cache;
1251 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1252 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1253 eassert (CONSP (cache));
1254 val = XCDR (cache);
1255 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1256 if (XSAVE_INTEGER (val, 1) == 0)
1258 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1260 FT_Done_Face (cache_data->ft_face);
1261 #ifdef HAVE_LIBOTF
1262 if (ftfont_info->otf)
1263 OTF_close (ftfont_info->otf);
1264 #endif
1265 cache_data->ft_face = NULL;
1267 else
1268 FT_Done_Size (ftfont_info->ft_size);
1272 ftfont_has_char (Lisp_Object font, int c)
1274 struct charset *cs = NULL;
1276 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1277 && charset_jisx0208 >= 0)
1278 cs = CHARSET_FROM_ID (charset_jisx0208);
1279 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1280 && charset_ksc5601 >= 0)
1281 cs = CHARSET_FROM_ID (charset_ksc5601);
1282 if (cs)
1283 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1285 if (FONT_ENTITY_P (font))
1287 FcCharSet *charset = ftfont_get_fc_charset (font);
1289 return (FcCharSetHasChar (charset, c) == FcTrue);
1291 else
1293 struct ftfont_info *ftfont_info;
1295 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1296 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1297 != 0);
1301 unsigned
1302 ftfont_encode_char (struct font *font, int c)
1304 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1305 FT_Face ft_face = ftfont_info->ft_size->face;
1306 FT_ULong charcode = c;
1307 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1309 return (code > 0 ? code : FONT_INVALID_CODE);
1312 void
1313 ftfont_text_extents (struct font *font, unsigned int *code,
1314 int nglyphs, struct font_metrics *metrics)
1316 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1317 FT_Face ft_face = ftfont_info->ft_size->face;
1318 int i, width = 0;
1319 bool first;
1321 if (ftfont_info->ft_size != ft_face->size)
1322 FT_Activate_Size (ftfont_info->ft_size);
1324 for (i = 0, first = 1; i < nglyphs; i++)
1326 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1328 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1330 if (first)
1332 metrics->lbearing = m->horiBearingX >> 6;
1333 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1334 metrics->ascent = m->horiBearingY >> 6;
1335 metrics->descent = (m->height - m->horiBearingY) >> 6;
1336 first = 0;
1338 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1339 metrics->lbearing = width + (m->horiBearingX >> 6);
1340 if (metrics->rbearing
1341 < width + ((m->horiBearingX + m->width) >> 6))
1342 metrics->rbearing
1343 = width + ((m->horiBearingX + m->width) >> 6);
1344 if (metrics->ascent < (m->horiBearingY >> 6))
1345 metrics->ascent = m->horiBearingY >> 6;
1346 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1347 metrics->descent = (m->height - m->horiBearingY) >> 6;
1348 width += m->horiAdvance >> 6;
1350 else
1351 width += font->space_width;
1353 metrics->width = width;
1357 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1359 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1360 FT_Face ft_face = ftfont_info->ft_size->face;
1361 FT_Int32 load_flags = FT_LOAD_RENDER;
1363 if (ftfont_info->ft_size != ft_face->size)
1364 FT_Activate_Size (ftfont_info->ft_size);
1365 if (bits_per_pixel == 1)
1367 #ifdef FT_LOAD_TARGET_MONO
1368 load_flags |= FT_LOAD_TARGET_MONO;
1369 #else
1370 load_flags |= FT_LOAD_MONOCHROME;
1371 #endif
1373 else if (bits_per_pixel != 8)
1374 /* We don't support such a rendering. */
1375 return -1;
1377 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1378 return -1;
1379 bitmap->bits_per_pixel
1380 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1381 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1382 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1383 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1384 : -1);
1385 if (bitmap->bits_per_pixel < 0)
1386 /* We don't support that kind of pixel mode. */
1387 return -1;
1388 bitmap->rows = ft_face->glyph->bitmap.rows;
1389 bitmap->width = ft_face->glyph->bitmap.width;
1390 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1391 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1392 bitmap->left = ft_face->glyph->bitmap_left;
1393 bitmap->top = ft_face->glyph->bitmap_top;
1394 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1396 return 0;
1400 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1401 int *x, int *y)
1403 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1404 FT_Face ft_face = ftfont_info->ft_size->face;
1406 if (ftfont_info->ft_size != ft_face->size)
1407 FT_Activate_Size (ftfont_info->ft_size);
1408 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1409 return -1;
1410 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1411 return -1;
1412 if (idx >= ft_face->glyph->outline.n_points)
1413 return -1;
1414 *x = ft_face->glyph->outline.points[idx].x;
1415 *y = ft_face->glyph->outline.points[idx].y;
1416 return 0;
1419 #ifdef HAVE_LIBOTF
1421 static Lisp_Object
1422 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1424 Lisp_Object scripts, langsyses, features, sym;
1425 int i, j, k, l;
1427 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1429 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1431 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1433 OTF_LangSys *otf_langsys;
1435 if (j >= 0)
1436 otf_langsys = otf_script->LangSys + j;
1437 else if (otf_script->DefaultLangSysOffset)
1438 otf_langsys = &otf_script->DefaultLangSys;
1439 else
1440 break;
1442 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1444 l = otf_langsys->FeatureIndex[k];
1445 if (l >= gsub_gpos->FeatureList.FeatureCount)
1446 continue;
1447 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1448 features = Fcons (sym, features);
1450 if (j >= 0)
1451 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1452 else
1453 sym = Qnil;
1454 langsyses = Fcons (Fcons (sym, features), langsyses);
1457 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1458 scripts = Fcons (Fcons (sym, langsyses), scripts);
1460 return scripts;
1465 Lisp_Object
1466 ftfont_otf_capability (struct font *font)
1468 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1469 OTF *otf = ftfont_get_otf (ftfont_info);
1470 Lisp_Object gsub_gpos;
1472 if (! otf)
1473 return Qnil;
1474 gsub_gpos = Fcons (Qnil, Qnil);
1475 if (OTF_get_table (otf, "GSUB") == 0
1476 && otf->gsub->FeatureList.FeatureCount > 0)
1477 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1478 if (OTF_get_table (otf, "GPOS") == 0
1479 && otf->gpos->FeatureList.FeatureCount > 0)
1480 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1481 return gsub_gpos;
1484 #ifdef HAVE_M17N_FLT
1486 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1487 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1488 /* We can use the new feature of libotf and m17n-flt to handle the
1489 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1490 some Agian scripts. */
1491 #define M17N_FLT_USE_NEW_FEATURE
1492 #endif
1494 struct MFLTFontFT
1496 MFLTFont flt_font;
1497 struct font *font;
1498 FT_Face ft_face;
1499 OTF *otf;
1500 FT_Matrix *matrix;
1503 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1504 We use this structure instead of MFLTGlyph to utilize the new
1505 feature of libotf ver.0.9.15 which requires saving and restoring
1506 the value of OTF_GlyphString.positioning_type in the succeeding
1507 calls of the callback function MFLTFont.drive_otf (which is set to
1508 ftfont_drive_otf). */
1510 typedef struct {
1511 MFLTGlyph g;
1512 unsigned int libotf_positioning_type;
1513 } MFLTGlyphFT;
1515 static int
1516 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1517 int from, int to)
1519 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1520 FT_Face ft_face = flt_font_ft->ft_face;
1521 MFLTGlyphFT *g;
1523 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1524 if (! g->g.encoded)
1526 FT_UInt code = FT_Get_Char_Index (ft_face, g->g.code);
1528 g->g.code = code > 0 ? code : FONT_INVALID_CODE;
1529 g->g.encoded = 1;
1531 return 0;
1534 /* Operators for 26.6 fixed fractional pixel format */
1536 #define FLOOR(x) ((x) & -64)
1537 #define CEIL(x) (((x)+63) & -64)
1538 #define ROUND(x) (((x)+32) & -64)
1540 static int
1541 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1542 int from, int to)
1544 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1545 FT_Face ft_face = flt_font_ft->ft_face;
1546 MFLTGlyphFT *g;
1548 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1549 if (! g->g.measured)
1551 if (g->g.code != FONT_INVALID_CODE)
1553 FT_Glyph_Metrics *m;
1555 if (FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_DEFAULT) != 0
1556 && FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_NO_HINTING) != 0)
1557 emacs_abort ();
1558 m = &ft_face->glyph->metrics;
1559 if (flt_font_ft->matrix)
1561 FT_Vector v[4];
1562 int i;
1564 v[0].x = v[1].x = m->horiBearingX;
1565 v[2].x = v[3].x = m->horiBearingX + m->width;
1566 v[0].y = v[2].y = m->horiBearingY;
1567 v[1].y = v[3].y = m->horiBearingY - m->height;
1568 for (i = 0; i < 4; i++)
1569 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1570 g->g.lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1571 g->g.rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1572 g->g.ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1573 g->g.descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1575 else
1577 g->g.lbearing = FLOOR (m->horiBearingX);
1578 g->g.rbearing = CEIL (m->horiBearingX + m->width);
1579 g->g.ascent = CEIL (m->horiBearingY);
1580 g->g.descent = - FLOOR (m->horiBearingY - m->height);
1582 g->g.xadv = ROUND (ft_face->glyph->advance.x);
1584 else
1586 g->g.lbearing = 0;
1587 g->g.rbearing = g->g.xadv = flt_font_ft->font->space_width << 6;
1588 g->g.ascent = flt_font_ft->font->ascent << 6;
1589 g->g.descent = flt_font_ft->font->descent << 6;
1591 g->g.yadv = 0;
1592 g->g.measured = 1;
1594 return 0;
1597 static int
1598 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1600 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1602 #define FEATURE_ANY(IDX) \
1603 (spec->features[IDX] \
1604 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1606 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1607 OTF *otf = flt_font_ft->otf;
1608 OTF_Tag *tags;
1609 int i, n;
1610 bool negative;
1612 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1613 /* Return true iff any of GSUB or GPOS support the script (and
1614 language). */
1615 return (otf
1616 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1617 NULL, 0) > 0
1618 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1619 NULL, 0) > 0));
1621 for (i = 0; i < 2; i++)
1622 if (! FEATURE_ANY (i))
1624 if (FEATURE_NONE (i))
1626 if (otf
1627 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1628 NULL, 0) > 0)
1629 return 0;
1630 continue;
1632 if (spec->features[i][0] == 0xFFFFFFFF)
1634 if (! otf
1635 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1636 NULL, 0) <= 0)
1637 continue;
1639 else if (! otf)
1640 return 0;
1641 for (n = 1; spec->features[i][n]; n++);
1642 USE_SAFE_ALLOCA;
1643 SAFE_NALLOCA (tags, 1, n);
1644 for (n = 0, negative = 0; spec->features[i][n]; n++)
1646 if (spec->features[i][n] == 0xFFFFFFFF)
1647 negative = 1;
1648 else if (negative)
1649 tags[n - 1] = spec->features[i][n] | 0x80000000;
1650 else
1651 tags[n] = spec->features[i][n];
1653 bool passed = true;
1654 #ifndef M17N_FLT_USE_NEW_FEATURE
1655 passed = n - negative > 0;
1656 #endif
1657 if (passed)
1658 passed = (OTF_check_features (otf, i == 0, spec->script,
1659 spec->langsys, tags, n - negative)
1660 != 1);
1661 SAFE_FREE ();
1662 if (passed)
1663 return 0;
1665 return 1;
1666 #undef FEATURE_NONE
1667 #undef FEATURE_ANY
1670 #define DEVICE_DELTA(table, size) \
1671 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1672 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1673 : 0)
1675 static void
1676 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1677 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1679 if (anchor->AnchorFormat == 2)
1681 FT_Outline *outline;
1682 int ap = anchor->f.f1.AnchorPoint;
1684 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1685 outline = &ft_face->glyph->outline;
1686 if (ap < outline->n_points)
1688 *x = outline->points[ap].x << 6;
1689 *y = outline->points[ap].y << 6;
1692 else if (anchor->AnchorFormat == 3)
1694 if (anchor->f.f2.XDeviceTable.offset
1695 && anchor->f.f2.XDeviceTable.DeltaValue)
1696 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1697 if (anchor->f.f2.YDeviceTable.offset
1698 && anchor->f.f2.YDeviceTable.DeltaValue)
1699 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1703 static OTF_GlyphString otf_gstring;
1705 static void
1706 setup_otf_gstring (int size)
1708 if (otf_gstring.size < size)
1710 ptrdiff_t new_size = otf_gstring.size;
1711 xfree (otf_gstring.glyphs);
1712 otf_gstring.glyphs = xpalloc (NULL, &new_size, size - otf_gstring.size,
1713 INT_MAX, sizeof *otf_gstring.glyphs);
1714 otf_gstring.size = new_size;
1716 otf_gstring.used = size;
1717 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1720 #ifdef M17N_FLT_USE_NEW_FEATURE
1722 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1723 #define PACK_OTF_TAG(TAG) \
1724 ((((TAG) & 0x7F000000) >> 3) \
1725 | (((TAG) & 0x7F0000) >> 2) \
1726 | (((TAG) & 0x7F00) >> 1) \
1727 | ((TAG) & 0x7F))
1729 /* Assuming that FONT is an OpenType font, apply OpenType features
1730 specified in SPEC on glyphs between FROM and TO of IN, and record
1731 the lastly applied feature in each glyph of IN. If OUT is not
1732 NULL, append the resulting glyphs to OUT while storing glyph
1733 position adjustment information in ADJUSTMENT. */
1735 static int
1736 ftfont_drive_otf (MFLTFont *font,
1737 MFLTOtfSpec *spec,
1738 MFLTGlyphString *in,
1739 int from,
1740 int to,
1741 MFLTGlyphString *out,
1742 MFLTGlyphAdjustment *adjustment)
1744 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1745 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
1746 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
1747 FT_Face ft_face = flt_font_ft->ft_face;
1748 OTF *otf = flt_font_ft->otf;
1749 int len = to - from;
1750 int i, j, gidx;
1751 OTF_Glyph *otfg;
1752 char script[5], *langsys = NULL;
1753 char *gsub_features = NULL, *gpos_features = NULL;
1754 OTF_Feature *features;
1756 if (len == 0)
1757 return from;
1758 OTF_tag_name (spec->script, script);
1760 char langsysbuf[5];
1761 if (spec->langsys)
1763 langsys = langsysbuf;
1764 OTF_tag_name (spec->langsys, langsys);
1767 USE_SAFE_ALLOCA;
1768 for (i = 0; i < 2; i++)
1770 char *p;
1772 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1774 for (j = 0; spec->features[i][j]; j++);
1775 SAFE_NALLOCA (p, 6, j);
1776 if (i == 0)
1777 gsub_features = p;
1778 else
1779 gpos_features = p;
1780 for (j = 0; spec->features[i][j]; j++)
1782 if (spec->features[i][j] == 0xFFFFFFFF)
1783 *p++ = '*', *p++ = ',';
1784 else
1786 OTF_tag_name (spec->features[i][j], p);
1787 p[4] = ',';
1788 p += 5;
1791 *--p = '\0';
1795 setup_otf_gstring (len);
1796 for (i = 0; i < len; i++)
1798 otf_gstring.glyphs[i].c = in_glyphs[i].g.c & 0x11FFFF;
1799 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
1800 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1801 otf_gstring.glyphs[i].positioning_type = in_glyphs[i].libotf_positioning_type;
1802 #endif
1805 OTF_drive_gdef (otf, &otf_gstring);
1806 gidx = out ? out->used : from;
1808 if (gsub_features && out)
1810 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1811 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1812 gsub_features) < 0)
1813 goto simple_copy;
1814 #else
1815 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1816 gsub_features) < 0)
1817 goto simple_copy;
1818 #endif
1819 if (out->allocated < out->used + otf_gstring.used)
1821 SAFE_FREE ();
1822 return -2;
1824 features = otf->gsub->FeatureList.Feature;
1825 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1827 MFLTGlyphFT *g;
1828 int min_from, max_to;
1829 int feature_idx;
1831 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1832 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1833 #else
1834 feature_idx = otfg->positioning_type >> 4;
1835 #endif
1836 g = out_glyphs + out->used;
1837 *g = in_glyphs[otfg->f.index.from];
1838 if (g->g.code != otfg->glyph_id)
1840 g->g.c = 0;
1841 g->g.code = otfg->glyph_id;
1842 g->g.measured = 0;
1844 out->used++;
1845 min_from = g->g.from;
1846 max_to = g->g.to;
1847 if (otfg->f.index.from < otfg->f.index.to)
1849 /* OTFG substitutes multiple glyphs in IN. */
1850 for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
1852 if (min_from > in_glyphs[j].g.from)
1853 min_from = in_glyphs[j].g.from;
1854 if (max_to < in_glyphs[j].g.to)
1855 max_to = in_glyphs[j].g.to;
1857 g->g.from = min_from;
1858 g->g.to = max_to;
1860 if (feature_idx)
1862 unsigned int tag = features[feature_idx - 1].FeatureTag;
1863 tag = PACK_OTF_TAG (tag);
1864 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1866 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1867 g->libotf_positioning_type
1868 = otfg->positioning_type & OTF_positioning_type_components_mask;
1869 #endif
1870 for (i++, otfg++; (i < otf_gstring.used
1871 && otfg->f.index.from == otfg[-1].f.index.from);
1872 i++, otfg++)
1874 g = out_glyphs + out->used;
1875 *g = in_glyphs[otfg->f.index.to];
1876 if (g->g.code != otfg->glyph_id)
1878 g->g.c = 0;
1879 g->g.code = otfg->glyph_id;
1880 g->g.measured = 0;
1882 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1883 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1884 #else
1885 feature_idx = otfg->positioning_type >> 4;
1886 #endif
1887 if (feature_idx)
1889 unsigned int tag = features[feature_idx - 1].FeatureTag;
1890 tag = PACK_OTF_TAG (tag);
1891 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1893 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1894 g->libotf_positioning_type
1895 = otfg->positioning_type & OTF_positioning_type_components_mask;
1896 #endif
1897 out->used++;
1901 else if (gsub_features)
1903 /* Just for checking which features will be applied. */
1904 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1905 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1906 gsub_features) < 0)
1907 goto simple_copy;
1908 #else
1909 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1910 gsub_features) < 0)
1911 goto simple_copy;
1912 #endif
1913 features = otf->gsub->FeatureList.Feature;
1914 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1915 otfg++)
1917 int feature_idx;
1918 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1919 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1920 #else
1921 feature_idx = otfg->positioning_type >> 4;
1922 #endif
1923 if (feature_idx)
1925 unsigned int tag = features[feature_idx - 1].FeatureTag;
1926 tag = PACK_OTF_TAG (tag);
1927 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1929 MFLTGlyphFT *g = in_glyphs + j;
1930 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1935 else if (out)
1937 if (out->allocated < out->used + len)
1939 SAFE_FREE ();
1940 return -2;
1942 for (i = 0; i < len; i++)
1943 out_glyphs[out->used++] = in_glyphs[i];
1946 if (gpos_features && out)
1948 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
1949 int x_ppem, y_ppem, x_scale, y_scale;
1951 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1952 if (OTF_drive_gpos_features (otf, &otf_gstring, script, langsys,
1953 gpos_features) < 0)
1955 SAFE_FREE ();
1956 return to;
1958 #else
1959 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1960 gpos_features) < 0)
1962 SAFE_FREE ();
1963 return to;
1965 #endif
1966 features = otf->gpos->FeatureList.Feature;
1967 x_ppem = ft_face->size->metrics.x_ppem;
1968 y_ppem = ft_face->size->metrics.y_ppem;
1969 x_scale = ft_face->size->metrics.x_scale;
1970 y_scale = ft_face->size->metrics.y_scale;
1972 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
1973 i < otf_gstring.used; i++, otfg++)
1975 MFLTGlyphAdjustment *adjust = adjustment;
1976 MFLTGlyphFT *prev;
1977 int positioning_type, feature_idx;
1979 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1980 positioning_type = OTF_POSITIONING_TYPE_GET_FORMAT (otfg);
1981 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1982 #else
1983 positioning_type = otfg->positioning_type & 0xF;
1984 feature_idx = otfg->positioning_type >> 4;
1985 #endif
1986 if (feature_idx)
1988 unsigned int tag = features[feature_idx - 1].FeatureTag;
1989 tag = PACK_OTF_TAG (tag);
1990 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1993 if (! otfg->glyph_id)
1994 /* This is a pseudo glyph that contains positioning
1995 information to be accumulated to a real glyph. */
1996 adjust--;
1997 switch (positioning_type)
1999 case 0:
2000 break;
2001 case 1: /* Single */
2002 case 2: /* Pair */
2004 int format = otfg->f.f1.format;
2006 if (format & OTF_XPlacement)
2007 adjust->xoff
2008 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2009 if (format & OTF_XPlaDevice)
2010 adjust->xoff
2011 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2012 if (format & OTF_YPlacement)
2013 adjust->yoff
2014 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2015 if (format & OTF_YPlaDevice)
2016 adjust->yoff
2017 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2018 if (format & OTF_XAdvance)
2019 adjust->xadv
2020 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2021 if (format & OTF_XAdvDevice)
2022 adjust->xadv
2023 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2024 if (format & OTF_YAdvance)
2025 adjust->yadv
2026 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2027 if (format & OTF_YAdvDevice)
2028 adjust->yadv
2029 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2030 adjust->set = 1;
2032 break;
2033 case 3: /* Cursive */
2034 /* Not yet supported. */
2035 break;
2036 case 4: /* Mark-to-Base */
2037 case 5: /* Mark-to-Ligature */
2038 if (! base)
2039 break;
2040 prev = base;
2041 goto label_adjust_anchor;
2042 default: /* i.e. case 6 Mark-to-Mark */
2043 if (! mark)
2044 break;
2045 prev = mark;
2046 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2048 int distance = OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg);
2050 if (distance > 0)
2052 prev = g - distance;
2053 if (prev < out_glyphs)
2054 prev = mark;
2057 #endif
2059 label_adjust_anchor:
2061 int base_x, base_y, mark_x, mark_y;
2062 int this_from, this_to;
2064 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2065 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2066 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2067 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2069 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2070 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2071 x_ppem, y_ppem, &base_x, &base_y);
2072 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2073 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2074 x_ppem, y_ppem, &mark_x, &mark_y);
2075 adjust->xoff = (base_x - mark_x);
2076 adjust->yoff = - (base_y - mark_y);
2077 adjust->back = (g - prev);
2078 adjust->xadv = 0;
2079 adjust->advance_is_absolute = 1;
2080 adjust->set = 1;
2081 this_from = g->g.from;
2082 this_to = g->g.to;
2083 for (j = 0; prev + j < g; j++)
2085 if (this_from > prev[j].g.from)
2086 this_from = prev[j].g.from;
2087 if (this_to < prev[j].g.to)
2088 this_to = prev[j].g.to;
2090 for (; prev <= g; prev++)
2092 prev->g.from = this_from;
2093 prev->g.to = this_to;
2097 if (otfg->glyph_id)
2099 if (otfg->GlyphClass == OTF_GlyphClass0)
2100 base = mark = g;
2101 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2102 mark = g;
2103 else
2104 base = g;
2105 g++, adjustment++;
2109 else if (gpos_features)
2111 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2112 gpos_features) < 0)
2114 SAFE_FREE ();
2115 return to;
2117 features = otf->gpos->FeatureList.Feature;
2118 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2119 i++, otfg++)
2120 if (otfg->positioning_type & 0xF)
2122 int feature_idx = otfg->positioning_type >> 4;
2124 if (feature_idx)
2126 unsigned int tag = features[feature_idx - 1].FeatureTag;
2127 tag = PACK_OTF_TAG (tag);
2128 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2130 MFLTGlyphFT *g = in_glyphs + j;
2131 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2136 SAFE_FREE ();
2137 return to;
2139 simple_copy:
2140 SAFE_FREE ();
2141 if (! out)
2142 return to;
2143 if (out->allocated < out->used + len)
2144 return -2;
2145 font->get_metrics (font, in, from, to);
2146 memcpy (out->glyphs + out->used, in_glyphs, sizeof (MFLTGlyphFT) * len);
2147 out->used += len;
2148 return to;
2151 static int
2152 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2153 MFLTGlyphString *in, int from, int to)
2155 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2158 #else /* not M17N_FLT_USE_NEW_FEATURE */
2160 static int
2161 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2162 int from, int to,
2163 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2165 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2166 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
2167 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
2168 FT_Face ft_face = flt_font_ft->ft_face;
2169 OTF *otf = flt_font_ft->otf;
2170 int len = to - from;
2171 int i, j, gidx;
2172 OTF_Glyph *otfg;
2173 char script[5], *langsys = NULL;
2174 char *gsub_features = NULL, *gpos_features = NULL;
2176 if (len == 0)
2177 return from;
2178 OTF_tag_name (spec->script, script);
2180 char langsysbuf[5];
2181 if (spec->langsys)
2183 langsys = langsysbuf;
2184 OTF_tag_name (spec->langsys, langsys);
2187 USE_SAFE_ALLOCA;
2188 for (i = 0; i < 2; i++)
2190 char *p;
2192 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2194 for (j = 0; spec->features[i][j]; j++);
2195 SAFE_NALLOCA (p, 6, j);
2196 if (i == 0)
2197 gsub_features = p;
2198 else
2199 gpos_features = p;
2200 for (j = 0; spec->features[i][j]; j++)
2202 if (spec->features[i][j] == 0xFFFFFFFF)
2203 *p++ = '*', *p++ = ',';
2204 else
2206 OTF_tag_name (spec->features[i][j], p);
2207 p[4] = ',';
2208 p += 5;
2211 *--p = '\0';
2215 setup_otf_gstring (len);
2216 for (i = 0; i < len; i++)
2218 otf_gstring.glyphs[i].c = in_glyphs[i].g.c;
2219 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
2222 OTF_drive_gdef (otf, &otf_gstring);
2223 gidx = out->used;
2225 if (gsub_features)
2227 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2228 < 0)
2229 goto simple_copy;
2230 if (out->allocated < out->used + otf_gstring.used)
2232 SAFE_FREE ();
2233 return -2;
2235 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2237 MFLTGlyphFT *g;
2238 int min_from, max_to;
2239 int j;
2241 g = out_glyphs + out->used;
2242 *g = in_glyphs[otfg->f.index.from];
2243 if (g->g.code != otfg->glyph_id)
2245 g->g.c = 0;
2246 g->g.code = otfg->glyph_id;
2247 g->g.measured = 0;
2249 out->used++;
2250 min_from = g->g.from;
2251 max_to = g->g.to;
2252 if (otfg->f.index.from < otfg->f.index.to)
2254 /* OTFG substitutes multiple glyphs in IN. */
2255 for (j = from + otfg->f.index.from + 1;
2256 j <= from + otfg->f.index.to; j++)
2258 if (min_from > in->glyphs[j].from)
2259 min_from = in->glyphs[j].from;
2260 if (max_to < in->glyphs[j].to)
2261 max_to = in->glyphs[j].to;
2263 g->g.from = min_from;
2264 g->g.to = max_to;
2266 for (i++, otfg++; (i < otf_gstring.used
2267 && otfg->f.index.from == otfg[-1].f.index.from);
2268 i++, otfg++)
2270 g = out_glyphs + out->used;
2271 *g = in_glyphs[otfg->f.index.to];
2272 if (g->g.code != otfg->glyph_id)
2274 g->g.c = 0;
2275 g->g.code = otfg->glyph_id;
2276 g->g.measured = 0;
2278 out->used++;
2282 else
2284 if (out->allocated < out->used + len)
2286 SAFE_FREE ();
2287 return -2;
2289 for (i = 0; i < len; i++)
2290 out_glyphs[out->used++] = in_glyphs[i];
2293 if (gpos_features)
2295 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
2296 int x_ppem, y_ppem, x_scale, y_scale;
2298 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2299 < 0)
2301 SAFE_FREE ();
2302 return to;
2305 x_ppem = ft_face->size->metrics.x_ppem;
2306 y_ppem = ft_face->size->metrics.y_ppem;
2307 x_scale = ft_face->size->metrics.x_scale;
2308 y_scale = ft_face->size->metrics.y_scale;
2310 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2311 i < otf_gstring.used; i++, otfg++, g++)
2313 MFLTGlyphFT *prev;
2315 if (! otfg->glyph_id)
2316 continue;
2317 switch (otfg->positioning_type)
2319 case 0:
2320 break;
2321 case 1: /* Single */
2322 case 2: /* Pair */
2324 int format = otfg->f.f1.format;
2326 if (format & OTF_XPlacement)
2327 adjustment[i].xoff
2328 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2329 if (format & OTF_XPlaDevice)
2330 adjustment[i].xoff
2331 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2332 if (format & OTF_YPlacement)
2333 adjustment[i].yoff
2334 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2335 if (format & OTF_YPlaDevice)
2336 adjustment[i].yoff
2337 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2338 if (format & OTF_XAdvance)
2339 adjustment[i].xadv
2340 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2341 if (format & OTF_XAdvDevice)
2342 adjustment[i].xadv
2343 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2344 if (format & OTF_YAdvance)
2345 adjustment[i].yadv
2346 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2347 if (format & OTF_YAdvDevice)
2348 adjustment[i].yadv
2349 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2350 adjustment[i].set = 1;
2352 break;
2353 case 3: /* Cursive */
2354 /* Not yet supported. */
2355 break;
2356 case 4: /* Mark-to-Base */
2357 case 5: /* Mark-to-Ligature */
2358 if (! base)
2359 break;
2360 prev = base;
2361 goto label_adjust_anchor;
2362 default: /* i.e. case 6 Mark-to-Mark */
2363 if (! mark)
2364 break;
2365 prev = mark;
2367 label_adjust_anchor:
2369 int base_x, base_y, mark_x, mark_y;
2370 int this_from, this_to;
2372 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2373 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2374 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2375 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2377 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2378 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2379 x_ppem, y_ppem, &base_x, &base_y);
2380 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2381 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2382 x_ppem, y_ppem, &mark_x, &mark_y);
2383 adjustment[i].xoff = (base_x - mark_x);
2384 adjustment[i].yoff = - (base_y - mark_y);
2385 adjustment[i].back = (g - prev);
2386 adjustment[i].xadv = 0;
2387 adjustment[i].advance_is_absolute = 1;
2388 adjustment[i].set = 1;
2389 this_from = g->g.from;
2390 this_to = g->g.to;
2391 for (j = 0; prev + j < g; j++)
2393 if (this_from > prev[j].g.from)
2394 this_from = prev[j].g.from;
2395 if (this_to < prev[j].g.to)
2396 this_to = prev[j].g.to;
2398 for (; prev <= g; prev++)
2400 prev->g.from = this_from;
2401 prev->g.to = this_to;
2405 if (otfg->GlyphClass == OTF_GlyphClass0)
2406 base = mark = g;
2407 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2408 mark = g;
2409 else
2410 base = g;
2413 SAFE_FREE ();
2414 return to;
2416 simple_copy:
2417 SAFE_FREE ();
2418 if (out->allocated < out->used + len)
2419 return -2;
2420 font->get_metrics (font, in, from, to);
2421 memcpy (out_glyphs + out->used, in_glyphs,
2422 sizeof (MFLTGlyphFT) * len);
2423 out->used += len;
2424 return to;
2427 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2429 static MFLTGlyphString gstring;
2431 static bool m17n_flt_initialized;
2433 static Lisp_Object
2434 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2435 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2437 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2438 ptrdiff_t i;
2439 struct MFLTFontFT flt_font_ft;
2440 MFLT *flt = NULL;
2441 bool with_variation_selector = false;
2443 if (! m17n_flt_initialized)
2445 M17N_INIT ();
2446 #ifdef M17N_FLT_USE_NEW_FEATURE
2447 mflt_enable_new_feature = 1;
2448 mflt_try_otf = ftfont_try_otf;
2449 #endif /* M17N_FLT_USE_NEW_FEATURE */
2450 m17n_flt_initialized = 1;
2453 for (i = 0; i < len; i++)
2455 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2456 int c;
2458 if (NILP (g))
2459 break;
2460 c = LGLYPH_CHAR (g);
2461 if (CHAR_VARIATION_SELECTOR_P (c))
2462 with_variation_selector = true;
2465 len = i;
2467 if (otf && with_variation_selector)
2469 setup_otf_gstring (len);
2470 for (i = 0; i < len; i++)
2472 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2474 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2475 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2476 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2478 OTF_drive_cmap (otf, &otf_gstring);
2479 for (i = 0; i < otf_gstring.used; i++)
2481 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2482 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2483 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2485 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2486 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2487 LGSTRING_SET_GLYPH (lgstring, i, g0);
2489 if (len > otf_gstring.used)
2491 len = otf_gstring.used;
2492 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2497 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2499 if (NILP (family))
2500 flt_font_ft.flt_font.family = Mnil;
2501 else
2502 flt_font_ft.flt_font.family
2503 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2505 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2506 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2507 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2508 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2509 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2510 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2511 flt_font_ft.flt_font.internal = NULL;
2512 flt_font_ft.font = font;
2513 flt_font_ft.ft_face = ft_face;
2514 flt_font_ft.otf = otf;
2515 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2517 if (1 < len)
2519 /* A little bit ad hoc. Perhaps, shaper must get script and
2520 language information, and select a proper flt for them
2521 here. */
2522 int c1 = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 1));
2523 /* For the combining characters in the range U+300..U+36F,
2524 "combining" is the sole FLT provided by the m17n-lib. In
2525 addition, it is the sole FLT that can handle the other
2526 combining characters with non-OTF fonts. */
2527 if ((0x300 <= c1 && c1 <= 0x36F)
2528 || (! otf && CHAR_HAS_CATEGORY (c1, '^')))
2529 flt = mflt_get (msymbol ("combining"));
2531 if (! flt && ! otf)
2533 flt = mflt_find (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 0)),
2534 &flt_font_ft.flt_font);
2535 if (! flt)
2536 return make_number (0);
2539 MFLTGlyphFT *glyphs = (MFLTGlyphFT *) gstring.glyphs;
2540 ptrdiff_t allocated = gstring.allocated;
2541 ptrdiff_t incr_min = len - allocated;
2545 if (0 < incr_min)
2547 xfree (glyphs);
2548 glyphs = xpalloc (NULL, &allocated, incr_min, INT_MAX, sizeof *glyphs);
2550 incr_min = 1;
2552 for (i = 0; i < len; i++)
2554 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2555 memset (&glyphs[i], 0, sizeof glyphs[i]);
2556 glyphs[i].g.c = LGLYPH_CHAR (g);
2557 if (with_variation_selector)
2559 glyphs[i].g.code = LGLYPH_CODE (g);
2560 glyphs[i].g.encoded = 1;
2564 gstring.glyph_size = sizeof *glyphs;
2565 gstring.glyphs = (MFLTGlyph *) glyphs;
2566 gstring.allocated = allocated;
2567 gstring.used = len;
2568 gstring.r2l = 0;
2570 while (mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt) == -2);
2572 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2573 return Qnil;
2574 for (i = 0; i < gstring.used; i++)
2576 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2578 g->g.from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->g.from));
2579 g->g.to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->g.to));
2582 for (i = 0; i < gstring.used; i++)
2584 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2585 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2587 if (NILP (lglyph))
2589 lglyph = LGLYPH_NEW ();
2590 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2592 LGLYPH_SET_FROM (lglyph, g->g.from);
2593 LGLYPH_SET_TO (lglyph, g->g.to);
2594 LGLYPH_SET_CHAR (lglyph, g->g.c);
2595 LGLYPH_SET_CODE (lglyph, g->g.code);
2596 LGLYPH_SET_WIDTH (lglyph, g->g.xadv >> 6);
2597 LGLYPH_SET_LBEARING (lglyph, g->g.lbearing >> 6);
2598 LGLYPH_SET_RBEARING (lglyph, g->g.rbearing >> 6);
2599 LGLYPH_SET_ASCENT (lglyph, g->g.ascent >> 6);
2600 LGLYPH_SET_DESCENT (lglyph, g->g.descent >> 6);
2601 if (g->g.adjusted)
2603 Lisp_Object vec = make_uninit_vector (3);
2605 ASET (vec, 0, make_number (g->g.xoff >> 6));
2606 ASET (vec, 1, make_number (g->g.yoff >> 6));
2607 ASET (vec, 2, make_number (g->g.xadv >> 6));
2608 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2611 return make_number (i);
2614 Lisp_Object
2615 ftfont_shape (Lisp_Object lgstring)
2617 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2618 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2619 OTF *otf = ftfont_get_otf (ftfont_info);
2621 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2622 &ftfont_info->matrix);
2625 #endif /* HAVE_M17N_FLT */
2627 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2630 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2632 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2633 OTF *otf = ftfont_get_otf (ftfont_info);
2635 if (! otf)
2636 return 0;
2637 return OTF_get_variation_glyphs (otf, c, variations);
2640 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2641 #endif /* HAVE_LIBOTF */
2643 static const char *const ftfont_booleans [] = {
2644 ":antialias",
2645 ":hinting",
2646 ":verticallayout",
2647 ":autohint",
2648 ":globaladvance",
2649 ":outline",
2650 ":scalable",
2651 ":minspace",
2652 ":embolden",
2653 NULL,
2656 static const char *const ftfont_non_booleans [] = {
2657 ":family",
2658 ":familylang",
2659 ":style",
2660 ":stylelang",
2661 ":fullname",
2662 ":fullnamelang",
2663 ":slant",
2664 ":weight",
2665 ":size",
2666 ":width",
2667 ":aspect",
2668 ":pixelsize",
2669 ":spacing",
2670 ":foundry",
2671 ":hintstyle",
2672 ":file",
2673 ":index",
2674 ":ftface",
2675 ":rasterizer",
2676 ":scale",
2677 ":dpi",
2678 ":rgba",
2679 ":lcdfilter",
2680 ":charset",
2681 ":lang",
2682 ":fontversion",
2683 ":capability",
2684 NULL,
2687 void
2688 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2690 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2694 Lisp_Object
2695 ftfont_combining_capability (struct font *font)
2697 #ifdef HAVE_M17N_FLT
2698 return Qt;
2699 #else
2700 return Qnil;
2701 #endif
2704 static struct font_driver const ftfont_driver =
2706 /* We can't draw a text without device dependent functions. */
2707 .type = LISPSYM_INITIALLY (Qfreetype),
2708 .get_cache = ftfont_get_cache,
2709 .list = ftfont_list,
2710 .match = ftfont_match,
2711 .list_family = ftfont_list_family,
2712 .open = ftfont_open,
2713 .close = ftfont_close,
2714 .has_char = ftfont_has_char,
2715 .encode_char = ftfont_encode_char,
2716 .text_extents = ftfont_text_extents,
2717 .get_bitmap = ftfont_get_bitmap,
2718 .anchor_point = ftfont_anchor_point,
2719 #ifdef HAVE_LIBOTF
2720 .otf_capability = ftfont_otf_capability,
2721 #endif
2722 #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
2723 .shape = ftfont_shape,
2724 #endif
2725 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2726 .get_variation_glyphs = ftfont_variation_glyphs,
2727 #endif
2728 .filter_properties = ftfont_filter_properties,
2729 .combining_capability = ftfont_combining_capability,
2732 void
2733 syms_of_ftfont (void)
2735 /* Symbolic type of this font-driver. */
2736 DEFSYM (Qfreetype, "freetype");
2738 /* Fontconfig's generic families and their aliases. */
2739 DEFSYM (Qmonospace, "monospace");
2740 DEFSYM (Qsans_serif, "sans-serif");
2741 DEFSYM (Qsans, "sans");
2742 DEFSYM (Qsans__serif, "sans serif");
2744 staticpro (&freetype_font_cache);
2745 freetype_font_cache = list1 (Qt);
2747 staticpro (&ftfont_generic_family_list);
2748 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2749 Fcons (Qsans_serif, Qt),
2750 Fcons (Qsans, Qt));
2752 staticpro (&ft_face_cache);
2753 ft_face_cache = Qnil;
2755 register_font_driver (&ftfont_driver, NULL);