; * src/ftfont.c (ftfont_spec_pattern): Fix whitespace.
[emacs.git] / src / ftfont.c
blob51b04a86829b47c45a1e9a1eb0555fcad5fd5b99
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 /* FIXME: Although this function can be called while garbage-collecting,
1246 the function assumes that Lisp data structures are properly-formed.
1247 This invalid assumption can lead to core dumps (Bug#20890). */
1248 #ifdef USE_CAIRO
1249 /* Although this works around Bug#20890, it is probably not the
1250 right thing to do. */
1251 if (gc_in_progress)
1252 return;
1253 #endif
1255 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1256 Lisp_Object val, cache;
1258 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1259 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1260 eassert (CONSP (cache));
1261 val = XCDR (cache);
1262 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1263 if (XSAVE_INTEGER (val, 1) == 0)
1265 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1267 FT_Done_Face (cache_data->ft_face);
1268 #ifdef HAVE_LIBOTF
1269 if (ftfont_info->otf)
1270 OTF_close (ftfont_info->otf);
1271 #endif
1272 cache_data->ft_face = NULL;
1274 else
1275 FT_Done_Size (ftfont_info->ft_size);
1279 ftfont_has_char (Lisp_Object font, int c)
1281 struct charset *cs = NULL;
1283 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1284 && charset_jisx0208 >= 0)
1285 cs = CHARSET_FROM_ID (charset_jisx0208);
1286 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1287 && charset_ksc5601 >= 0)
1288 cs = CHARSET_FROM_ID (charset_ksc5601);
1289 if (cs)
1290 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1292 if (FONT_ENTITY_P (font))
1294 FcCharSet *charset = ftfont_get_fc_charset (font);
1296 return (FcCharSetHasChar (charset, c) == FcTrue);
1298 else
1300 struct ftfont_info *ftfont_info;
1302 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1303 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1304 != 0);
1308 unsigned
1309 ftfont_encode_char (struct font *font, int c)
1311 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1312 FT_Face ft_face = ftfont_info->ft_size->face;
1313 FT_ULong charcode = c;
1314 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1316 return (code > 0 ? code : FONT_INVALID_CODE);
1319 void
1320 ftfont_text_extents (struct font *font, unsigned int *code,
1321 int nglyphs, struct font_metrics *metrics)
1323 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1324 FT_Face ft_face = ftfont_info->ft_size->face;
1325 int i, width = 0;
1326 bool first;
1328 if (ftfont_info->ft_size != ft_face->size)
1329 FT_Activate_Size (ftfont_info->ft_size);
1331 for (i = 0, first = 1; i < nglyphs; i++)
1333 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1335 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1337 if (first)
1339 metrics->lbearing = m->horiBearingX >> 6;
1340 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1341 metrics->ascent = m->horiBearingY >> 6;
1342 metrics->descent = (m->height - m->horiBearingY) >> 6;
1343 first = 0;
1345 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1346 metrics->lbearing = width + (m->horiBearingX >> 6);
1347 if (metrics->rbearing
1348 < width + ((m->horiBearingX + m->width) >> 6))
1349 metrics->rbearing
1350 = width + ((m->horiBearingX + m->width) >> 6);
1351 if (metrics->ascent < (m->horiBearingY >> 6))
1352 metrics->ascent = m->horiBearingY >> 6;
1353 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1354 metrics->descent = (m->height - m->horiBearingY) >> 6;
1355 width += m->horiAdvance >> 6;
1357 else
1358 width += font->space_width;
1360 metrics->width = width;
1364 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1366 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1367 FT_Face ft_face = ftfont_info->ft_size->face;
1368 FT_Int32 load_flags = FT_LOAD_RENDER;
1370 if (ftfont_info->ft_size != ft_face->size)
1371 FT_Activate_Size (ftfont_info->ft_size);
1372 if (bits_per_pixel == 1)
1374 #ifdef FT_LOAD_TARGET_MONO
1375 load_flags |= FT_LOAD_TARGET_MONO;
1376 #else
1377 load_flags |= FT_LOAD_MONOCHROME;
1378 #endif
1380 else if (bits_per_pixel != 8)
1381 /* We don't support such a rendering. */
1382 return -1;
1384 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1385 return -1;
1386 bitmap->bits_per_pixel
1387 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1388 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1389 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1390 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1391 : -1);
1392 if (bitmap->bits_per_pixel < 0)
1393 /* We don't support that kind of pixel mode. */
1394 return -1;
1395 bitmap->rows = ft_face->glyph->bitmap.rows;
1396 bitmap->width = ft_face->glyph->bitmap.width;
1397 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1398 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1399 bitmap->left = ft_face->glyph->bitmap_left;
1400 bitmap->top = ft_face->glyph->bitmap_top;
1401 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1403 return 0;
1407 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1408 int *x, int *y)
1410 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1411 FT_Face ft_face = ftfont_info->ft_size->face;
1413 if (ftfont_info->ft_size != ft_face->size)
1414 FT_Activate_Size (ftfont_info->ft_size);
1415 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1416 return -1;
1417 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1418 return -1;
1419 if (idx >= ft_face->glyph->outline.n_points)
1420 return -1;
1421 *x = ft_face->glyph->outline.points[idx].x;
1422 *y = ft_face->glyph->outline.points[idx].y;
1423 return 0;
1426 #ifdef HAVE_LIBOTF
1428 static Lisp_Object
1429 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1431 Lisp_Object scripts, langsyses, features, sym;
1432 int i, j, k, l;
1434 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1436 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1438 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1440 OTF_LangSys *otf_langsys;
1442 if (j >= 0)
1443 otf_langsys = otf_script->LangSys + j;
1444 else if (otf_script->DefaultLangSysOffset)
1445 otf_langsys = &otf_script->DefaultLangSys;
1446 else
1447 break;
1449 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1451 l = otf_langsys->FeatureIndex[k];
1452 if (l >= gsub_gpos->FeatureList.FeatureCount)
1453 continue;
1454 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1455 features = Fcons (sym, features);
1457 if (j >= 0)
1458 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1459 else
1460 sym = Qnil;
1461 langsyses = Fcons (Fcons (sym, features), langsyses);
1464 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1465 scripts = Fcons (Fcons (sym, langsyses), scripts);
1467 return scripts;
1472 Lisp_Object
1473 ftfont_otf_capability (struct font *font)
1475 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1476 OTF *otf = ftfont_get_otf (ftfont_info);
1477 Lisp_Object gsub_gpos;
1479 if (! otf)
1480 return Qnil;
1481 gsub_gpos = Fcons (Qnil, Qnil);
1482 if (OTF_get_table (otf, "GSUB") == 0
1483 && otf->gsub->FeatureList.FeatureCount > 0)
1484 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1485 if (OTF_get_table (otf, "GPOS") == 0
1486 && otf->gpos->FeatureList.FeatureCount > 0)
1487 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1488 return gsub_gpos;
1491 #ifdef HAVE_M17N_FLT
1493 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1494 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1495 /* We can use the new feature of libotf and m17n-flt to handle the
1496 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1497 some Agian scripts. */
1498 #define M17N_FLT_USE_NEW_FEATURE
1499 #endif
1501 struct MFLTFontFT
1503 MFLTFont flt_font;
1504 struct font *font;
1505 FT_Face ft_face;
1506 OTF *otf;
1507 FT_Matrix *matrix;
1510 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1511 We use this structure instead of MFLTGlyph to utilize the new
1512 feature of libotf ver.0.9.15 which requires saving and restoring
1513 the value of OTF_GlyphString.positioning_type in the succeeding
1514 calls of the callback function MFLTFont.drive_otf (which is set to
1515 ftfont_drive_otf). */
1517 typedef struct {
1518 MFLTGlyph g;
1519 unsigned int libotf_positioning_type;
1520 } MFLTGlyphFT;
1522 static int
1523 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1524 int from, int to)
1526 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1527 FT_Face ft_face = flt_font_ft->ft_face;
1528 MFLTGlyphFT *g;
1530 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1531 if (! g->g.encoded)
1533 FT_UInt code = FT_Get_Char_Index (ft_face, g->g.code);
1535 g->g.code = code > 0 ? code : FONT_INVALID_CODE;
1536 g->g.encoded = 1;
1538 return 0;
1541 /* Operators for 26.6 fixed fractional pixel format */
1543 #define FLOOR(x) ((x) & -64)
1544 #define CEIL(x) (((x)+63) & -64)
1545 #define ROUND(x) (((x)+32) & -64)
1547 static int
1548 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1549 int from, int to)
1551 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1552 FT_Face ft_face = flt_font_ft->ft_face;
1553 MFLTGlyphFT *g;
1555 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1556 if (! g->g.measured)
1558 if (g->g.code != FONT_INVALID_CODE)
1560 FT_Glyph_Metrics *m;
1562 if (FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_DEFAULT) != 0
1563 && FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_NO_HINTING) != 0)
1564 emacs_abort ();
1565 m = &ft_face->glyph->metrics;
1566 if (flt_font_ft->matrix)
1568 FT_Vector v[4];
1569 int i;
1571 v[0].x = v[1].x = m->horiBearingX;
1572 v[2].x = v[3].x = m->horiBearingX + m->width;
1573 v[0].y = v[2].y = m->horiBearingY;
1574 v[1].y = v[3].y = m->horiBearingY - m->height;
1575 for (i = 0; i < 4; i++)
1576 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1577 g->g.lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1578 g->g.rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1579 g->g.ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1580 g->g.descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1582 else
1584 g->g.lbearing = FLOOR (m->horiBearingX);
1585 g->g.rbearing = CEIL (m->horiBearingX + m->width);
1586 g->g.ascent = CEIL (m->horiBearingY);
1587 g->g.descent = - FLOOR (m->horiBearingY - m->height);
1589 g->g.xadv = ROUND (ft_face->glyph->advance.x);
1591 else
1593 g->g.lbearing = 0;
1594 g->g.rbearing = g->g.xadv = flt_font_ft->font->space_width << 6;
1595 g->g.ascent = flt_font_ft->font->ascent << 6;
1596 g->g.descent = flt_font_ft->font->descent << 6;
1598 g->g.yadv = 0;
1599 g->g.measured = 1;
1601 return 0;
1604 static int
1605 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1607 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1609 #define FEATURE_ANY(IDX) \
1610 (spec->features[IDX] \
1611 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1613 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1614 OTF *otf = flt_font_ft->otf;
1615 OTF_Tag *tags;
1616 int i, n;
1617 bool negative;
1619 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1620 /* Return true iff any of GSUB or GPOS support the script (and
1621 language). */
1622 return (otf
1623 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1624 NULL, 0) > 0
1625 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1626 NULL, 0) > 0));
1628 for (i = 0; i < 2; i++)
1629 if (! FEATURE_ANY (i))
1631 if (FEATURE_NONE (i))
1633 if (otf
1634 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1635 NULL, 0) > 0)
1636 return 0;
1637 continue;
1639 if (spec->features[i][0] == 0xFFFFFFFF)
1641 if (! otf
1642 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1643 NULL, 0) <= 0)
1644 continue;
1646 else if (! otf)
1647 return 0;
1648 for (n = 1; spec->features[i][n]; n++);
1649 USE_SAFE_ALLOCA;
1650 SAFE_NALLOCA (tags, 1, n);
1651 for (n = 0, negative = 0; spec->features[i][n]; n++)
1653 if (spec->features[i][n] == 0xFFFFFFFF)
1654 negative = 1;
1655 else if (negative)
1656 tags[n - 1] = spec->features[i][n] | 0x80000000;
1657 else
1658 tags[n] = spec->features[i][n];
1660 bool passed = true;
1661 #ifndef M17N_FLT_USE_NEW_FEATURE
1662 passed = n - negative > 0;
1663 #endif
1664 if (passed)
1665 passed = (OTF_check_features (otf, i == 0, spec->script,
1666 spec->langsys, tags, n - negative)
1667 != 1);
1668 SAFE_FREE ();
1669 if (passed)
1670 return 0;
1672 return 1;
1673 #undef FEATURE_NONE
1674 #undef FEATURE_ANY
1677 #define DEVICE_DELTA(table, size) \
1678 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1679 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1680 : 0)
1682 static void
1683 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1684 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1686 if (anchor->AnchorFormat == 2)
1688 FT_Outline *outline;
1689 int ap = anchor->f.f1.AnchorPoint;
1691 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1692 outline = &ft_face->glyph->outline;
1693 if (ap < outline->n_points)
1695 *x = outline->points[ap].x << 6;
1696 *y = outline->points[ap].y << 6;
1699 else if (anchor->AnchorFormat == 3)
1701 if (anchor->f.f2.XDeviceTable.offset
1702 && anchor->f.f2.XDeviceTable.DeltaValue)
1703 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1704 if (anchor->f.f2.YDeviceTable.offset
1705 && anchor->f.f2.YDeviceTable.DeltaValue)
1706 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1710 static OTF_GlyphString otf_gstring;
1712 static void
1713 setup_otf_gstring (int size)
1715 if (otf_gstring.size < size)
1717 ptrdiff_t new_size = otf_gstring.size;
1718 xfree (otf_gstring.glyphs);
1719 otf_gstring.glyphs = xpalloc (NULL, &new_size, size - otf_gstring.size,
1720 INT_MAX, sizeof *otf_gstring.glyphs);
1721 otf_gstring.size = new_size;
1723 otf_gstring.used = size;
1724 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1727 #ifdef M17N_FLT_USE_NEW_FEATURE
1729 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1730 #define PACK_OTF_TAG(TAG) \
1731 ((((TAG) & 0x7F000000) >> 3) \
1732 | (((TAG) & 0x7F0000) >> 2) \
1733 | (((TAG) & 0x7F00) >> 1) \
1734 | ((TAG) & 0x7F))
1736 /* Assuming that FONT is an OpenType font, apply OpenType features
1737 specified in SPEC on glyphs between FROM and TO of IN, and record
1738 the lastly applied feature in each glyph of IN. If OUT is not
1739 NULL, append the resulting glyphs to OUT while storing glyph
1740 position adjustment information in ADJUSTMENT. */
1742 static int
1743 ftfont_drive_otf (MFLTFont *font,
1744 MFLTOtfSpec *spec,
1745 MFLTGlyphString *in,
1746 int from,
1747 int to,
1748 MFLTGlyphString *out,
1749 MFLTGlyphAdjustment *adjustment)
1751 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1752 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
1753 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
1754 FT_Face ft_face = flt_font_ft->ft_face;
1755 OTF *otf = flt_font_ft->otf;
1756 int len = to - from;
1757 int i, j, gidx;
1758 OTF_Glyph *otfg;
1759 char script[5], *langsys = NULL;
1760 char *gsub_features = NULL, *gpos_features = NULL;
1761 OTF_Feature *features;
1763 if (len == 0)
1764 return from;
1765 OTF_tag_name (spec->script, script);
1767 char langsysbuf[5];
1768 if (spec->langsys)
1770 langsys = langsysbuf;
1771 OTF_tag_name (spec->langsys, langsys);
1774 USE_SAFE_ALLOCA;
1775 for (i = 0; i < 2; i++)
1777 char *p;
1779 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1781 for (j = 0; spec->features[i][j]; j++);
1782 SAFE_NALLOCA (p, 6, j);
1783 if (i == 0)
1784 gsub_features = p;
1785 else
1786 gpos_features = p;
1787 for (j = 0; spec->features[i][j]; j++)
1789 if (spec->features[i][j] == 0xFFFFFFFF)
1790 *p++ = '*', *p++ = ',';
1791 else
1793 OTF_tag_name (spec->features[i][j], p);
1794 p[4] = ',';
1795 p += 5;
1798 *--p = '\0';
1802 setup_otf_gstring (len);
1803 for (i = 0; i < len; i++)
1805 otf_gstring.glyphs[i].c = in_glyphs[i].g.c & 0x11FFFF;
1806 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
1807 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1808 otf_gstring.glyphs[i].positioning_type = in_glyphs[i].libotf_positioning_type;
1809 #endif
1812 OTF_drive_gdef (otf, &otf_gstring);
1813 gidx = out ? out->used : from;
1815 if (gsub_features && out)
1817 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1818 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1819 gsub_features) < 0)
1820 goto simple_copy;
1821 #else
1822 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1823 gsub_features) < 0)
1824 goto simple_copy;
1825 #endif
1826 if (out->allocated < out->used + otf_gstring.used)
1828 SAFE_FREE ();
1829 return -2;
1831 features = otf->gsub->FeatureList.Feature;
1832 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1834 MFLTGlyphFT *g;
1835 int min_from, max_to;
1836 int feature_idx;
1838 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1839 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1840 #else
1841 feature_idx = otfg->positioning_type >> 4;
1842 #endif
1843 g = out_glyphs + out->used;
1844 *g = in_glyphs[otfg->f.index.from];
1845 if (g->g.code != otfg->glyph_id)
1847 g->g.c = 0;
1848 g->g.code = otfg->glyph_id;
1849 g->g.measured = 0;
1851 out->used++;
1852 min_from = g->g.from;
1853 max_to = g->g.to;
1854 if (otfg->f.index.from < otfg->f.index.to)
1856 /* OTFG substitutes multiple glyphs in IN. */
1857 for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
1859 if (min_from > in_glyphs[j].g.from)
1860 min_from = in_glyphs[j].g.from;
1861 if (max_to < in_glyphs[j].g.to)
1862 max_to = in_glyphs[j].g.to;
1864 g->g.from = min_from;
1865 g->g.to = max_to;
1867 if (feature_idx)
1869 unsigned int tag = features[feature_idx - 1].FeatureTag;
1870 tag = PACK_OTF_TAG (tag);
1871 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1873 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1874 g->libotf_positioning_type
1875 = otfg->positioning_type & OTF_positioning_type_components_mask;
1876 #endif
1877 for (i++, otfg++; (i < otf_gstring.used
1878 && otfg->f.index.from == otfg[-1].f.index.from);
1879 i++, otfg++)
1881 g = out_glyphs + out->used;
1882 *g = in_glyphs[otfg->f.index.to];
1883 if (g->g.code != otfg->glyph_id)
1885 g->g.c = 0;
1886 g->g.code = otfg->glyph_id;
1887 g->g.measured = 0;
1889 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1890 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1891 #else
1892 feature_idx = otfg->positioning_type >> 4;
1893 #endif
1894 if (feature_idx)
1896 unsigned int tag = features[feature_idx - 1].FeatureTag;
1897 tag = PACK_OTF_TAG (tag);
1898 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1900 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1901 g->libotf_positioning_type
1902 = otfg->positioning_type & OTF_positioning_type_components_mask;
1903 #endif
1904 out->used++;
1908 else if (gsub_features)
1910 /* Just for checking which features will be applied. */
1911 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1912 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1913 gsub_features) < 0)
1914 goto simple_copy;
1915 #else
1916 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1917 gsub_features) < 0)
1918 goto simple_copy;
1919 #endif
1920 features = otf->gsub->FeatureList.Feature;
1921 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1922 otfg++)
1924 int feature_idx;
1925 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1926 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1927 #else
1928 feature_idx = otfg->positioning_type >> 4;
1929 #endif
1930 if (feature_idx)
1932 unsigned int tag = features[feature_idx - 1].FeatureTag;
1933 tag = PACK_OTF_TAG (tag);
1934 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1936 MFLTGlyphFT *g = in_glyphs + j;
1937 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1942 else if (out)
1944 if (out->allocated < out->used + len)
1946 SAFE_FREE ();
1947 return -2;
1949 for (i = 0; i < len; i++)
1950 out_glyphs[out->used++] = in_glyphs[i];
1953 if (gpos_features && out)
1955 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
1956 int x_ppem, y_ppem, x_scale, y_scale;
1958 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1959 if (OTF_drive_gpos_features (otf, &otf_gstring, script, langsys,
1960 gpos_features) < 0)
1962 SAFE_FREE ();
1963 return to;
1965 #else
1966 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1967 gpos_features) < 0)
1969 SAFE_FREE ();
1970 return to;
1972 #endif
1973 features = otf->gpos->FeatureList.Feature;
1974 x_ppem = ft_face->size->metrics.x_ppem;
1975 y_ppem = ft_face->size->metrics.y_ppem;
1976 x_scale = ft_face->size->metrics.x_scale;
1977 y_scale = ft_face->size->metrics.y_scale;
1979 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
1980 i < otf_gstring.used; i++, otfg++)
1982 MFLTGlyphAdjustment *adjust = adjustment;
1983 MFLTGlyphFT *prev;
1984 int positioning_type, feature_idx;
1986 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1987 positioning_type = OTF_POSITIONING_TYPE_GET_FORMAT (otfg);
1988 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1989 #else
1990 positioning_type = otfg->positioning_type & 0xF;
1991 feature_idx = otfg->positioning_type >> 4;
1992 #endif
1993 if (feature_idx)
1995 unsigned int tag = features[feature_idx - 1].FeatureTag;
1996 tag = PACK_OTF_TAG (tag);
1997 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2000 if (! otfg->glyph_id)
2001 /* This is a pseudo glyph that contains positioning
2002 information to be accumulated to a real glyph. */
2003 adjust--;
2004 switch (positioning_type)
2006 case 0:
2007 break;
2008 case 1: /* Single */
2009 case 2: /* Pair */
2011 int format = otfg->f.f1.format;
2013 if (format & OTF_XPlacement)
2014 adjust->xoff
2015 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2016 if (format & OTF_XPlaDevice)
2017 adjust->xoff
2018 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2019 if (format & OTF_YPlacement)
2020 adjust->yoff
2021 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2022 if (format & OTF_YPlaDevice)
2023 adjust->yoff
2024 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2025 if (format & OTF_XAdvance)
2026 adjust->xadv
2027 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2028 if (format & OTF_XAdvDevice)
2029 adjust->xadv
2030 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2031 if (format & OTF_YAdvance)
2032 adjust->yadv
2033 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2034 if (format & OTF_YAdvDevice)
2035 adjust->yadv
2036 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2037 adjust->set = 1;
2039 break;
2040 case 3: /* Cursive */
2041 /* Not yet supported. */
2042 break;
2043 case 4: /* Mark-to-Base */
2044 case 5: /* Mark-to-Ligature */
2045 if (! base)
2046 break;
2047 prev = base;
2048 goto label_adjust_anchor;
2049 default: /* i.e. case 6 Mark-to-Mark */
2050 if (! mark)
2051 break;
2052 prev = mark;
2053 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2055 int distance = OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg);
2057 if (distance > 0)
2059 prev = g - distance;
2060 if (prev < out_glyphs)
2061 prev = mark;
2064 #endif
2066 label_adjust_anchor:
2068 int base_x, base_y, mark_x, mark_y;
2069 int this_from, this_to;
2071 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2072 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2073 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2074 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2076 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2077 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2078 x_ppem, y_ppem, &base_x, &base_y);
2079 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2080 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2081 x_ppem, y_ppem, &mark_x, &mark_y);
2082 adjust->xoff = (base_x - mark_x);
2083 adjust->yoff = - (base_y - mark_y);
2084 adjust->back = (g - prev);
2085 adjust->xadv = 0;
2086 adjust->advance_is_absolute = 1;
2087 adjust->set = 1;
2088 this_from = g->g.from;
2089 this_to = g->g.to;
2090 for (j = 0; prev + j < g; j++)
2092 if (this_from > prev[j].g.from)
2093 this_from = prev[j].g.from;
2094 if (this_to < prev[j].g.to)
2095 this_to = prev[j].g.to;
2097 for (; prev <= g; prev++)
2099 prev->g.from = this_from;
2100 prev->g.to = this_to;
2104 if (otfg->glyph_id)
2106 if (otfg->GlyphClass == OTF_GlyphClass0)
2107 base = mark = g;
2108 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2109 mark = g;
2110 else
2111 base = g;
2112 g++, adjustment++;
2116 else if (gpos_features)
2118 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2119 gpos_features) < 0)
2121 SAFE_FREE ();
2122 return to;
2124 features = otf->gpos->FeatureList.Feature;
2125 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2126 i++, otfg++)
2127 if (otfg->positioning_type & 0xF)
2129 int feature_idx = otfg->positioning_type >> 4;
2131 if (feature_idx)
2133 unsigned int tag = features[feature_idx - 1].FeatureTag;
2134 tag = PACK_OTF_TAG (tag);
2135 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2137 MFLTGlyphFT *g = in_glyphs + j;
2138 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2143 SAFE_FREE ();
2144 return to;
2146 simple_copy:
2147 SAFE_FREE ();
2148 if (! out)
2149 return to;
2150 if (out->allocated < out->used + len)
2151 return -2;
2152 font->get_metrics (font, in, from, to);
2153 memcpy (out->glyphs + out->used, in_glyphs, sizeof (MFLTGlyphFT) * len);
2154 out->used += len;
2155 return to;
2158 static int
2159 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2160 MFLTGlyphString *in, int from, int to)
2162 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2165 #else /* not M17N_FLT_USE_NEW_FEATURE */
2167 static int
2168 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2169 int from, int to,
2170 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2172 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2173 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
2174 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
2175 FT_Face ft_face = flt_font_ft->ft_face;
2176 OTF *otf = flt_font_ft->otf;
2177 int len = to - from;
2178 int i, j, gidx;
2179 OTF_Glyph *otfg;
2180 char script[5], *langsys = NULL;
2181 char *gsub_features = NULL, *gpos_features = NULL;
2183 if (len == 0)
2184 return from;
2185 OTF_tag_name (spec->script, script);
2187 char langsysbuf[5];
2188 if (spec->langsys)
2190 langsys = langsysbuf;
2191 OTF_tag_name (spec->langsys, langsys);
2194 USE_SAFE_ALLOCA;
2195 for (i = 0; i < 2; i++)
2197 char *p;
2199 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2201 for (j = 0; spec->features[i][j]; j++);
2202 SAFE_NALLOCA (p, 6, j);
2203 if (i == 0)
2204 gsub_features = p;
2205 else
2206 gpos_features = p;
2207 for (j = 0; spec->features[i][j]; j++)
2209 if (spec->features[i][j] == 0xFFFFFFFF)
2210 *p++ = '*', *p++ = ',';
2211 else
2213 OTF_tag_name (spec->features[i][j], p);
2214 p[4] = ',';
2215 p += 5;
2218 *--p = '\0';
2222 setup_otf_gstring (len);
2223 for (i = 0; i < len; i++)
2225 otf_gstring.glyphs[i].c = in_glyphs[i].g.c;
2226 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
2229 OTF_drive_gdef (otf, &otf_gstring);
2230 gidx = out->used;
2232 if (gsub_features)
2234 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2235 < 0)
2236 goto simple_copy;
2237 if (out->allocated < out->used + otf_gstring.used)
2239 SAFE_FREE ();
2240 return -2;
2242 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2244 MFLTGlyphFT *g;
2245 int min_from, max_to;
2246 int j;
2248 g = out_glyphs + out->used;
2249 *g = in_glyphs[otfg->f.index.from];
2250 if (g->g.code != otfg->glyph_id)
2252 g->g.c = 0;
2253 g->g.code = otfg->glyph_id;
2254 g->g.measured = 0;
2256 out->used++;
2257 min_from = g->g.from;
2258 max_to = g->g.to;
2259 if (otfg->f.index.from < otfg->f.index.to)
2261 /* OTFG substitutes multiple glyphs in IN. */
2262 for (j = from + otfg->f.index.from + 1;
2263 j <= from + otfg->f.index.to; j++)
2265 if (min_from > in->glyphs[j].from)
2266 min_from = in->glyphs[j].from;
2267 if (max_to < in->glyphs[j].to)
2268 max_to = in->glyphs[j].to;
2270 g->g.from = min_from;
2271 g->g.to = max_to;
2273 for (i++, otfg++; (i < otf_gstring.used
2274 && otfg->f.index.from == otfg[-1].f.index.from);
2275 i++, otfg++)
2277 g = out_glyphs + out->used;
2278 *g = in_glyphs[otfg->f.index.to];
2279 if (g->g.code != otfg->glyph_id)
2281 g->g.c = 0;
2282 g->g.code = otfg->glyph_id;
2283 g->g.measured = 0;
2285 out->used++;
2289 else
2291 if (out->allocated < out->used + len)
2293 SAFE_FREE ();
2294 return -2;
2296 for (i = 0; i < len; i++)
2297 out_glyphs[out->used++] = in_glyphs[i];
2300 if (gpos_features)
2302 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
2303 int x_ppem, y_ppem, x_scale, y_scale;
2305 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2306 < 0)
2308 SAFE_FREE ();
2309 return to;
2312 x_ppem = ft_face->size->metrics.x_ppem;
2313 y_ppem = ft_face->size->metrics.y_ppem;
2314 x_scale = ft_face->size->metrics.x_scale;
2315 y_scale = ft_face->size->metrics.y_scale;
2317 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2318 i < otf_gstring.used; i++, otfg++, g++)
2320 MFLTGlyphFT *prev;
2322 if (! otfg->glyph_id)
2323 continue;
2324 switch (otfg->positioning_type)
2326 case 0:
2327 break;
2328 case 1: /* Single */
2329 case 2: /* Pair */
2331 int format = otfg->f.f1.format;
2333 if (format & OTF_XPlacement)
2334 adjustment[i].xoff
2335 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2336 if (format & OTF_XPlaDevice)
2337 adjustment[i].xoff
2338 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2339 if (format & OTF_YPlacement)
2340 adjustment[i].yoff
2341 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2342 if (format & OTF_YPlaDevice)
2343 adjustment[i].yoff
2344 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2345 if (format & OTF_XAdvance)
2346 adjustment[i].xadv
2347 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2348 if (format & OTF_XAdvDevice)
2349 adjustment[i].xadv
2350 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2351 if (format & OTF_YAdvance)
2352 adjustment[i].yadv
2353 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2354 if (format & OTF_YAdvDevice)
2355 adjustment[i].yadv
2356 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2357 adjustment[i].set = 1;
2359 break;
2360 case 3: /* Cursive */
2361 /* Not yet supported. */
2362 break;
2363 case 4: /* Mark-to-Base */
2364 case 5: /* Mark-to-Ligature */
2365 if (! base)
2366 break;
2367 prev = base;
2368 goto label_adjust_anchor;
2369 default: /* i.e. case 6 Mark-to-Mark */
2370 if (! mark)
2371 break;
2372 prev = mark;
2374 label_adjust_anchor:
2376 int base_x, base_y, mark_x, mark_y;
2377 int this_from, this_to;
2379 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2380 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2381 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2382 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2384 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2385 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2386 x_ppem, y_ppem, &base_x, &base_y);
2387 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2388 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2389 x_ppem, y_ppem, &mark_x, &mark_y);
2390 adjustment[i].xoff = (base_x - mark_x);
2391 adjustment[i].yoff = - (base_y - mark_y);
2392 adjustment[i].back = (g - prev);
2393 adjustment[i].xadv = 0;
2394 adjustment[i].advance_is_absolute = 1;
2395 adjustment[i].set = 1;
2396 this_from = g->g.from;
2397 this_to = g->g.to;
2398 for (j = 0; prev + j < g; j++)
2400 if (this_from > prev[j].g.from)
2401 this_from = prev[j].g.from;
2402 if (this_to < prev[j].g.to)
2403 this_to = prev[j].g.to;
2405 for (; prev <= g; prev++)
2407 prev->g.from = this_from;
2408 prev->g.to = this_to;
2412 if (otfg->GlyphClass == OTF_GlyphClass0)
2413 base = mark = g;
2414 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2415 mark = g;
2416 else
2417 base = g;
2420 SAFE_FREE ();
2421 return to;
2423 simple_copy:
2424 SAFE_FREE ();
2425 if (out->allocated < out->used + len)
2426 return -2;
2427 font->get_metrics (font, in, from, to);
2428 memcpy (out_glyphs + out->used, in_glyphs,
2429 sizeof (MFLTGlyphFT) * len);
2430 out->used += len;
2431 return to;
2434 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2436 static MFLTGlyphString gstring;
2438 static bool m17n_flt_initialized;
2440 static Lisp_Object
2441 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2442 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2444 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2445 ptrdiff_t i;
2446 struct MFLTFontFT flt_font_ft;
2447 MFLT *flt = NULL;
2448 bool with_variation_selector = false;
2450 if (! m17n_flt_initialized)
2452 M17N_INIT ();
2453 #ifdef M17N_FLT_USE_NEW_FEATURE
2454 mflt_enable_new_feature = 1;
2455 mflt_try_otf = ftfont_try_otf;
2456 #endif /* M17N_FLT_USE_NEW_FEATURE */
2457 m17n_flt_initialized = 1;
2460 for (i = 0; i < len; i++)
2462 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2463 int c;
2465 if (NILP (g))
2466 break;
2467 c = LGLYPH_CHAR (g);
2468 if (CHAR_VARIATION_SELECTOR_P (c))
2469 with_variation_selector = true;
2472 len = i;
2474 if (otf && with_variation_selector)
2476 setup_otf_gstring (len);
2477 for (i = 0; i < len; i++)
2479 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2481 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2482 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2483 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2485 OTF_drive_cmap (otf, &otf_gstring);
2486 for (i = 0; i < otf_gstring.used; i++)
2488 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2489 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2490 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2492 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2493 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2494 LGSTRING_SET_GLYPH (lgstring, i, g0);
2496 if (len > otf_gstring.used)
2498 len = otf_gstring.used;
2499 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2504 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2506 if (NILP (family))
2507 flt_font_ft.flt_font.family = Mnil;
2508 else
2509 flt_font_ft.flt_font.family
2510 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2512 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2513 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2514 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2515 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2516 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2517 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2518 flt_font_ft.flt_font.internal = NULL;
2519 flt_font_ft.font = font;
2520 flt_font_ft.ft_face = ft_face;
2521 flt_font_ft.otf = otf;
2522 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2524 if (1 < len)
2526 /* A little bit ad hoc. Perhaps, shaper must get script and
2527 language information, and select a proper flt for them
2528 here. */
2529 int c1 = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 1));
2530 /* For the combining characters in the range U+300..U+36F,
2531 "combining" is the sole FLT provided by the m17n-lib. In
2532 addition, it is the sole FLT that can handle the other
2533 combining characters with non-OTF fonts. */
2534 if ((0x300 <= c1 && c1 <= 0x36F)
2535 || (! otf && CHAR_HAS_CATEGORY (c1, '^')))
2536 flt = mflt_get (msymbol ("combining"));
2538 if (! flt && ! otf)
2540 flt = mflt_find (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 0)),
2541 &flt_font_ft.flt_font);
2542 if (! flt)
2543 return make_number (0);
2546 MFLTGlyphFT *glyphs = (MFLTGlyphFT *) gstring.glyphs;
2547 ptrdiff_t allocated = gstring.allocated;
2548 ptrdiff_t incr_min = len - allocated;
2552 if (0 < incr_min)
2554 xfree (glyphs);
2555 glyphs = xpalloc (NULL, &allocated, incr_min, INT_MAX, sizeof *glyphs);
2557 incr_min = 1;
2559 for (i = 0; i < len; i++)
2561 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2562 memset (&glyphs[i], 0, sizeof glyphs[i]);
2563 glyphs[i].g.c = LGLYPH_CHAR (g);
2564 if (with_variation_selector)
2566 glyphs[i].g.code = LGLYPH_CODE (g);
2567 glyphs[i].g.encoded = 1;
2571 gstring.glyph_size = sizeof *glyphs;
2572 gstring.glyphs = (MFLTGlyph *) glyphs;
2573 gstring.allocated = allocated;
2574 gstring.used = len;
2575 gstring.r2l = 0;
2577 while (mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt) == -2);
2579 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2580 return Qnil;
2581 for (i = 0; i < gstring.used; i++)
2583 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2585 g->g.from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->g.from));
2586 g->g.to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->g.to));
2589 for (i = 0; i < gstring.used; i++)
2591 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2592 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2594 if (NILP (lglyph))
2596 lglyph = LGLYPH_NEW ();
2597 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2599 LGLYPH_SET_FROM (lglyph, g->g.from);
2600 LGLYPH_SET_TO (lglyph, g->g.to);
2601 LGLYPH_SET_CHAR (lglyph, g->g.c);
2602 LGLYPH_SET_CODE (lglyph, g->g.code);
2603 LGLYPH_SET_WIDTH (lglyph, g->g.xadv >> 6);
2604 LGLYPH_SET_LBEARING (lglyph, g->g.lbearing >> 6);
2605 LGLYPH_SET_RBEARING (lglyph, g->g.rbearing >> 6);
2606 LGLYPH_SET_ASCENT (lglyph, g->g.ascent >> 6);
2607 LGLYPH_SET_DESCENT (lglyph, g->g.descent >> 6);
2608 if (g->g.adjusted)
2610 Lisp_Object vec = make_uninit_vector (3);
2612 ASET (vec, 0, make_number (g->g.xoff >> 6));
2613 ASET (vec, 1, make_number (g->g.yoff >> 6));
2614 ASET (vec, 2, make_number (g->g.xadv >> 6));
2615 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2618 return make_number (i);
2621 Lisp_Object
2622 ftfont_shape (Lisp_Object lgstring)
2624 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2625 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2626 OTF *otf = ftfont_get_otf (ftfont_info);
2628 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2629 &ftfont_info->matrix);
2632 #endif /* HAVE_M17N_FLT */
2634 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2637 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2639 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2640 OTF *otf = ftfont_get_otf (ftfont_info);
2642 if (! otf)
2643 return 0;
2644 return OTF_get_variation_glyphs (otf, c, variations);
2647 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2648 #endif /* HAVE_LIBOTF */
2650 static const char *const ftfont_booleans [] = {
2651 ":antialias",
2652 ":hinting",
2653 ":verticallayout",
2654 ":autohint",
2655 ":globaladvance",
2656 ":outline",
2657 ":scalable",
2658 ":minspace",
2659 ":embolden",
2660 NULL,
2663 static const char *const ftfont_non_booleans [] = {
2664 ":family",
2665 ":familylang",
2666 ":style",
2667 ":stylelang",
2668 ":fullname",
2669 ":fullnamelang",
2670 ":slant",
2671 ":weight",
2672 ":size",
2673 ":width",
2674 ":aspect",
2675 ":pixelsize",
2676 ":spacing",
2677 ":foundry",
2678 ":hintstyle",
2679 ":file",
2680 ":index",
2681 ":ftface",
2682 ":rasterizer",
2683 ":scale",
2684 ":dpi",
2685 ":rgba",
2686 ":lcdfilter",
2687 ":charset",
2688 ":lang",
2689 ":fontversion",
2690 ":capability",
2691 NULL,
2694 void
2695 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2697 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2701 Lisp_Object
2702 ftfont_combining_capability (struct font *font)
2704 #ifdef HAVE_M17N_FLT
2705 return Qt;
2706 #else
2707 return Qnil;
2708 #endif
2711 static struct font_driver const ftfont_driver =
2713 /* We can't draw a text without device dependent functions. */
2714 .type = LISPSYM_INITIALLY (Qfreetype),
2715 .get_cache = ftfont_get_cache,
2716 .list = ftfont_list,
2717 .match = ftfont_match,
2718 .list_family = ftfont_list_family,
2719 .open = ftfont_open,
2720 .close = ftfont_close,
2721 .has_char = ftfont_has_char,
2722 .encode_char = ftfont_encode_char,
2723 .text_extents = ftfont_text_extents,
2724 .get_bitmap = ftfont_get_bitmap,
2725 .anchor_point = ftfont_anchor_point,
2726 #ifdef HAVE_LIBOTF
2727 .otf_capability = ftfont_otf_capability,
2728 #endif
2729 #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
2730 .shape = ftfont_shape,
2731 #endif
2732 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2733 .get_variation_glyphs = ftfont_variation_glyphs,
2734 #endif
2735 .filter_properties = ftfont_filter_properties,
2736 .combining_capability = ftfont_combining_capability,
2739 void
2740 syms_of_ftfont (void)
2742 /* Symbolic type of this font-driver. */
2743 DEFSYM (Qfreetype, "freetype");
2745 /* Fontconfig's generic families and their aliases. */
2746 DEFSYM (Qmonospace, "monospace");
2747 DEFSYM (Qsans_serif, "sans-serif");
2748 DEFSYM (Qsans, "sans");
2749 DEFSYM (Qsans__serif, "sans serif");
2751 staticpro (&freetype_font_cache);
2752 freetype_font_cache = list1 (Qt);
2754 staticpro (&ftfont_generic_family_list);
2755 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2756 Fcons (Qsans_serif, Qt),
2757 Fcons (Qsans, Qt));
2759 staticpro (&ft_face_cache);
2760 ft_face_cache = Qnil;
2762 register_font_driver (&ftfont_driver, NULL);