Port to OpenIndiana
[emacs.git] / src / ftfont.c
blob35f5923376116ccaea75d7e2be8e4b37dfbc2b66
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2017 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;
768 goto finish;
770 err:
771 /* We come here because of unexpected error in fontconfig API call
772 (usually insufficient memory). */
773 if (pattern)
775 FcPatternDestroy (pattern);
776 pattern = NULL;
778 if (*otspec)
780 if ((*otspec)->nfeatures[0] > 0)
781 free ((*otspec)->features[0]);
782 if ((*otspec)->nfeatures[1] > 0)
783 free ((*otspec)->features[1]);
784 free (*otspec);
785 *otspec = NULL;
788 finish:
789 if (langset) FcLangSetDestroy (langset);
790 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
791 return pattern;
794 Lisp_Object
795 ftfont_list (struct frame *f, Lisp_Object spec)
797 Lisp_Object val = Qnil, family, adstyle;
798 int i;
799 FcPattern *pattern;
800 FcFontSet *fontset = NULL;
801 FcObjectSet *objset = NULL;
802 FcCharSet *charset;
803 Lisp_Object chars = Qnil;
804 char otlayout[15]; /* For "otlayout:XXXX" */
805 struct OpenTypeSpec *otspec = NULL;
806 int spacing = -1;
807 const char *langname = NULL;
809 if (! fc_initialized)
811 FcInit ();
812 fc_initialized = 1;
815 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
816 if (! pattern)
817 return Qnil;
818 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
820 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
821 if (! NILP (val))
823 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
824 if (CONSP (val) && VECTORP (XCDR (val)))
825 chars = XCDR (val);
827 val = Qnil;
829 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
830 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
831 family = AREF (spec, FONT_FAMILY_INDEX);
832 if (! NILP (family))
834 Lisp_Object resolved;
836 resolved = ftfont_resolve_generic_family (family, pattern);
837 if (! NILP (resolved))
839 FcPatternDel (pattern, FC_FAMILY);
840 if (! FcPatternAddString (pattern, FC_FAMILY,
841 SYMBOL_FcChar8 (resolved)))
842 goto err;
845 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
846 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
847 adstyle = Qnil;
848 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
849 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
850 FC_STYLE, FC_FILE, FC_INDEX,
851 #ifdef FC_CAPABILITY
852 FC_CAPABILITY,
853 #endif /* FC_CAPABILITY */
854 #ifdef FC_FONTFORMAT
855 FC_FONTFORMAT,
856 #endif
857 NULL);
858 if (! objset)
859 goto err;
860 if (! NILP (chars))
861 FcObjectSetAdd (objset, FC_CHARSET);
863 fontset = FcFontList (NULL, pattern, objset);
864 if (! fontset || fontset->nfont == 0)
865 goto finish;
866 #if 0
867 /* Need fix because this finds any fonts. */
868 if (fontset->nfont == 0 && ! NILP (family))
870 /* Try matching with configuration. For instance, the
871 configuration may specify "Nimbus Mono L" as an alias of
872 "Courier". */
873 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
874 SYMBOL_FcChar8 (family), NULL);
875 FcChar8 *fam;
877 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
879 for (i = 0;
880 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
881 i++)
883 FcPatternDel (pattern, FC_FAMILY);
884 FcPatternAddString (pattern, FC_FAMILY, fam);
885 FcFontSetDestroy (fontset);
886 fontset = FcFontList (NULL, pattern, objset);
887 if (fontset && fontset->nfont > 0)
888 break;
892 #endif
893 for (i = 0; i < fontset->nfont; i++)
895 Lisp_Object entity;
897 if (spacing >= 0)
899 int this;
901 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
902 == FcResultMatch)
903 && spacing != this)
904 continue;
907 #ifdef FC_CAPABILITY
908 if (otlayout[0])
910 FcChar8 *this;
912 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
913 != FcResultMatch
914 || ! strstr ((char *) this, otlayout))
915 continue;
917 #endif /* FC_CAPABILITY */
918 #ifdef HAVE_LIBOTF
919 if (otspec)
921 FcChar8 *file;
922 bool passed;
923 OTF *otf;
925 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
926 != FcResultMatch)
927 continue;
928 otf = OTF_open ((char *) file);
929 if (! otf)
930 continue;
931 passed = (OTF_check_features (otf, 1, otspec->script_tag,
932 otspec->langsys_tag,
933 otspec->features[0],
934 otspec->nfeatures[0]) == 1
935 && OTF_check_features (otf, 0, otspec->script_tag,
936 otspec->langsys_tag,
937 otspec->features[1],
938 otspec->nfeatures[1]) == 1);
939 OTF_close (otf);
940 if (!passed)
941 continue;
943 #endif /* HAVE_LIBOTF */
944 if (VECTORP (chars))
946 ptrdiff_t j;
948 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
949 != FcResultMatch)
950 continue;
951 for (j = 0; j < ASIZE (chars); j++)
952 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
953 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
954 break;
955 if (j == ASIZE (chars))
956 continue;
958 if (! NILP (adstyle) || langname)
960 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
962 if (! NILP (adstyle)
963 && (NILP (this_adstyle)
964 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
965 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
966 continue;
967 if (langname
968 && ! NILP (this_adstyle)
969 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
970 continue;
972 entity = ftfont_pattern_entity (fontset->fonts[i],
973 AREF (spec, FONT_EXTRA_INDEX));
974 if (! NILP (entity))
975 val = Fcons (entity, val);
977 val = Fnreverse (val);
978 goto finish;
980 err:
981 /* We come here because of unexpected error in fontconfig API call
982 (usually insufficient memory). */
983 val = Qnil;
985 finish:
986 FONT_ADD_LOG ("ftfont-list", spec, val);
987 if (objset) FcObjectSetDestroy (objset);
988 if (fontset) FcFontSetDestroy (fontset);
989 if (pattern) FcPatternDestroy (pattern);
990 return val;
993 Lisp_Object
994 ftfont_match (struct frame *f, Lisp_Object spec)
996 Lisp_Object entity = Qnil;
997 FcPattern *pattern, *match = NULL;
998 FcResult result;
999 char otlayout[15]; /* For "otlayout:XXXX" */
1000 struct OpenTypeSpec *otspec = NULL;
1001 const char *langname = NULL;
1003 if (! fc_initialized)
1005 FcInit ();
1006 fc_initialized = 1;
1009 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1010 if (! pattern)
1011 return Qnil;
1013 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1015 FcValue value;
1017 value.type = FcTypeDouble;
1018 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1019 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1021 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1023 FcDefaultSubstitute (pattern);
1024 match = FcFontMatch (NULL, pattern, &result);
1025 if (match)
1027 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1028 FcPatternDestroy (match);
1029 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1030 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1031 ftfont_generic_family_list))
1032 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1033 AREF (entity, FONT_FAMILY_INDEX))))
1034 entity = Qnil;
1037 FcPatternDestroy (pattern);
1039 FONT_ADD_LOG ("ftfont-match", spec, entity);
1040 return entity;
1043 Lisp_Object
1044 ftfont_list_family (struct frame *f)
1046 Lisp_Object list = Qnil;
1047 FcPattern *pattern = NULL;
1048 FcFontSet *fontset = NULL;
1049 FcObjectSet *objset = NULL;
1050 int i;
1052 if (! fc_initialized)
1054 FcInit ();
1055 fc_initialized = 1;
1058 pattern = FcPatternCreate ();
1059 if (! pattern)
1060 goto finish;
1061 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1062 if (! objset)
1063 goto finish;
1064 fontset = FcFontList (NULL, pattern, objset);
1065 if (! fontset)
1066 goto finish;
1068 for (i = 0; i < fontset->nfont; i++)
1070 FcPattern *pat = fontset->fonts[i];
1071 FcChar8 *str;
1073 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1074 list = Fcons (intern ((char *) str), list);
1077 finish:
1078 if (objset) FcObjectSetDestroy (objset);
1079 if (fontset) FcFontSetDestroy (fontset);
1080 if (pattern) FcPatternDestroy (pattern);
1082 return list;
1086 Lisp_Object
1087 ftfont_open2 (struct frame *f,
1088 Lisp_Object entity,
1089 int pixel_size,
1090 Lisp_Object font_object)
1092 struct ftfont_info *ftfont_info;
1093 struct font *font;
1094 struct ftfont_cache_data *cache_data;
1095 FT_Face ft_face;
1096 FT_Size ft_size;
1097 FT_UInt size;
1098 Lisp_Object val, filename, idx, cache;
1099 bool scalable;
1100 int spacing;
1101 int i;
1102 double upEM;
1104 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1105 if (! CONSP (val))
1106 return Qnil;
1107 val = XCDR (val);
1108 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1109 if (NILP (cache))
1110 return Qnil;
1111 filename = XCAR (val);
1112 idx = XCDR (val);
1113 val = XCDR (cache);
1114 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1115 ft_face = cache_data->ft_face;
1116 if (XSAVE_INTEGER (val, 1) > 0)
1118 /* FT_Face in this cache is already used by the different size. */
1119 if (FT_New_Size (ft_face, &ft_size) != 0)
1120 return Qnil;
1121 if (FT_Activate_Size (ft_size) != 0)
1123 FT_Done_Size (ft_size);
1124 return Qnil;
1127 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1128 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1129 if (size == 0)
1130 size = pixel_size;
1131 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1133 if (XSAVE_INTEGER (val, 1) == 0)
1134 FT_Done_Face (ft_face);
1135 return Qnil;
1138 ASET (font_object, FONT_FILE_INDEX, filename);
1139 font = XFONT_OBJECT (font_object);
1140 ftfont_info = (struct ftfont_info *) font;
1141 ftfont_info->ft_size = ft_face->size;
1142 ftfont_info->index = XINT (idx);
1143 #ifdef HAVE_LIBOTF
1144 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1145 ftfont_info->otf = NULL;
1146 #endif /* HAVE_LIBOTF */
1147 /* This means that there's no need of transformation. */
1148 ftfont_info->matrix.xx = 0;
1149 font->pixel_size = size;
1150 font->driver = &ftfont_driver;
1151 font->encoding_charset = font->repertory_charset = -1;
1153 upEM = ft_face->units_per_EM;
1154 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1155 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1156 if (scalable)
1158 font->ascent = ft_face->ascender * size / upEM + 0.5;
1159 font->descent = - ft_face->descender * size / upEM + 0.5;
1160 font->height = ft_face->height * size / upEM + 0.5;
1162 else
1164 font->ascent = ft_face->size->metrics.ascender >> 6;
1165 font->descent = - ft_face->size->metrics.descender >> 6;
1166 font->height = ft_face->size->metrics.height >> 6;
1168 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1169 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1170 else
1171 spacing = FC_PROPORTIONAL;
1172 if (spacing != FC_PROPORTIONAL
1173 #ifdef FC_DUAL
1174 && spacing != FC_DUAL
1175 #endif /* FC_DUAL */
1177 font->min_width = font->average_width = font->space_width
1178 = (scalable ? ft_face->max_advance_width * size / upEM + 0.5
1179 : ft_face->size->metrics.max_advance >> 6);
1180 else
1182 int n;
1184 font->min_width = font->average_width = font->space_width = 0;
1185 for (i = 32, n = 0; i < 127; i++)
1186 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1188 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1190 if (this_width > 0
1191 && (! font->min_width || font->min_width > this_width))
1192 font->min_width = this_width;
1193 if (i == 32)
1194 font->space_width = this_width;
1195 font->average_width += this_width;
1196 n++;
1198 if (n > 0)
1199 font->average_width /= n;
1202 font->baseline_offset = 0;
1203 font->relative_compose = 0;
1204 font->default_ascent = 0;
1205 font->vertical_centering = 0;
1206 if (scalable)
1208 font->underline_position = (-ft_face->underline_position * size / upEM
1209 + 0.5);
1210 font->underline_thickness = (ft_face->underline_thickness * size / upEM
1211 + 0.5);
1213 else
1215 font->underline_position = -1;
1216 font->underline_thickness = 0;
1219 return font_object;
1222 Lisp_Object
1223 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1225 Lisp_Object font_object;
1226 FT_UInt size;
1227 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1228 if (size == 0)
1229 size = pixel_size;
1230 font_object = font_build_object (VECSIZE (struct ftfont_info),
1231 Qfreetype, entity, size);
1232 return ftfont_open2 (f, entity, pixel_size, font_object);
1235 void
1236 ftfont_close (struct font *font)
1238 /* FIXME: Although this function can be called while garbage-collecting,
1239 the function assumes that Lisp data structures are properly-formed.
1240 This invalid assumption can lead to core dumps (Bug#20890). */
1242 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1243 Lisp_Object val, cache;
1245 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1246 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1247 eassert (CONSP (cache));
1248 val = XCDR (cache);
1249 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1250 if (XSAVE_INTEGER (val, 1) == 0)
1252 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1254 FT_Done_Face (cache_data->ft_face);
1255 #ifdef HAVE_LIBOTF
1256 if (ftfont_info->otf)
1257 OTF_close (ftfont_info->otf);
1258 #endif
1259 cache_data->ft_face = NULL;
1261 else
1262 FT_Done_Size (ftfont_info->ft_size);
1266 ftfont_has_char (Lisp_Object font, int c)
1268 struct charset *cs = NULL;
1270 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1271 && charset_jisx0208 >= 0)
1272 cs = CHARSET_FROM_ID (charset_jisx0208);
1273 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1274 && charset_ksc5601 >= 0)
1275 cs = CHARSET_FROM_ID (charset_ksc5601);
1276 if (cs)
1277 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1279 if (FONT_ENTITY_P (font))
1281 FcCharSet *charset = ftfont_get_fc_charset (font);
1283 return (FcCharSetHasChar (charset, c) == FcTrue);
1285 else
1287 struct ftfont_info *ftfont_info;
1289 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1290 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1291 != 0);
1295 unsigned
1296 ftfont_encode_char (struct font *font, int c)
1298 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1299 FT_Face ft_face = ftfont_info->ft_size->face;
1300 FT_ULong charcode = c;
1301 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1303 return (code > 0 ? code : FONT_INVALID_CODE);
1306 void
1307 ftfont_text_extents (struct font *font, unsigned int *code,
1308 int nglyphs, struct font_metrics *metrics)
1310 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1311 FT_Face ft_face = ftfont_info->ft_size->face;
1312 int i, width = 0;
1313 bool first;
1315 if (ftfont_info->ft_size != ft_face->size)
1316 FT_Activate_Size (ftfont_info->ft_size);
1318 for (i = 0, first = 1; i < nglyphs; i++)
1320 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1322 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1324 if (first)
1326 metrics->lbearing = m->horiBearingX >> 6;
1327 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1328 metrics->ascent = m->horiBearingY >> 6;
1329 metrics->descent = (m->height - m->horiBearingY) >> 6;
1330 first = 0;
1332 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1333 metrics->lbearing = width + (m->horiBearingX >> 6);
1334 if (metrics->rbearing
1335 < width + ((m->horiBearingX + m->width) >> 6))
1336 metrics->rbearing
1337 = width + ((m->horiBearingX + m->width) >> 6);
1338 if (metrics->ascent < (m->horiBearingY >> 6))
1339 metrics->ascent = m->horiBearingY >> 6;
1340 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1341 metrics->descent = (m->height - m->horiBearingY) >> 6;
1342 width += m->horiAdvance >> 6;
1344 else
1345 width += font->space_width;
1347 metrics->width = width;
1351 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1353 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1354 FT_Face ft_face = ftfont_info->ft_size->face;
1355 FT_Int32 load_flags = FT_LOAD_RENDER;
1357 if (ftfont_info->ft_size != ft_face->size)
1358 FT_Activate_Size (ftfont_info->ft_size);
1359 if (bits_per_pixel == 1)
1361 #ifdef FT_LOAD_TARGET_MONO
1362 load_flags |= FT_LOAD_TARGET_MONO;
1363 #else
1364 load_flags |= FT_LOAD_MONOCHROME;
1365 #endif
1367 else if (bits_per_pixel != 8)
1368 /* We don't support such a rendering. */
1369 return -1;
1371 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1372 return -1;
1373 bitmap->bits_per_pixel
1374 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1375 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1376 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1377 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1378 : -1);
1379 if (bitmap->bits_per_pixel < 0)
1380 /* We don't support that kind of pixel mode. */
1381 return -1;
1382 bitmap->rows = ft_face->glyph->bitmap.rows;
1383 bitmap->width = ft_face->glyph->bitmap.width;
1384 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1385 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1386 bitmap->left = ft_face->glyph->bitmap_left;
1387 bitmap->top = ft_face->glyph->bitmap_top;
1388 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1390 return 0;
1394 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1395 int *x, int *y)
1397 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1398 FT_Face ft_face = ftfont_info->ft_size->face;
1400 if (ftfont_info->ft_size != ft_face->size)
1401 FT_Activate_Size (ftfont_info->ft_size);
1402 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1403 return -1;
1404 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1405 return -1;
1406 if (idx >= ft_face->glyph->outline.n_points)
1407 return -1;
1408 *x = ft_face->glyph->outline.points[idx].x;
1409 *y = ft_face->glyph->outline.points[idx].y;
1410 return 0;
1413 #ifdef HAVE_LIBOTF
1415 static Lisp_Object
1416 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1418 Lisp_Object scripts, langsyses, features, sym;
1419 int i, j, k, l;
1421 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1423 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1425 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1427 OTF_LangSys *otf_langsys;
1429 if (j >= 0)
1430 otf_langsys = otf_script->LangSys + j;
1431 else if (otf_script->DefaultLangSysOffset)
1432 otf_langsys = &otf_script->DefaultLangSys;
1433 else
1434 break;
1436 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1438 l = otf_langsys->FeatureIndex[k];
1439 if (l >= gsub_gpos->FeatureList.FeatureCount)
1440 continue;
1441 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1442 features = Fcons (sym, features);
1444 if (j >= 0)
1445 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1446 else
1447 sym = Qnil;
1448 langsyses = Fcons (Fcons (sym, features), langsyses);
1451 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1452 scripts = Fcons (Fcons (sym, langsyses), scripts);
1454 return scripts;
1459 Lisp_Object
1460 ftfont_otf_capability (struct font *font)
1462 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1463 OTF *otf = ftfont_get_otf (ftfont_info);
1464 Lisp_Object gsub_gpos;
1466 if (! otf)
1467 return Qnil;
1468 gsub_gpos = Fcons (Qnil, Qnil);
1469 if (OTF_get_table (otf, "GSUB") == 0
1470 && otf->gsub->FeatureList.FeatureCount > 0)
1471 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1472 if (OTF_get_table (otf, "GPOS") == 0
1473 && otf->gpos->FeatureList.FeatureCount > 0)
1474 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1475 return gsub_gpos;
1478 #ifdef HAVE_M17N_FLT
1480 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1481 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1482 /* We can use the new feature of libotf and m17n-flt to handle the
1483 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1484 some Agian scripts. */
1485 #define M17N_FLT_USE_NEW_FEATURE
1486 #endif
1488 struct MFLTFontFT
1490 MFLTFont flt_font;
1491 struct font *font;
1492 FT_Face ft_face;
1493 OTF *otf;
1494 FT_Matrix *matrix;
1497 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1498 We use this structure instead of MFLTGlyph to utilize the new
1499 feature of libotf ver.0.9.15 which requires saving and restoring
1500 the value of OTF_GlyphString.positioning_type in the succeeding
1501 calls of the callback function MFLTFont.drive_otf (which is set to
1502 ftfont_drive_otf). */
1504 typedef struct {
1505 MFLTGlyph g;
1506 unsigned int libotf_positioning_type;
1507 } MFLTGlyphFT;
1509 static int
1510 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1511 int from, int to)
1513 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1514 FT_Face ft_face = flt_font_ft->ft_face;
1515 MFLTGlyphFT *g;
1517 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1518 if (! g->g.encoded)
1520 FT_UInt code = FT_Get_Char_Index (ft_face, g->g.code);
1522 g->g.code = code > 0 ? code : FONT_INVALID_CODE;
1523 g->g.encoded = 1;
1525 return 0;
1528 /* Operators for 26.6 fixed fractional pixel format */
1530 #define FLOOR(x) ((x) & -64)
1531 #define CEIL(x) (((x)+63) & -64)
1532 #define ROUND(x) (((x)+32) & -64)
1534 static int
1535 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1536 int from, int to)
1538 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1539 FT_Face ft_face = flt_font_ft->ft_face;
1540 MFLTGlyphFT *g;
1542 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1543 if (! g->g.measured)
1545 if (g->g.code != FONT_INVALID_CODE)
1547 FT_Glyph_Metrics *m;
1549 if (FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_DEFAULT) != 0
1550 && FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_NO_HINTING) != 0)
1551 emacs_abort ();
1552 m = &ft_face->glyph->metrics;
1553 if (flt_font_ft->matrix)
1555 FT_Vector v[4];
1556 int i;
1558 v[0].x = v[1].x = m->horiBearingX;
1559 v[2].x = v[3].x = m->horiBearingX + m->width;
1560 v[0].y = v[2].y = m->horiBearingY;
1561 v[1].y = v[3].y = m->horiBearingY - m->height;
1562 for (i = 0; i < 4; i++)
1563 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1564 g->g.lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1565 g->g.rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1566 g->g.ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1567 g->g.descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1569 else
1571 g->g.lbearing = FLOOR (m->horiBearingX);
1572 g->g.rbearing = CEIL (m->horiBearingX + m->width);
1573 g->g.ascent = CEIL (m->horiBearingY);
1574 g->g.descent = - FLOOR (m->horiBearingY - m->height);
1576 g->g.xadv = ROUND (ft_face->glyph->advance.x);
1578 else
1580 g->g.lbearing = 0;
1581 g->g.rbearing = g->g.xadv = flt_font_ft->font->space_width << 6;
1582 g->g.ascent = flt_font_ft->font->ascent << 6;
1583 g->g.descent = flt_font_ft->font->descent << 6;
1585 g->g.yadv = 0;
1586 g->g.measured = 1;
1588 return 0;
1591 static int
1592 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1594 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1596 #define FEATURE_ANY(IDX) \
1597 (spec->features[IDX] \
1598 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1600 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1601 OTF *otf = flt_font_ft->otf;
1602 OTF_Tag *tags;
1603 int i, n;
1604 bool negative;
1606 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1607 /* Return true iff any of GSUB or GPOS support the script (and
1608 language). */
1609 return (otf
1610 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1611 NULL, 0) > 0
1612 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1613 NULL, 0) > 0));
1615 for (i = 0; i < 2; i++)
1616 if (! FEATURE_ANY (i))
1618 if (FEATURE_NONE (i))
1620 if (otf
1621 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1622 NULL, 0) > 0)
1623 return 0;
1624 continue;
1626 if (spec->features[i][0] == 0xFFFFFFFF)
1628 if (! otf
1629 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1630 NULL, 0) <= 0)
1631 continue;
1633 else if (! otf)
1634 return 0;
1635 for (n = 1; spec->features[i][n]; n++);
1636 USE_SAFE_ALLOCA;
1637 SAFE_NALLOCA (tags, 1, n);
1638 for (n = 0, negative = 0; spec->features[i][n]; n++)
1640 if (spec->features[i][n] == 0xFFFFFFFF)
1641 negative = 1;
1642 else if (negative)
1643 tags[n - 1] = spec->features[i][n] | 0x80000000;
1644 else
1645 tags[n] = spec->features[i][n];
1647 bool passed = true;
1648 #ifndef M17N_FLT_USE_NEW_FEATURE
1649 passed = n - negative > 0;
1650 #endif
1651 if (passed)
1652 passed = (OTF_check_features (otf, i == 0, spec->script,
1653 spec->langsys, tags, n - negative)
1654 != 1);
1655 SAFE_FREE ();
1656 if (passed)
1657 return 0;
1659 return 1;
1660 #undef FEATURE_NONE
1661 #undef FEATURE_ANY
1664 #define DEVICE_DELTA(table, size) \
1665 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1666 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1667 : 0)
1669 static void
1670 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1671 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1673 if (anchor->AnchorFormat == 2)
1675 FT_Outline *outline;
1676 int ap = anchor->f.f1.AnchorPoint;
1678 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1679 outline = &ft_face->glyph->outline;
1680 if (ap < outline->n_points)
1682 *x = outline->points[ap].x << 6;
1683 *y = outline->points[ap].y << 6;
1686 else if (anchor->AnchorFormat == 3)
1688 if (anchor->f.f2.XDeviceTable.offset
1689 && anchor->f.f2.XDeviceTable.DeltaValue)
1690 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1691 if (anchor->f.f2.YDeviceTable.offset
1692 && anchor->f.f2.YDeviceTable.DeltaValue)
1693 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1697 static OTF_GlyphString otf_gstring;
1699 static void
1700 setup_otf_gstring (int size)
1702 if (otf_gstring.size < size)
1704 ptrdiff_t new_size = otf_gstring.size;
1705 xfree (otf_gstring.glyphs);
1706 otf_gstring.glyphs = xpalloc (NULL, &new_size, size - otf_gstring.size,
1707 INT_MAX, sizeof *otf_gstring.glyphs);
1708 otf_gstring.size = new_size;
1710 otf_gstring.used = size;
1711 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1714 #ifdef M17N_FLT_USE_NEW_FEATURE
1716 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1717 #define PACK_OTF_TAG(TAG) \
1718 ((((TAG) & 0x7F000000) >> 3) \
1719 | (((TAG) & 0x7F0000) >> 2) \
1720 | (((TAG) & 0x7F00) >> 1) \
1721 | ((TAG) & 0x7F))
1723 /* Assuming that FONT is an OpenType font, apply OpenType features
1724 specified in SPEC on glyphs between FROM and TO of IN, and record
1725 the lastly applied feature in each glyph of IN. If OUT is not
1726 NULL, append the resulting glyphs to OUT while storing glyph
1727 position adjustment information in ADJUSTMENT. */
1729 static int
1730 ftfont_drive_otf (MFLTFont *font,
1731 MFLTOtfSpec *spec,
1732 MFLTGlyphString *in,
1733 int from,
1734 int to,
1735 MFLTGlyphString *out,
1736 MFLTGlyphAdjustment *adjustment)
1738 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1739 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
1740 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
1741 FT_Face ft_face = flt_font_ft->ft_face;
1742 OTF *otf = flt_font_ft->otf;
1743 int len = to - from;
1744 int i, j, gidx;
1745 OTF_Glyph *otfg;
1746 char script[5], *langsys = NULL;
1747 char *gsub_features = NULL, *gpos_features = NULL;
1748 OTF_Feature *features;
1750 if (len == 0)
1751 return from;
1752 OTF_tag_name (spec->script, script);
1754 char langsysbuf[5];
1755 if (spec->langsys)
1757 langsys = langsysbuf;
1758 OTF_tag_name (spec->langsys, langsys);
1761 USE_SAFE_ALLOCA;
1762 for (i = 0; i < 2; i++)
1764 char *p;
1766 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1768 for (j = 0; spec->features[i][j]; j++);
1769 SAFE_NALLOCA (p, 6, j);
1770 if (i == 0)
1771 gsub_features = p;
1772 else
1773 gpos_features = p;
1774 for (j = 0; spec->features[i][j]; j++)
1776 if (spec->features[i][j] == 0xFFFFFFFF)
1777 *p++ = '*', *p++ = ',';
1778 else
1780 OTF_tag_name (spec->features[i][j], p);
1781 p[4] = ',';
1782 p += 5;
1785 *--p = '\0';
1789 setup_otf_gstring (len);
1790 for (i = 0; i < len; i++)
1792 otf_gstring.glyphs[i].c = in_glyphs[i].g.c & 0x11FFFF;
1793 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
1794 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1795 otf_gstring.glyphs[i].positioning_type = in_glyphs[i].libotf_positioning_type;
1796 #endif
1799 OTF_drive_gdef (otf, &otf_gstring);
1800 gidx = out ? out->used : from;
1802 if (gsub_features && out)
1804 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1805 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1806 gsub_features) < 0)
1807 goto simple_copy;
1808 #else
1809 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1810 gsub_features) < 0)
1811 goto simple_copy;
1812 #endif
1813 if (out->allocated < out->used + otf_gstring.used)
1815 SAFE_FREE ();
1816 return -2;
1818 features = otf->gsub->FeatureList.Feature;
1819 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1821 MFLTGlyphFT *g;
1822 int min_from, max_to;
1823 int feature_idx;
1825 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1826 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1827 #else
1828 feature_idx = otfg->positioning_type >> 4;
1829 #endif
1830 g = out_glyphs + out->used;
1831 *g = in_glyphs[otfg->f.index.from];
1832 if (g->g.code != otfg->glyph_id)
1834 g->g.c = 0;
1835 g->g.code = otfg->glyph_id;
1836 g->g.measured = 0;
1838 out->used++;
1839 min_from = g->g.from;
1840 max_to = g->g.to;
1841 if (otfg->f.index.from < otfg->f.index.to)
1843 /* OTFG substitutes multiple glyphs in IN. */
1844 for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
1846 if (min_from > in_glyphs[j].g.from)
1847 min_from = in_glyphs[j].g.from;
1848 if (max_to < in_glyphs[j].g.to)
1849 max_to = in_glyphs[j].g.to;
1851 g->g.from = min_from;
1852 g->g.to = max_to;
1854 if (feature_idx)
1856 unsigned int tag = features[feature_idx - 1].FeatureTag;
1857 tag = PACK_OTF_TAG (tag);
1858 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1860 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1861 g->libotf_positioning_type
1862 = otfg->positioning_type & OTF_positioning_type_components_mask;
1863 #endif
1864 for (i++, otfg++; (i < otf_gstring.used
1865 && otfg->f.index.from == otfg[-1].f.index.from);
1866 i++, otfg++)
1868 g = out_glyphs + out->used;
1869 *g = in_glyphs[otfg->f.index.to];
1870 if (g->g.code != otfg->glyph_id)
1872 g->g.c = 0;
1873 g->g.code = otfg->glyph_id;
1874 g->g.measured = 0;
1876 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1877 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1878 #else
1879 feature_idx = otfg->positioning_type >> 4;
1880 #endif
1881 if (feature_idx)
1883 unsigned int tag = features[feature_idx - 1].FeatureTag;
1884 tag = PACK_OTF_TAG (tag);
1885 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1887 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1888 g->libotf_positioning_type
1889 = otfg->positioning_type & OTF_positioning_type_components_mask;
1890 #endif
1891 out->used++;
1895 else if (gsub_features)
1897 /* Just for checking which features will be applied. */
1898 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1899 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1900 gsub_features) < 0)
1901 goto simple_copy;
1902 #else
1903 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1904 gsub_features) < 0)
1905 goto simple_copy;
1906 #endif
1907 features = otf->gsub->FeatureList.Feature;
1908 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1909 otfg++)
1911 int feature_idx;
1912 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1913 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1914 #else
1915 feature_idx = otfg->positioning_type >> 4;
1916 #endif
1917 if (feature_idx)
1919 unsigned int tag = features[feature_idx - 1].FeatureTag;
1920 tag = PACK_OTF_TAG (tag);
1921 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1923 MFLTGlyphFT *g = in_glyphs + j;
1924 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1929 else if (out)
1931 if (out->allocated < out->used + len)
1933 SAFE_FREE ();
1934 return -2;
1936 for (i = 0; i < len; i++)
1937 out_glyphs[out->used++] = in_glyphs[i];
1940 if (gpos_features && out)
1942 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
1943 int x_ppem, y_ppem, x_scale, y_scale;
1945 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1946 if (OTF_drive_gpos_features (otf, &otf_gstring, script, langsys,
1947 gpos_features) < 0)
1949 SAFE_FREE ();
1950 return to;
1952 #else
1953 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1954 gpos_features) < 0)
1956 SAFE_FREE ();
1957 return to;
1959 #endif
1960 features = otf->gpos->FeatureList.Feature;
1961 x_ppem = ft_face->size->metrics.x_ppem;
1962 y_ppem = ft_face->size->metrics.y_ppem;
1963 x_scale = ft_face->size->metrics.x_scale;
1964 y_scale = ft_face->size->metrics.y_scale;
1966 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
1967 i < otf_gstring.used; i++, otfg++)
1969 MFLTGlyphAdjustment *adjust = adjustment;
1970 MFLTGlyphFT *prev;
1971 int positioning_type, feature_idx;
1973 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1974 positioning_type = OTF_POSITIONING_TYPE_GET_FORMAT (otfg);
1975 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1976 #else
1977 positioning_type = otfg->positioning_type & 0xF;
1978 feature_idx = otfg->positioning_type >> 4;
1979 #endif
1980 if (feature_idx)
1982 unsigned int tag = features[feature_idx - 1].FeatureTag;
1983 tag = PACK_OTF_TAG (tag);
1984 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1987 if (! otfg->glyph_id)
1988 /* This is a pseudo glyph that contains positioning
1989 information to be accumulated to a real glyph. */
1990 adjust--;
1991 switch (positioning_type)
1993 case 0:
1994 break;
1995 case 1: /* Single */
1996 case 2: /* Pair */
1998 int format = otfg->f.f1.format;
2000 if (format & OTF_XPlacement)
2001 adjust->xoff
2002 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2003 if (format & OTF_XPlaDevice)
2004 adjust->xoff
2005 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2006 if (format & OTF_YPlacement)
2007 adjust->yoff
2008 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2009 if (format & OTF_YPlaDevice)
2010 adjust->yoff
2011 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2012 if (format & OTF_XAdvance)
2013 adjust->xadv
2014 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2015 if (format & OTF_XAdvDevice)
2016 adjust->xadv
2017 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2018 if (format & OTF_YAdvance)
2019 adjust->yadv
2020 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2021 if (format & OTF_YAdvDevice)
2022 adjust->yadv
2023 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2024 adjust->set = 1;
2026 break;
2027 case 3: /* Cursive */
2028 /* Not yet supported. */
2029 break;
2030 case 4: /* Mark-to-Base */
2031 case 5: /* Mark-to-Ligature */
2032 if (! base)
2033 break;
2034 prev = base;
2035 goto label_adjust_anchor;
2036 default: /* i.e. case 6 Mark-to-Mark */
2037 if (! mark)
2038 break;
2039 prev = mark;
2040 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2042 int distance = OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg);
2044 if (distance > 0)
2046 prev = g - distance;
2047 if (prev < out_glyphs)
2048 prev = mark;
2051 #endif
2053 label_adjust_anchor:
2055 int base_x, base_y, mark_x, mark_y;
2056 int this_from, this_to;
2058 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2059 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2060 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2061 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2063 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2064 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2065 x_ppem, y_ppem, &base_x, &base_y);
2066 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2067 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2068 x_ppem, y_ppem, &mark_x, &mark_y);
2069 adjust->xoff = (base_x - mark_x);
2070 adjust->yoff = - (base_y - mark_y);
2071 adjust->back = (g - prev);
2072 adjust->xadv = 0;
2073 adjust->advance_is_absolute = 1;
2074 adjust->set = 1;
2075 this_from = g->g.from;
2076 this_to = g->g.to;
2077 for (j = 0; prev + j < g; j++)
2079 if (this_from > prev[j].g.from)
2080 this_from = prev[j].g.from;
2081 if (this_to < prev[j].g.to)
2082 this_to = prev[j].g.to;
2084 for (; prev <= g; prev++)
2086 prev->g.from = this_from;
2087 prev->g.to = this_to;
2091 if (otfg->glyph_id)
2093 if (otfg->GlyphClass == OTF_GlyphClass0)
2094 base = mark = g;
2095 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2096 mark = g;
2097 else
2098 base = g;
2099 g++, adjustment++;
2103 else if (gpos_features)
2105 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2106 gpos_features) < 0)
2108 SAFE_FREE ();
2109 return to;
2111 features = otf->gpos->FeatureList.Feature;
2112 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2113 i++, otfg++)
2114 if (otfg->positioning_type & 0xF)
2116 int feature_idx = otfg->positioning_type >> 4;
2118 if (feature_idx)
2120 unsigned int tag = features[feature_idx - 1].FeatureTag;
2121 tag = PACK_OTF_TAG (tag);
2122 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2124 MFLTGlyphFT *g = in_glyphs + j;
2125 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2130 SAFE_FREE ();
2131 return to;
2133 simple_copy:
2134 SAFE_FREE ();
2135 if (! out)
2136 return to;
2137 if (out->allocated < out->used + len)
2138 return -2;
2139 font->get_metrics (font, in, from, to);
2140 memcpy (out->glyphs + out->used, in_glyphs, sizeof (MFLTGlyphFT) * len);
2141 out->used += len;
2142 return to;
2145 static int
2146 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2147 MFLTGlyphString *in, int from, int to)
2149 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2152 #else /* not M17N_FLT_USE_NEW_FEATURE */
2154 static int
2155 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2156 int from, int to,
2157 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2159 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2160 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
2161 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
2162 FT_Face ft_face = flt_font_ft->ft_face;
2163 OTF *otf = flt_font_ft->otf;
2164 int len = to - from;
2165 int i, j, gidx;
2166 OTF_Glyph *otfg;
2167 char script[5], *langsys = NULL;
2168 char *gsub_features = NULL, *gpos_features = NULL;
2170 if (len == 0)
2171 return from;
2172 OTF_tag_name (spec->script, script);
2174 char langsysbuf[5];
2175 if (spec->langsys)
2177 langsys = langsysbuf;
2178 OTF_tag_name (spec->langsys, langsys);
2181 USE_SAFE_ALLOCA;
2182 for (i = 0; i < 2; i++)
2184 char *p;
2186 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2188 for (j = 0; spec->features[i][j]; j++);
2189 SAFE_NALLOCA (p, 6, j);
2190 if (i == 0)
2191 gsub_features = p;
2192 else
2193 gpos_features = p;
2194 for (j = 0; spec->features[i][j]; j++)
2196 if (spec->features[i][j] == 0xFFFFFFFF)
2197 *p++ = '*', *p++ = ',';
2198 else
2200 OTF_tag_name (spec->features[i][j], p);
2201 p[4] = ',';
2202 p += 5;
2205 *--p = '\0';
2209 setup_otf_gstring (len);
2210 for (i = 0; i < len; i++)
2212 otf_gstring.glyphs[i].c = in_glyphs[i].g.c;
2213 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
2216 OTF_drive_gdef (otf, &otf_gstring);
2217 gidx = out->used;
2219 if (gsub_features)
2221 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2222 < 0)
2223 goto simple_copy;
2224 if (out->allocated < out->used + otf_gstring.used)
2226 SAFE_FREE ();
2227 return -2;
2229 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2231 MFLTGlyphFT *g;
2232 int min_from, max_to;
2233 int j;
2235 g = out_glyphs + out->used;
2236 *g = in_glyphs[otfg->f.index.from];
2237 if (g->g.code != otfg->glyph_id)
2239 g->g.c = 0;
2240 g->g.code = otfg->glyph_id;
2241 g->g.measured = 0;
2243 out->used++;
2244 min_from = g->g.from;
2245 max_to = g->g.to;
2246 if (otfg->f.index.from < otfg->f.index.to)
2248 /* OTFG substitutes multiple glyphs in IN. */
2249 for (j = from + otfg->f.index.from + 1;
2250 j <= from + otfg->f.index.to; j++)
2252 if (min_from > in->glyphs[j].from)
2253 min_from = in->glyphs[j].from;
2254 if (max_to < in->glyphs[j].to)
2255 max_to = in->glyphs[j].to;
2257 g->g.from = min_from;
2258 g->g.to = max_to;
2260 for (i++, otfg++; (i < otf_gstring.used
2261 && otfg->f.index.from == otfg[-1].f.index.from);
2262 i++, otfg++)
2264 g = out_glyphs + out->used;
2265 *g = in_glyphs[otfg->f.index.to];
2266 if (g->g.code != otfg->glyph_id)
2268 g->g.c = 0;
2269 g->g.code = otfg->glyph_id;
2270 g->g.measured = 0;
2272 out->used++;
2276 else
2278 if (out->allocated < out->used + len)
2280 SAFE_FREE ();
2281 return -2;
2283 for (i = 0; i < len; i++)
2284 out_glyphs[out->used++] = in_glyphs[i];
2287 if (gpos_features)
2289 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
2290 int x_ppem, y_ppem, x_scale, y_scale;
2292 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2293 < 0)
2295 SAFE_FREE ();
2296 return to;
2299 x_ppem = ft_face->size->metrics.x_ppem;
2300 y_ppem = ft_face->size->metrics.y_ppem;
2301 x_scale = ft_face->size->metrics.x_scale;
2302 y_scale = ft_face->size->metrics.y_scale;
2304 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2305 i < otf_gstring.used; i++, otfg++, g++)
2307 MFLTGlyphFT *prev;
2309 if (! otfg->glyph_id)
2310 continue;
2311 switch (otfg->positioning_type)
2313 case 0:
2314 break;
2315 case 1: /* Single */
2316 case 2: /* Pair */
2318 int format = otfg->f.f1.format;
2320 if (format & OTF_XPlacement)
2321 adjustment[i].xoff
2322 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2323 if (format & OTF_XPlaDevice)
2324 adjustment[i].xoff
2325 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2326 if (format & OTF_YPlacement)
2327 adjustment[i].yoff
2328 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2329 if (format & OTF_YPlaDevice)
2330 adjustment[i].yoff
2331 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2332 if (format & OTF_XAdvance)
2333 adjustment[i].xadv
2334 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2335 if (format & OTF_XAdvDevice)
2336 adjustment[i].xadv
2337 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2338 if (format & OTF_YAdvance)
2339 adjustment[i].yadv
2340 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2341 if (format & OTF_YAdvDevice)
2342 adjustment[i].yadv
2343 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2344 adjustment[i].set = 1;
2346 break;
2347 case 3: /* Cursive */
2348 /* Not yet supported. */
2349 break;
2350 case 4: /* Mark-to-Base */
2351 case 5: /* Mark-to-Ligature */
2352 if (! base)
2353 break;
2354 prev = base;
2355 goto label_adjust_anchor;
2356 default: /* i.e. case 6 Mark-to-Mark */
2357 if (! mark)
2358 break;
2359 prev = mark;
2361 label_adjust_anchor:
2363 int base_x, base_y, mark_x, mark_y;
2364 int this_from, this_to;
2366 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2367 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2368 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2369 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2371 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2372 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2373 x_ppem, y_ppem, &base_x, &base_y);
2374 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2375 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2376 x_ppem, y_ppem, &mark_x, &mark_y);
2377 adjustment[i].xoff = (base_x - mark_x);
2378 adjustment[i].yoff = - (base_y - mark_y);
2379 adjustment[i].back = (g - prev);
2380 adjustment[i].xadv = 0;
2381 adjustment[i].advance_is_absolute = 1;
2382 adjustment[i].set = 1;
2383 this_from = g->g.from;
2384 this_to = g->g.to;
2385 for (j = 0; prev + j < g; j++)
2387 if (this_from > prev[j].g.from)
2388 this_from = prev[j].g.from;
2389 if (this_to < prev[j].g.to)
2390 this_to = prev[j].g.to;
2392 for (; prev <= g; prev++)
2394 prev->g.from = this_from;
2395 prev->g.to = this_to;
2399 if (otfg->GlyphClass == OTF_GlyphClass0)
2400 base = mark = g;
2401 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2402 mark = g;
2403 else
2404 base = g;
2407 SAFE_FREE ();
2408 return to;
2410 simple_copy:
2411 SAFE_FREE ();
2412 if (out->allocated < out->used + len)
2413 return -2;
2414 font->get_metrics (font, in, from, to);
2415 memcpy (out_glyphs + out->used, in_glyphs,
2416 sizeof (MFLTGlyphFT) * len);
2417 out->used += len;
2418 return to;
2421 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2423 static MFLTGlyphString gstring;
2425 static bool m17n_flt_initialized;
2427 static Lisp_Object
2428 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2429 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2431 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2432 ptrdiff_t i;
2433 struct MFLTFontFT flt_font_ft;
2434 MFLT *flt = NULL;
2435 bool with_variation_selector = false;
2437 if (! m17n_flt_initialized)
2439 M17N_INIT ();
2440 #ifdef M17N_FLT_USE_NEW_FEATURE
2441 mflt_enable_new_feature = 1;
2442 mflt_try_otf = ftfont_try_otf;
2443 #endif /* M17N_FLT_USE_NEW_FEATURE */
2444 m17n_flt_initialized = 1;
2447 for (i = 0; i < len; i++)
2449 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2450 int c;
2452 if (NILP (g))
2453 break;
2454 c = LGLYPH_CHAR (g);
2455 if (CHAR_VARIATION_SELECTOR_P (c))
2456 with_variation_selector = true;
2459 len = i;
2461 if (otf && with_variation_selector)
2463 setup_otf_gstring (len);
2464 for (i = 0; i < len; i++)
2466 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2468 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2469 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2470 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2472 OTF_drive_cmap (otf, &otf_gstring);
2473 for (i = 0; i < otf_gstring.used; i++)
2475 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2476 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2477 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2479 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2480 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2481 LGSTRING_SET_GLYPH (lgstring, i, g0);
2483 if (len > otf_gstring.used)
2485 len = otf_gstring.used;
2486 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2491 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2493 if (NILP (family))
2494 flt_font_ft.flt_font.family = Mnil;
2495 else
2496 flt_font_ft.flt_font.family
2497 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2499 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2500 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2501 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2502 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2503 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2504 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2505 flt_font_ft.flt_font.internal = NULL;
2506 flt_font_ft.font = font;
2507 flt_font_ft.ft_face = ft_face;
2508 flt_font_ft.otf = otf;
2509 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2511 if (1 < len)
2513 /* A little bit ad hoc. Perhaps, shaper must get script and
2514 language information, and select a proper flt for them
2515 here. */
2516 int c1 = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 1));
2517 /* For the combining characters in the range U+300..U+36F,
2518 "combining" is the sole FLT provided by the m17n-lib. In
2519 addition, it is the sole FLT that can handle the other
2520 combining characters with non-OTF fonts. */
2521 if ((0x300 <= c1 && c1 <= 0x36F)
2522 || (! otf && CHAR_HAS_CATEGORY (c1, '^')))
2523 flt = mflt_get (msymbol ("combining"));
2525 if (! flt && ! otf)
2527 flt = mflt_find (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 0)),
2528 &flt_font_ft.flt_font);
2529 if (! flt)
2530 return make_number (0);
2533 MFLTGlyphFT *glyphs = (MFLTGlyphFT *) gstring.glyphs;
2534 ptrdiff_t allocated = gstring.allocated;
2535 ptrdiff_t incr_min = len - allocated;
2539 if (0 < incr_min)
2541 xfree (glyphs);
2542 glyphs = xpalloc (NULL, &allocated, incr_min, INT_MAX, sizeof *glyphs);
2544 incr_min = 1;
2546 for (i = 0; i < len; i++)
2548 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2549 memset (&glyphs[i], 0, sizeof glyphs[i]);
2550 glyphs[i].g.c = LGLYPH_CHAR (g);
2551 if (with_variation_selector)
2553 glyphs[i].g.code = LGLYPH_CODE (g);
2554 glyphs[i].g.encoded = 1;
2558 gstring.glyph_size = sizeof *glyphs;
2559 gstring.glyphs = (MFLTGlyph *) glyphs;
2560 gstring.allocated = allocated;
2561 gstring.used = len;
2562 gstring.r2l = 0;
2564 while (mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt) == -2);
2566 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2567 return Qnil;
2568 for (i = 0; i < gstring.used; i++)
2570 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2572 g->g.from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->g.from));
2573 g->g.to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->g.to));
2576 for (i = 0; i < gstring.used; i++)
2578 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2579 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2581 if (NILP (lglyph))
2583 lglyph = LGLYPH_NEW ();
2584 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2586 LGLYPH_SET_FROM (lglyph, g->g.from);
2587 LGLYPH_SET_TO (lglyph, g->g.to);
2588 LGLYPH_SET_CHAR (lglyph, g->g.c);
2589 LGLYPH_SET_CODE (lglyph, g->g.code);
2590 LGLYPH_SET_WIDTH (lglyph, g->g.xadv >> 6);
2591 LGLYPH_SET_LBEARING (lglyph, g->g.lbearing >> 6);
2592 LGLYPH_SET_RBEARING (lglyph, g->g.rbearing >> 6);
2593 LGLYPH_SET_ASCENT (lglyph, g->g.ascent >> 6);
2594 LGLYPH_SET_DESCENT (lglyph, g->g.descent >> 6);
2595 if (g->g.adjusted)
2597 Lisp_Object vec = make_uninit_vector (3);
2599 ASET (vec, 0, make_number (g->g.xoff >> 6));
2600 ASET (vec, 1, make_number (g->g.yoff >> 6));
2601 ASET (vec, 2, make_number (g->g.xadv >> 6));
2602 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2605 return make_number (i);
2608 Lisp_Object
2609 ftfont_shape (Lisp_Object lgstring)
2611 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2612 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2613 OTF *otf = ftfont_get_otf (ftfont_info);
2615 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2616 &ftfont_info->matrix);
2619 #endif /* HAVE_M17N_FLT */
2621 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2624 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2626 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2627 OTF *otf = ftfont_get_otf (ftfont_info);
2629 if (! otf)
2630 return 0;
2631 return OTF_get_variation_glyphs (otf, c, variations);
2634 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2635 #endif /* HAVE_LIBOTF */
2637 static const char *const ftfont_booleans [] = {
2638 ":antialias",
2639 ":hinting",
2640 ":verticallayout",
2641 ":autohint",
2642 ":globaladvance",
2643 ":outline",
2644 ":scalable",
2645 ":minspace",
2646 ":embolden",
2647 NULL,
2650 static const char *const ftfont_non_booleans [] = {
2651 ":family",
2652 ":familylang",
2653 ":style",
2654 ":stylelang",
2655 ":fullname",
2656 ":fullnamelang",
2657 ":slant",
2658 ":weight",
2659 ":size",
2660 ":width",
2661 ":aspect",
2662 ":pixelsize",
2663 ":spacing",
2664 ":foundry",
2665 ":hintstyle",
2666 ":file",
2667 ":index",
2668 ":ftface",
2669 ":rasterizer",
2670 ":scale",
2671 ":dpi",
2672 ":rgba",
2673 ":lcdfilter",
2674 ":charset",
2675 ":lang",
2676 ":fontversion",
2677 ":capability",
2678 NULL,
2681 void
2682 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2684 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2688 Lisp_Object
2689 ftfont_combining_capability (struct font *font)
2691 #ifdef HAVE_M17N_FLT
2692 return Qt;
2693 #else
2694 return Qnil;
2695 #endif
2698 static struct font_driver const ftfont_driver =
2700 /* We can't draw a text without device dependent functions. */
2701 .type = LISPSYM_INITIALLY (Qfreetype),
2702 .get_cache = ftfont_get_cache,
2703 .list = ftfont_list,
2704 .match = ftfont_match,
2705 .list_family = ftfont_list_family,
2706 .open = ftfont_open,
2707 .close = ftfont_close,
2708 .has_char = ftfont_has_char,
2709 .encode_char = ftfont_encode_char,
2710 .text_extents = ftfont_text_extents,
2711 .get_bitmap = ftfont_get_bitmap,
2712 .anchor_point = ftfont_anchor_point,
2713 #ifdef HAVE_LIBOTF
2714 .otf_capability = ftfont_otf_capability,
2715 #endif
2716 #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
2717 .shape = ftfont_shape,
2718 #endif
2719 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2720 .get_variation_glyphs = ftfont_variation_glyphs,
2721 #endif
2722 .filter_properties = ftfont_filter_properties,
2723 .combining_capability = ftfont_combining_capability,
2726 void
2727 syms_of_ftfont (void)
2729 /* Symbolic type of this font-driver. */
2730 DEFSYM (Qfreetype, "freetype");
2732 /* Fontconfig's generic families and their aliases. */
2733 DEFSYM (Qmonospace, "monospace");
2734 DEFSYM (Qsans_serif, "sans-serif");
2735 DEFSYM (Qsans, "sans");
2736 DEFSYM (Qsans__serif, "sans serif");
2738 staticpro (&freetype_font_cache);
2739 freetype_font_cache = list1 (Qt);
2741 staticpro (&ftfont_generic_family_list);
2742 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2743 Fcons (Qsans_serif, Qt),
2744 Fcons (Qsans, Qt));
2746 staticpro (&ft_face_cache);
2747 ft_face_cache = Qnil;
2749 register_font_driver (&ftfont_driver, NULL);