Fix Bug#21841
[emacs.git] / src / ftfont.c
blobfb1addb7a0ceedfad58ca608e0efa3318f8548a4
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2015 Free Software Foundation, Inc.
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
7 This file is part of GNU Emacs.
9 GNU Emacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 #include <config.h>
23 #include <stdio.h>
24 #include <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 "composite.h"
34 #include "font.h"
35 #include "ftfont.h"
37 /* Flag to tell if FcInit is already called or not. */
38 static bool fc_initialized;
40 /* Handle to a FreeType library instance. */
41 static FT_Library ft_library;
43 /* Cache for FreeType fonts. */
44 static Lisp_Object freetype_font_cache;
46 /* Cache for FT_Face and FcCharSet. */
47 static Lisp_Object ft_face_cache;
49 /* The actual structure for FreeType font that can be cast to struct
50 font. */
52 struct ftfont_info
54 struct font font;
55 #ifdef HAVE_LIBOTF
56 /* The following four members must be here in this order to be
57 compatible with struct xftfont_info (in xftfont.c). */
58 bool maybe_otf; /* Flag to tell if this may be OTF or not. */
59 OTF *otf;
60 #endif /* HAVE_LIBOTF */
61 FT_Size ft_size;
62 int index;
63 FT_Matrix matrix;
66 size_t ftfont_info_size = sizeof (struct ftfont_info);
68 enum ftfont_cache_for
70 FTFONT_CACHE_FOR_FACE,
71 FTFONT_CACHE_FOR_CHARSET,
72 FTFONT_CACHE_FOR_ENTITY
75 static Lisp_Object ftfont_pattern_entity (FcPattern *, Lisp_Object);
77 static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
78 FcPattern *);
79 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
80 enum ftfont_cache_for);
82 static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
84 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
86 static struct
88 /* registry name */
89 const char *name;
90 /* characters to distinguish the charset from the others */
91 int uniquifier[6];
92 /* additional constraint by language */
93 const char *lang;
94 /* set on demand */
95 FcCharSet *fc_charset;
96 } fc_charset_table[] =
97 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
98 { "iso8859-2", { 0x00A0, 0x010E }},
99 { "iso8859-3", { 0x00A0, 0x0108 }},
100 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
101 { "iso8859-5", { 0x00A0, 0x0401 }},
102 { "iso8859-6", { 0x00A0, 0x060C }},
103 { "iso8859-7", { 0x00A0, 0x0384 }},
104 { "iso8859-8", { 0x00A0, 0x05D0 }},
105 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
106 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
107 { "iso8859-11", { 0x00A0, 0x0E01 }},
108 { "iso8859-13", { 0x00A0, 0x201C }},
109 { "iso8859-14", { 0x00A0, 0x0174 }},
110 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
111 { "iso8859-16", { 0x00A0, 0x0218}},
112 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
113 { "big5-0", { 0xF6B1 }, "zh-tw" },
114 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
115 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
116 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
117 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
118 { "cns11643.1992-3", { 0x201A9 }},
119 { "cns11643.1992-4", { 0x20057 }},
120 { "cns11643.1992-5", { 0x20000 }},
121 { "cns11643.1992-6", { 0x20003 }},
122 { "cns11643.1992-7", { 0x20055 }},
123 { "gbk-0", { 0x4E06 }, "zh-cn"},
124 { "jisx0212.1990-0", { 0x4E44 }},
125 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
126 { "jisx0213.2000-2", { 0xFA49 }},
127 { "jisx0213.2004-1", { 0x20B9F }},
128 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
129 { "tis620.2529-1", { 0x0E01 }, "th"},
130 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
131 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
132 { "mulelao-1", { 0x0E81 }, "lo"},
133 { "unicode-sip", { 0x20000 }},
134 { NULL }
137 static bool
138 matching_prefix (char const *str, ptrdiff_t len, char const *pat)
140 return len == strlen (pat) && c_strncasecmp (str, pat, len) == 0;
143 /* Dirty hack for handing ADSTYLE property.
145 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
146 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
147 "Oblique", "Italic", or any non-normal SWIDTH property names
148 (e.g. SemiCondensed) are appended. In addition, if there's no
149 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
150 "Regular" is used for FC_STYLE (see the function
151 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
153 Unfortunately this behavior is not documented, so the following
154 code may fail if FreeType changes the behavior in the future. */
156 static Lisp_Object
157 get_adstyle_property (FcPattern *p)
159 FcChar8 *fcstr;
160 char *str, *end;
161 Lisp_Object adstyle;
163 #ifdef FC_FONTFORMAT
164 if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
165 && xstrcasecmp ((char *) fcstr, "bdf") != 0
166 && xstrcasecmp ((char *) fcstr, "pcf") != 0)
167 /* Not a BDF nor PCF font. */
168 return Qnil;
169 #endif
170 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
171 return Qnil;
172 str = (char *) fcstr;
173 for (end = str; *end && *end != ' '; end++);
174 if (matching_prefix (str, end - str, "Regular")
175 || matching_prefix (str, end - str, "Bold")
176 || matching_prefix (str, end - str, "Oblique")
177 || matching_prefix (str, end - str, "Italic"))
178 return Qnil;
179 adstyle = font_intern_prop (str, end - str, 1);
180 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
181 return Qnil;
182 return adstyle;
185 static Lisp_Object
186 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
188 Lisp_Object key, cache, entity;
189 FcChar8 *str;
190 char *file;
191 int idx;
192 int numeric;
193 double dbl;
194 FcBool b;
196 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
197 return Qnil;
198 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
199 return Qnil;
201 file = (char *) str;
202 key = Fcons (build_unibyte_string (file), make_number (idx));
203 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
204 entity = XCAR (cache);
205 if (! NILP (entity))
207 Lisp_Object val = font_make_entity ();
208 int i;
210 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
211 ASET (val, i, AREF (entity, i));
213 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
214 font_put_extra (val, QCfont_entity, key);
216 return val;
218 entity = font_make_entity ();
219 XSETCAR (cache, entity);
221 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
222 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
224 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
226 char *s = (char *) str;
227 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
229 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
231 char *s = (char *) str;
232 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
234 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
236 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
237 numeric = FC_WEIGHT_MEDIUM;
238 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
240 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
242 numeric += 100;
243 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
245 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
247 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
249 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
251 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
253 else
254 ASET (entity, FONT_SIZE_INDEX, make_number (0));
255 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
256 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
257 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
259 int dpi = dbl;
260 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
262 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
263 && b == FcTrue)
265 ASET (entity, FONT_SIZE_INDEX, make_number (0));
266 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
268 else
270 /* As this font is not scalable, perhaps this is a BDF or PCF
271 font. */
272 FT_Face ft_face;
274 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
275 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
276 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
278 BDF_PropertyRec rec;
280 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
281 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
282 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
283 FT_Done_Face (ft_face);
287 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
288 font_put_extra (entity, QCfont_entity, key);
289 return entity;
293 static Lisp_Object ftfont_generic_family_list;
295 static Lisp_Object
296 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
298 Lisp_Object slot;
299 FcPattern *match;
300 FcResult result;
301 FcLangSet *langset;
303 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
304 if (EQ (family, Qmono))
305 family = Qmonospace;
306 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
307 family = Qsans_serif;
308 slot = assq_no_quit (family, ftfont_generic_family_list);
309 if (! CONSP (slot))
310 return Qnil;
311 if (! EQ (XCDR (slot), Qt))
312 return XCDR (slot);
313 pattern = FcPatternDuplicate (pattern);
314 if (! pattern)
315 goto err;
316 FcPatternDel (pattern, FC_FOUNDRY);
317 FcPatternDel (pattern, FC_FAMILY);
318 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
319 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
321 /* This is to avoid the effect of locale. */
322 static const FcChar8 lang[] = "en";
323 langset = FcLangSetCreate ();
324 FcLangSetAdd (langset, lang);
325 FcPatternAddLangSet (pattern, FC_LANG, langset);
326 FcLangSetDestroy (langset);
328 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
329 FcDefaultSubstitute (pattern);
330 match = FcFontMatch (NULL, pattern, &result);
331 if (match)
333 FcChar8 *fam;
335 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
336 family = intern ((char *) fam);
338 else
339 family = Qnil;
340 XSETCDR (slot, family);
341 if (match) FcPatternDestroy (match);
342 err:
343 if (pattern) FcPatternDestroy (pattern);
344 return family;
347 struct ftfont_cache_data
349 FT_Face ft_face;
350 FcCharSet *fc_charset;
353 static Lisp_Object
354 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
356 Lisp_Object cache, val, entity;
357 struct ftfont_cache_data *cache_data;
359 if (FONT_ENTITY_P (key))
361 entity = key;
362 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
363 eassert (CONSP (val));
364 key = XCDR (val);
366 else
367 entity = Qnil;
369 if (NILP (ft_face_cache))
370 cache = Qnil;
371 else
372 cache = Fgethash (key, ft_face_cache, Qnil);
373 if (NILP (cache))
375 if (NILP (ft_face_cache))
376 ft_face_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
377 cache_data = xmalloc (sizeof *cache_data);
378 cache_data->ft_face = NULL;
379 cache_data->fc_charset = NULL;
380 val = make_save_ptr_int (cache_data, 0);
381 cache = Fcons (Qnil, val);
382 Fputhash (key, cache, ft_face_cache);
384 else
386 val = XCDR (cache);
387 cache_data = XSAVE_POINTER (val, 0);
390 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
391 return cache;
393 if (cache_for == FTFONT_CACHE_FOR_FACE
394 ? ! cache_data->ft_face : ! cache_data->fc_charset)
396 char *filename = SSDATA (XCAR (key));
397 int idx = XINT (XCDR (key));
399 if (cache_for == FTFONT_CACHE_FOR_FACE)
401 if (! ft_library
402 && FT_Init_FreeType (&ft_library) != 0)
403 return Qnil;
404 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
405 != 0)
406 return Qnil;
408 else
410 FcPattern *pat = NULL;
411 FcFontSet *fontset = NULL;
412 FcObjectSet *objset = NULL;
413 FcCharSet *charset = NULL;
415 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
416 FC_INDEX, FcTypeInteger, idx, NULL);
417 if (! pat)
418 goto finish;
419 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
420 if (! objset)
421 goto finish;
422 fontset = FcFontList (NULL, pat, objset);
423 if (! fontset)
424 goto finish;
425 if (fontset && fontset->nfont > 0
426 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
427 &charset)
428 == FcResultMatch))
429 cache_data->fc_charset = FcCharSetCopy (charset);
430 else
431 cache_data->fc_charset = FcCharSetCreate ();
433 finish:
434 if (fontset)
435 FcFontSetDestroy (fontset);
436 if (objset)
437 FcObjectSetDestroy (objset);
438 if (pat)
439 FcPatternDestroy (pat);
442 return cache;
445 FcCharSet *
446 ftfont_get_fc_charset (Lisp_Object entity)
448 Lisp_Object val, cache;
449 struct ftfont_cache_data *cache_data;
451 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
452 val = XCDR (cache);
453 cache_data = XSAVE_POINTER (val, 0);
454 return cache_data->fc_charset;
457 #ifdef HAVE_LIBOTF
458 static OTF *
459 ftfont_get_otf (struct ftfont_info *ftfont_info)
461 OTF *otf;
463 if (ftfont_info->otf)
464 return ftfont_info->otf;
465 if (! ftfont_info->maybe_otf)
466 return NULL;
467 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
468 if (! otf || OTF_get_table (otf, "head") < 0)
470 if (otf)
471 OTF_close (otf);
472 ftfont_info->maybe_otf = 0;
473 return NULL;
475 ftfont_info->otf = otf;
476 return otf;
478 #endif /* HAVE_LIBOTF */
480 static Lisp_Object ftfont_get_cache (struct frame *);
481 static Lisp_Object ftfont_list (struct frame *, Lisp_Object);
482 static Lisp_Object ftfont_match (struct frame *, Lisp_Object);
483 static Lisp_Object ftfont_list_family (struct frame *);
484 static Lisp_Object ftfont_open (struct frame *, Lisp_Object, int);
485 static void ftfont_close (struct font *);
486 static int ftfont_has_char (Lisp_Object, int);
487 static unsigned ftfont_encode_char (struct font *, int);
488 static void ftfont_text_extents (struct font *, unsigned *, int,
489 struct font_metrics *);
490 static int ftfont_get_bitmap (struct font *, unsigned,
491 struct font_bitmap *, int);
492 static int ftfont_anchor_point (struct font *, unsigned, int,
493 int *, int *);
494 #ifdef HAVE_LIBOTF
495 static Lisp_Object ftfont_otf_capability (struct font *);
496 # ifdef HAVE_M17N_FLT
497 static Lisp_Object ftfont_shape (Lisp_Object);
498 # endif
499 #endif
501 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
502 static int ftfont_variation_glyphs (struct font *, int c,
503 unsigned variations[256]);
504 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
506 struct font_driver ftfont_driver =
508 LISP_INITIALLY_ZERO, /* Qfreetype */
509 0, /* case insensitive */
510 ftfont_get_cache,
511 ftfont_list,
512 ftfont_match,
513 ftfont_list_family,
514 NULL, /* free_entity */
515 ftfont_open,
516 ftfont_close,
517 /* We can't draw a text without device dependent functions. */
518 NULL, /* prepare_face */
519 NULL, /* done_face */
520 ftfont_has_char,
521 ftfont_encode_char,
522 ftfont_text_extents,
523 /* We can't draw a text without device dependent functions. */
524 NULL, /* draw */
525 ftfont_get_bitmap,
526 NULL, /* free_bitmap */
527 ftfont_anchor_point,
528 #ifdef HAVE_LIBOTF
529 ftfont_otf_capability,
530 #else /* not HAVE_LIBOTF */
531 NULL,
532 #endif /* not HAVE_LIBOTF */
533 NULL, /* otf_drive */
534 NULL, /* start_for_frame */
535 NULL, /* end_for_frame */
536 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
537 ftfont_shape,
538 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
539 NULL,
540 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
541 NULL, /* check */
543 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
544 ftfont_variation_glyphs,
545 #else
546 NULL,
547 #endif
549 ftfont_filter_properties, /* filter_properties */
552 static Lisp_Object
553 ftfont_get_cache (struct frame *f)
555 return freetype_font_cache;
558 static int
559 ftfont_get_charset (Lisp_Object registry)
561 char *str = SSDATA (SYMBOL_NAME (registry));
562 USE_SAFE_ALLOCA;
563 char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
564 Lisp_Object regexp;
565 int i, j;
567 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
569 if (str[i] == '.')
570 re[j++] = '\\';
571 else if (str[i] == '*')
572 re[j++] = '.';
573 re[j] = str[i];
574 if (re[j] == '?')
575 re[j] = '.';
577 re[j] = '\0';
578 regexp = make_unibyte_string (re, j);
579 SAFE_FREE ();
580 for (i = 0; fc_charset_table[i].name; i++)
581 if (fast_c_string_match_ignore_case
582 (regexp, fc_charset_table[i].name,
583 strlen (fc_charset_table[i].name)) >= 0)
584 break;
585 if (! fc_charset_table[i].name)
586 return -1;
587 if (! fc_charset_table[i].fc_charset)
589 FcCharSet *charset = FcCharSetCreate ();
590 int *uniquifier = fc_charset_table[i].uniquifier;
592 if (! charset)
593 return -1;
594 for (j = 0; uniquifier[j]; j++)
595 if (! FcCharSetAddChar (charset, uniquifier[j]))
597 FcCharSetDestroy (charset);
598 return -1;
600 fc_charset_table[i].fc_charset = charset;
602 return i;
605 struct OpenTypeSpec
607 Lisp_Object script;
608 unsigned int script_tag, langsys_tag;
609 int nfeatures[2];
610 unsigned int *features[2];
613 #define OTF_SYM_TAG(SYM, TAG) \
614 do { \
615 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
616 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
617 } while (0)
619 #define OTF_TAG_STR(TAG, P) \
620 do { \
621 (P)[0] = (char) (TAG >> 24); \
622 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
623 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
624 (P)[3] = (char) (TAG & 0xFF); \
625 (P)[4] = '\0'; \
626 } while (0)
628 #ifdef HAVE_LIBOTF
629 #define OTF_TAG_SYM(SYM, TAG) \
630 do { \
631 char str[5]; \
633 OTF_TAG_STR (TAG, str); \
634 (SYM) = font_intern_prop (str, 4, 1); \
635 } while (0)
636 #endif
639 static struct OpenTypeSpec *
640 ftfont_get_open_type_spec (Lisp_Object otf_spec)
642 struct OpenTypeSpec *spec = malloc (sizeof *spec);
643 Lisp_Object val;
644 int i, j;
645 bool negative;
647 if (! spec)
648 return NULL;
649 spec->script = XCAR (otf_spec);
650 if (! NILP (spec->script))
652 OTF_SYM_TAG (spec->script, spec->script_tag);
653 val = assq_no_quit (spec->script, Votf_script_alist);
654 if (CONSP (val) && SYMBOLP (XCDR (val)))
655 spec->script = XCDR (val);
656 else
657 spec->script = Qnil;
659 else
660 spec->script_tag = 0x44464C54; /* "DFLT" */
661 otf_spec = XCDR (otf_spec);
662 spec->langsys_tag = 0;
663 if (! NILP (otf_spec))
665 val = XCAR (otf_spec);
666 if (! NILP (val))
667 OTF_SYM_TAG (val, spec->langsys_tag);
668 otf_spec = XCDR (otf_spec);
670 spec->nfeatures[0] = spec->nfeatures[1] = 0;
671 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
673 Lisp_Object len;
675 val = XCAR (otf_spec);
676 if (NILP (val))
677 continue;
678 len = Flength (val);
679 spec->features[i] =
680 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
682 : malloc (XINT (len) * sizeof *spec->features[i]));
683 if (! spec->features[i])
685 if (i > 0 && spec->features[0])
686 free (spec->features[0]);
687 free (spec);
688 return NULL;
690 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
692 if (NILP (XCAR (val)))
693 negative = 1;
694 else
696 unsigned int tag;
698 OTF_SYM_TAG (XCAR (val), tag);
699 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
702 spec->nfeatures[i] = j;
704 return spec;
707 static FcPattern *
708 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
710 Lisp_Object tmp, extra;
711 FcPattern *pattern = NULL;
712 FcCharSet *charset = NULL;
713 FcLangSet *langset = NULL;
714 int n;
715 int dpi = -1;
716 int scalable = -1;
717 Lisp_Object script = Qnil;
718 Lisp_Object registry;
719 int fc_charset_idx;
721 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
722 && n < 100)
723 /* Fontconfig doesn't support reverse-italic/oblique. */
724 return NULL;
726 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
727 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
728 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
729 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
730 scalable = 1;
732 registry = AREF (spec, FONT_REGISTRY_INDEX);
733 if (NILP (registry)
734 || EQ (registry, Qascii_0)
735 || EQ (registry, Qiso10646_1)
736 || EQ (registry, Qunicode_bmp))
737 fc_charset_idx = -1;
738 else
740 FcChar8 *lang;
742 fc_charset_idx = ftfont_get_charset (registry);
743 if (fc_charset_idx < 0)
744 return NULL;
745 charset = fc_charset_table[fc_charset_idx].fc_charset;
746 *langname = fc_charset_table[fc_charset_idx].lang;
747 lang = (FcChar8 *) *langname;
748 if (lang)
750 langset = FcLangSetCreate ();
751 if (! langset)
752 goto err;
753 FcLangSetAdd (langset, lang);
757 otlayout[0] = '\0';
758 for (extra = AREF (spec, FONT_EXTRA_INDEX);
759 CONSP (extra); extra = XCDR (extra))
761 Lisp_Object key, val;
763 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
764 if (EQ (key, QCdpi))
766 if (INTEGERP (val))
767 dpi = XINT (val);
769 else if (EQ (key, QClang))
771 if (! langset)
772 langset = FcLangSetCreate ();
773 if (! langset)
774 goto err;
775 if (SYMBOLP (val))
777 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
778 goto err;
780 else
781 for (; CONSP (val); val = XCDR (val))
782 if (SYMBOLP (XCAR (val))
783 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
784 goto err;
786 else if (EQ (key, QCotf))
788 if (CONSP (val))
790 *otspec = ftfont_get_open_type_spec (val);
791 if (! *otspec)
792 return NULL;
793 strcpy (otlayout, "otlayout:");
794 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
795 script = (*otspec)->script;
798 else if (EQ (key, QCscript))
799 script = val;
800 else if (EQ (key, QCscalable))
801 scalable = ! NILP (val);
804 if (! NILP (script) && ! charset)
806 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
808 if (CONSP (chars) && CONSP (CDR (chars)))
810 charset = FcCharSetCreate ();
811 if (! charset)
812 goto err;
813 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
814 if (CHARACTERP (XCAR (chars))
815 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
816 goto err;
820 pattern = FcPatternCreate ();
821 if (! pattern)
822 goto err;
823 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
824 if (! NILP (tmp)
825 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
826 goto err;
827 tmp = AREF (spec, FONT_FAMILY_INDEX);
828 if (! NILP (tmp)
829 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
830 goto err;
831 if (charset
832 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
833 goto err;
834 if (langset
835 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
836 goto err;
837 if (dpi >= 0
838 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
839 goto err;
840 if (scalable >= 0
841 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
842 goto err;
844 goto finish;
846 err:
847 /* We come here because of unexpected error in fontconfig API call
848 (usually insufficient memory). */
849 if (pattern)
851 FcPatternDestroy (pattern);
852 pattern = NULL;
854 if (*otspec)
856 if ((*otspec)->nfeatures[0] > 0)
857 free ((*otspec)->features[0]);
858 if ((*otspec)->nfeatures[1] > 0)
859 free ((*otspec)->features[1]);
860 free (*otspec);
861 *otspec = NULL;
864 finish:
865 if (langset) FcLangSetDestroy (langset);
866 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
867 return pattern;
870 static Lisp_Object
871 ftfont_list (struct frame *f, Lisp_Object spec)
873 Lisp_Object val = Qnil, family, adstyle;
874 int i;
875 FcPattern *pattern;
876 FcFontSet *fontset = NULL;
877 FcObjectSet *objset = NULL;
878 FcCharSet *charset;
879 Lisp_Object chars = Qnil;
880 char otlayout[15]; /* For "otlayout:XXXX" */
881 struct OpenTypeSpec *otspec = NULL;
882 int spacing = -1;
883 const char *langname = NULL;
885 if (! fc_initialized)
887 FcInit ();
888 fc_initialized = 1;
891 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
892 if (! pattern)
893 return Qnil;
894 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
896 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
897 if (! NILP (val))
899 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
900 if (CONSP (val) && VECTORP (XCDR (val)))
901 chars = XCDR (val);
903 val = Qnil;
905 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
906 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
907 family = AREF (spec, FONT_FAMILY_INDEX);
908 if (! NILP (family))
910 Lisp_Object resolved;
912 resolved = ftfont_resolve_generic_family (family, pattern);
913 if (! NILP (resolved))
915 FcPatternDel (pattern, FC_FAMILY);
916 if (! FcPatternAddString (pattern, FC_FAMILY,
917 SYMBOL_FcChar8 (resolved)))
918 goto err;
921 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
922 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
923 adstyle = Qnil;
924 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
925 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
926 FC_STYLE, FC_FILE, FC_INDEX,
927 #ifdef FC_CAPABILITY
928 FC_CAPABILITY,
929 #endif /* FC_CAPABILITY */
930 #ifdef FC_FONTFORMAT
931 FC_FONTFORMAT,
932 #endif
933 NULL);
934 if (! objset)
935 goto err;
936 if (! NILP (chars))
937 FcObjectSetAdd (objset, FC_CHARSET);
939 fontset = FcFontList (NULL, pattern, objset);
940 if (! fontset || fontset->nfont == 0)
941 goto finish;
942 #if 0
943 /* Need fix because this finds any fonts. */
944 if (fontset->nfont == 0 && ! NILP (family))
946 /* Try matching with configuration. For instance, the
947 configuration may specify "Nimbus Mono L" as an alias of
948 "Courier". */
949 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
950 SYMBOL_FcChar8 (family), NULL);
951 FcChar8 *fam;
953 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
955 for (i = 0;
956 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
957 i++)
959 FcPatternDel (pattern, FC_FAMILY);
960 FcPatternAddString (pattern, FC_FAMILY, fam);
961 FcFontSetDestroy (fontset);
962 fontset = FcFontList (NULL, pattern, objset);
963 if (fontset && fontset->nfont > 0)
964 break;
968 #endif
969 for (i = 0; i < fontset->nfont; i++)
971 Lisp_Object entity;
973 if (spacing >= 0)
975 int this;
977 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
978 == FcResultMatch)
979 && spacing != this)
980 continue;
983 #ifdef FC_CAPABILITY
984 if (otlayout[0])
986 FcChar8 *this;
988 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
989 != FcResultMatch
990 || ! strstr ((char *) this, otlayout))
991 continue;
993 #endif /* FC_CAPABILITY */
994 #ifdef HAVE_LIBOTF
995 if (otspec)
997 FcChar8 *file;
998 bool passed;
999 OTF *otf;
1001 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1002 != FcResultMatch)
1003 continue;
1004 otf = OTF_open ((char *) file);
1005 if (! otf)
1006 continue;
1007 passed = (OTF_check_features (otf, 1, otspec->script_tag,
1008 otspec->langsys_tag,
1009 otspec->features[0],
1010 otspec->nfeatures[0]) == 1
1011 && OTF_check_features (otf, 0, otspec->script_tag,
1012 otspec->langsys_tag,
1013 otspec->features[1],
1014 otspec->nfeatures[1]) == 1);
1015 OTF_close (otf);
1016 if (!passed)
1017 continue;
1019 #endif /* HAVE_LIBOTF */
1020 if (VECTORP (chars))
1022 ptrdiff_t j;
1024 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1025 != FcResultMatch)
1026 continue;
1027 for (j = 0; j < ASIZE (chars); j++)
1028 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1029 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1030 break;
1031 if (j == ASIZE (chars))
1032 continue;
1034 if (! NILP (adstyle) || langname)
1036 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1038 if (! NILP (adstyle)
1039 && (NILP (this_adstyle)
1040 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1041 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1042 continue;
1043 if (langname
1044 && ! NILP (this_adstyle)
1045 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1046 continue;
1048 entity = ftfont_pattern_entity (fontset->fonts[i],
1049 AREF (spec, FONT_EXTRA_INDEX));
1050 if (! NILP (entity))
1051 val = Fcons (entity, val);
1053 val = Fnreverse (val);
1054 goto finish;
1056 err:
1057 /* We come here because of unexpected error in fontconfig API call
1058 (usually insufficient memory). */
1059 val = Qnil;
1061 finish:
1062 FONT_ADD_LOG ("ftfont-list", spec, val);
1063 if (objset) FcObjectSetDestroy (objset);
1064 if (fontset) FcFontSetDestroy (fontset);
1065 if (pattern) FcPatternDestroy (pattern);
1066 return val;
1069 static Lisp_Object
1070 ftfont_match (struct frame *f, Lisp_Object spec)
1072 Lisp_Object entity = Qnil;
1073 FcPattern *pattern, *match = NULL;
1074 FcResult result;
1075 char otlayout[15]; /* For "otlayout:XXXX" */
1076 struct OpenTypeSpec *otspec = NULL;
1077 const char *langname = NULL;
1079 if (! fc_initialized)
1081 FcInit ();
1082 fc_initialized = 1;
1085 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1086 if (! pattern)
1087 return Qnil;
1089 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1091 FcValue value;
1093 value.type = FcTypeDouble;
1094 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1095 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1097 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1099 FcDefaultSubstitute (pattern);
1100 match = FcFontMatch (NULL, pattern, &result);
1101 if (match)
1103 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1104 FcPatternDestroy (match);
1105 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1106 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1107 ftfont_generic_family_list))
1108 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1109 AREF (entity, FONT_FAMILY_INDEX))))
1110 entity = Qnil;
1113 FcPatternDestroy (pattern);
1115 FONT_ADD_LOG ("ftfont-match", spec, entity);
1116 return entity;
1119 static Lisp_Object
1120 ftfont_list_family (struct frame *f)
1122 Lisp_Object list = Qnil;
1123 FcPattern *pattern = NULL;
1124 FcFontSet *fontset = NULL;
1125 FcObjectSet *objset = NULL;
1126 int i;
1128 if (! fc_initialized)
1130 FcInit ();
1131 fc_initialized = 1;
1134 pattern = FcPatternCreate ();
1135 if (! pattern)
1136 goto finish;
1137 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1138 if (! objset)
1139 goto finish;
1140 fontset = FcFontList (NULL, pattern, objset);
1141 if (! fontset)
1142 goto finish;
1144 for (i = 0; i < fontset->nfont; i++)
1146 FcPattern *pat = fontset->fonts[i];
1147 FcChar8 *str;
1149 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1150 list = Fcons (intern ((char *) str), list);
1153 finish:
1154 if (objset) FcObjectSetDestroy (objset);
1155 if (fontset) FcFontSetDestroy (fontset);
1156 if (pattern) FcPatternDestroy (pattern);
1158 return list;
1162 Lisp_Object
1163 ftfont_open2 (struct frame *f,
1164 Lisp_Object entity,
1165 int pixel_size,
1166 Lisp_Object font_object)
1168 struct ftfont_info *ftfont_info;
1169 struct font *font;
1170 struct ftfont_cache_data *cache_data;
1171 FT_Face ft_face;
1172 FT_Size ft_size;
1173 FT_UInt size;
1174 Lisp_Object val, filename, idx, cache;
1175 bool scalable;
1176 int spacing;
1177 int i;
1178 double upEM;
1180 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1181 if (! CONSP (val))
1182 return Qnil;
1183 val = XCDR (val);
1184 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1185 if (NILP (cache))
1186 return Qnil;
1187 filename = XCAR (val);
1188 idx = XCDR (val);
1189 val = XCDR (cache);
1190 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1191 ft_face = cache_data->ft_face;
1192 if (XSAVE_INTEGER (val, 1) > 0)
1194 /* FT_Face in this cache is already used by the different size. */
1195 if (FT_New_Size (ft_face, &ft_size) != 0)
1196 return Qnil;
1197 if (FT_Activate_Size (ft_size) != 0)
1199 FT_Done_Size (ft_size);
1200 return Qnil;
1203 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1204 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1205 if (size == 0)
1206 size = pixel_size;
1207 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1209 if (XSAVE_INTEGER (val, 1) == 0)
1210 FT_Done_Face (ft_face);
1211 return Qnil;
1214 ASET (font_object, FONT_FILE_INDEX, filename);
1215 font = XFONT_OBJECT (font_object);
1216 ftfont_info = (struct ftfont_info *) font;
1217 ftfont_info->ft_size = ft_face->size;
1218 ftfont_info->index = XINT (idx);
1219 #ifdef HAVE_LIBOTF
1220 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1221 ftfont_info->otf = NULL;
1222 #endif /* HAVE_LIBOTF */
1223 /* This means that there's no need of transformation. */
1224 ftfont_info->matrix.xx = 0;
1225 font->pixel_size = size;
1226 font->driver = &ftfont_driver;
1227 font->encoding_charset = font->repertory_charset = -1;
1229 upEM = ft_face->units_per_EM;
1230 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1231 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1232 if (scalable)
1234 font->ascent = ft_face->ascender * size / upEM + 0.5;
1235 font->descent = - ft_face->descender * size / upEM + 0.5;
1236 font->height = ft_face->height * size / upEM + 0.5;
1238 else
1240 font->ascent = ft_face->size->metrics.ascender >> 6;
1241 font->descent = - ft_face->size->metrics.descender >> 6;
1242 font->height = ft_face->size->metrics.height >> 6;
1244 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1245 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1246 else
1247 spacing = FC_PROPORTIONAL;
1248 if (spacing != FC_PROPORTIONAL
1249 #ifdef FC_DUAL
1250 && spacing != FC_DUAL
1251 #endif /* FC_DUAL */
1253 font->min_width = font->average_width = font->space_width
1254 = (scalable ? ft_face->max_advance_width * size / upEM + 0.5
1255 : ft_face->size->metrics.max_advance >> 6);
1256 else
1258 int n;
1260 font->min_width = font->average_width = font->space_width = 0;
1261 for (i = 32, n = 0; i < 127; i++)
1262 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1264 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1266 if (this_width > 0
1267 && (! font->min_width || font->min_width > this_width))
1268 font->min_width = this_width;
1269 if (i == 32)
1270 font->space_width = this_width;
1271 font->average_width += this_width;
1272 n++;
1274 if (n > 0)
1275 font->average_width /= n;
1278 font->baseline_offset = 0;
1279 font->relative_compose = 0;
1280 font->default_ascent = 0;
1281 font->vertical_centering = 0;
1282 if (scalable)
1284 font->underline_position = (-ft_face->underline_position * size / upEM
1285 + 0.5);
1286 font->underline_thickness = (ft_face->underline_thickness * size / upEM
1287 + 0.5);
1289 else
1291 font->underline_position = -1;
1292 font->underline_thickness = 0;
1295 return font_object;
1298 static Lisp_Object
1299 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1301 Lisp_Object font_object;
1302 FT_UInt size;
1303 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1304 if (size == 0)
1305 size = pixel_size;
1306 font_object = font_build_object (VECSIZE (struct ftfont_info),
1307 Qfreetype, entity, size);
1308 return ftfont_open2 (f, entity, pixel_size, font_object);
1311 static void
1312 ftfont_close (struct font *font)
1314 /* FIXME: Although this function can be called while garbage-collecting,
1315 the function assumes that Lisp data structures are properly-formed.
1316 This invalid assumption can lead to core dumps (Bug#20890). */
1318 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1319 Lisp_Object val, cache;
1321 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1322 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1323 eassert (CONSP (cache));
1324 val = XCDR (cache);
1325 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1326 if (XSAVE_INTEGER (val, 1) == 0)
1328 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1330 FT_Done_Face (cache_data->ft_face);
1331 #ifdef HAVE_LIBOTF
1332 if (ftfont_info->otf)
1333 OTF_close (ftfont_info->otf);
1334 #endif
1335 cache_data->ft_face = NULL;
1337 else
1338 FT_Done_Size (ftfont_info->ft_size);
1341 static int
1342 ftfont_has_char (Lisp_Object font, int c)
1344 struct charset *cs = NULL;
1346 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1347 && charset_jisx0208 >= 0)
1348 cs = CHARSET_FROM_ID (charset_jisx0208);
1349 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1350 && charset_ksc5601 >= 0)
1351 cs = CHARSET_FROM_ID (charset_ksc5601);
1352 if (cs)
1353 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1355 if (FONT_ENTITY_P (font))
1357 FcCharSet *charset = ftfont_get_fc_charset (font);
1359 return (FcCharSetHasChar (charset, c) == FcTrue);
1361 else
1363 struct ftfont_info *ftfont_info;
1365 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1366 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1367 != 0);
1371 static unsigned
1372 ftfont_encode_char (struct font *font, int c)
1374 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1375 FT_Face ft_face = ftfont_info->ft_size->face;
1376 FT_ULong charcode = c;
1377 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1379 return (code > 0 ? code : FONT_INVALID_CODE);
1382 static void
1383 ftfont_text_extents (struct font *font, unsigned int *code,
1384 int nglyphs, struct font_metrics *metrics)
1386 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1387 FT_Face ft_face = ftfont_info->ft_size->face;
1388 int i, width = 0;
1389 bool first;
1391 if (ftfont_info->ft_size != ft_face->size)
1392 FT_Activate_Size (ftfont_info->ft_size);
1394 for (i = 0, first = 1; i < nglyphs; i++)
1396 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1398 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1400 if (first)
1402 metrics->lbearing = m->horiBearingX >> 6;
1403 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1404 metrics->ascent = m->horiBearingY >> 6;
1405 metrics->descent = (m->height - m->horiBearingY) >> 6;
1406 first = 0;
1408 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1409 metrics->lbearing = width + (m->horiBearingX >> 6);
1410 if (metrics->rbearing
1411 < width + ((m->horiBearingX + m->width) >> 6))
1412 metrics->rbearing
1413 = width + ((m->horiBearingX + m->width) >> 6);
1414 if (metrics->ascent < (m->horiBearingY >> 6))
1415 metrics->ascent = m->horiBearingY >> 6;
1416 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1417 metrics->descent = (m->height - m->horiBearingY) >> 6;
1418 width += m->horiAdvance >> 6;
1420 else
1421 width += font->space_width;
1423 metrics->width = width;
1426 static int
1427 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1429 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1430 FT_Face ft_face = ftfont_info->ft_size->face;
1431 FT_Int32 load_flags = FT_LOAD_RENDER;
1433 if (ftfont_info->ft_size != ft_face->size)
1434 FT_Activate_Size (ftfont_info->ft_size);
1435 if (bits_per_pixel == 1)
1437 #ifdef FT_LOAD_TARGET_MONO
1438 load_flags |= FT_LOAD_TARGET_MONO;
1439 #else
1440 load_flags |= FT_LOAD_MONOCHROME;
1441 #endif
1443 else if (bits_per_pixel != 8)
1444 /* We don't support such a rendering. */
1445 return -1;
1447 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1448 return -1;
1449 bitmap->bits_per_pixel
1450 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1451 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1452 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1453 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1454 : -1);
1455 if (bitmap->bits_per_pixel < 0)
1456 /* We don't support that kind of pixel mode. */
1457 return -1;
1458 bitmap->rows = ft_face->glyph->bitmap.rows;
1459 bitmap->width = ft_face->glyph->bitmap.width;
1460 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1461 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1462 bitmap->left = ft_face->glyph->bitmap_left;
1463 bitmap->top = ft_face->glyph->bitmap_top;
1464 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1466 return 0;
1469 static int
1470 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1471 int *x, int *y)
1473 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1474 FT_Face ft_face = ftfont_info->ft_size->face;
1476 if (ftfont_info->ft_size != ft_face->size)
1477 FT_Activate_Size (ftfont_info->ft_size);
1478 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1479 return -1;
1480 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1481 return -1;
1482 if (idx >= ft_face->glyph->outline.n_points)
1483 return -1;
1484 *x = ft_face->glyph->outline.points[idx].x;
1485 *y = ft_face->glyph->outline.points[idx].y;
1486 return 0;
1489 #ifdef HAVE_LIBOTF
1491 static Lisp_Object
1492 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1494 Lisp_Object scripts, langsyses, features, sym;
1495 int i, j, k, l;
1497 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1499 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1501 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1503 OTF_LangSys *otf_langsys;
1505 if (j >= 0)
1506 otf_langsys = otf_script->LangSys + j;
1507 else if (otf_script->DefaultLangSysOffset)
1508 otf_langsys = &otf_script->DefaultLangSys;
1509 else
1510 break;
1512 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1514 l = otf_langsys->FeatureIndex[k];
1515 if (l >= gsub_gpos->FeatureList.FeatureCount)
1516 continue;
1517 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1518 features = Fcons (sym, features);
1520 if (j >= 0)
1521 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1522 else
1523 sym = Qnil;
1524 langsyses = Fcons (Fcons (sym, features), langsyses);
1527 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1528 scripts = Fcons (Fcons (sym, langsyses), scripts);
1530 return scripts;
1535 static Lisp_Object
1536 ftfont_otf_capability (struct font *font)
1538 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1539 OTF *otf = ftfont_get_otf (ftfont_info);
1540 Lisp_Object gsub_gpos;
1542 if (! otf)
1543 return Qnil;
1544 gsub_gpos = Fcons (Qnil, Qnil);
1545 if (OTF_get_table (otf, "GSUB") == 0
1546 && otf->gsub->FeatureList.FeatureCount > 0)
1547 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1548 if (OTF_get_table (otf, "GPOS") == 0
1549 && otf->gpos->FeatureList.FeatureCount > 0)
1550 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1551 return gsub_gpos;
1554 #ifdef HAVE_M17N_FLT
1556 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1557 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1558 /* We can use the new feature of libotf and m17n-flt to handle the
1559 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1560 some Agian scripts. */
1561 #define M17N_FLT_USE_NEW_FEATURE
1562 #endif
1564 struct MFLTFontFT
1566 MFLTFont flt_font;
1567 struct font *font;
1568 FT_Face ft_face;
1569 OTF *otf;
1570 FT_Matrix *matrix;
1573 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1574 We use this structure instead of MFLTGlyph to utilize the new
1575 feature of libotf ver.0.9.15 which requires saving and restoring
1576 the value of OTF_GlyphString.positioning_type in the succeeding
1577 calls of the callback function MFLTFont.drive_otf (which is set to
1578 ftfont_drive_otf). */
1580 typedef struct {
1581 MFLTGlyph g;
1582 unsigned int libotf_positioning_type;
1583 } MFLTGlyphFT;
1585 static int
1586 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1587 int from, int to)
1589 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1590 FT_Face ft_face = flt_font_ft->ft_face;
1591 MFLTGlyphFT *g;
1593 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1594 if (! g->g.encoded)
1596 FT_UInt code = FT_Get_Char_Index (ft_face, g->g.code);
1598 g->g.code = code > 0 ? code : FONT_INVALID_CODE;
1599 g->g.encoded = 1;
1601 return 0;
1604 /* Operators for 26.6 fixed fractional pixel format */
1606 #define FLOOR(x) ((x) & -64)
1607 #define CEIL(x) (((x)+63) & -64)
1608 #define ROUND(x) (((x)+32) & -64)
1610 static int
1611 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1612 int from, int to)
1614 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1615 FT_Face ft_face = flt_font_ft->ft_face;
1616 MFLTGlyphFT *g;
1618 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1619 if (! g->g.measured)
1621 if (g->g.code != FONT_INVALID_CODE)
1623 FT_Glyph_Metrics *m;
1625 if (FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_DEFAULT) != 0)
1626 emacs_abort ();
1627 m = &ft_face->glyph->metrics;
1628 if (flt_font_ft->matrix)
1630 FT_Vector v[4];
1631 int i;
1633 v[0].x = v[1].x = m->horiBearingX;
1634 v[2].x = v[3].x = m->horiBearingX + m->width;
1635 v[0].y = v[2].y = m->horiBearingY;
1636 v[1].y = v[3].y = m->horiBearingY - m->height;
1637 for (i = 0; i < 4; i++)
1638 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1639 g->g.lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1640 g->g.rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1641 g->g.ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1642 g->g.descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1644 else
1646 g->g.lbearing = FLOOR (m->horiBearingX);
1647 g->g.rbearing = CEIL (m->horiBearingX + m->width);
1648 g->g.ascent = CEIL (m->horiBearingY);
1649 g->g.descent = - FLOOR (m->horiBearingY - m->height);
1651 g->g.xadv = ROUND (ft_face->glyph->advance.x);
1653 else
1655 g->g.lbearing = 0;
1656 g->g.rbearing = g->g.xadv = flt_font_ft->font->space_width << 6;
1657 g->g.ascent = flt_font_ft->font->ascent << 6;
1658 g->g.descent = flt_font_ft->font->descent << 6;
1660 g->g.yadv = 0;
1661 g->g.measured = 1;
1663 return 0;
1666 static int
1667 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1669 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1671 #define FEATURE_ANY(IDX) \
1672 (spec->features[IDX] \
1673 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1675 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1676 OTF *otf = flt_font_ft->otf;
1677 OTF_Tag *tags;
1678 int i, n;
1679 bool negative;
1681 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1682 /* Return true iff any of GSUB or GPOS support the script (and
1683 language). */
1684 return (otf
1685 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1686 NULL, 0) > 0
1687 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1688 NULL, 0) > 0));
1690 for (i = 0; i < 2; i++)
1691 if (! FEATURE_ANY (i))
1693 if (FEATURE_NONE (i))
1695 if (otf
1696 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1697 NULL, 0) > 0)
1698 return 0;
1699 continue;
1701 if (spec->features[i][0] == 0xFFFFFFFF)
1703 if (! otf
1704 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1705 NULL, 0) <= 0)
1706 continue;
1708 else if (! otf)
1709 return 0;
1710 for (n = 1; spec->features[i][n]; n++);
1711 USE_SAFE_ALLOCA;
1712 SAFE_NALLOCA (tags, 1, n);
1713 for (n = 0, negative = 0; spec->features[i][n]; n++)
1715 if (spec->features[i][n] == 0xFFFFFFFF)
1716 negative = 1;
1717 else if (negative)
1718 tags[n - 1] = spec->features[i][n] | 0x80000000;
1719 else
1720 tags[n] = spec->features[i][n];
1722 bool passed = true;
1723 #ifndef M17N_FLT_USE_NEW_FEATURE
1724 passed = n - negative > 0;
1725 #endif
1726 if (passed)
1727 passed = (OTF_check_features (otf, i == 0, spec->script,
1728 spec->langsys, tags, n - negative)
1729 != 1);
1730 SAFE_FREE ();
1731 if (passed)
1732 return 0;
1734 return 1;
1735 #undef FEATURE_NONE
1736 #undef FEATURE_ANY
1739 #define DEVICE_DELTA(table, size) \
1740 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1741 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1742 : 0)
1744 static void
1745 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1746 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1748 if (anchor->AnchorFormat == 2)
1750 FT_Outline *outline;
1751 int ap = anchor->f.f1.AnchorPoint;
1753 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1754 outline = &ft_face->glyph->outline;
1755 if (ap < outline->n_points)
1757 *x = outline->points[ap].x << 6;
1758 *y = outline->points[ap].y << 6;
1761 else if (anchor->AnchorFormat == 3)
1763 if (anchor->f.f2.XDeviceTable.offset
1764 && anchor->f.f2.XDeviceTable.DeltaValue)
1765 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1766 if (anchor->f.f2.YDeviceTable.offset
1767 && anchor->f.f2.YDeviceTable.DeltaValue)
1768 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1772 static OTF_GlyphString otf_gstring;
1774 static void
1775 setup_otf_gstring (int size)
1777 if (otf_gstring.size < size)
1779 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1780 size, sizeof (OTF_Glyph));
1781 otf_gstring.size = size;
1783 otf_gstring.used = size;
1784 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1787 #ifdef M17N_FLT_USE_NEW_FEATURE
1789 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1790 #define PACK_OTF_TAG(TAG) \
1791 ((((TAG) & 0x7F000000) >> 3) \
1792 | (((TAG) & 0x7F0000) >> 2) \
1793 | (((TAG) & 0x7F00) >> 1) \
1794 | ((TAG) & 0x7F))
1796 /* Assuming that FONT is an OpenType font, apply OpenType features
1797 specified in SPEC on glyphs between FROM and TO of IN, and record
1798 the lastly applied feature in each glyph of IN. If OUT is not
1799 NULL, append the resulting glyphs to OUT while storing glyph
1800 position adjustment information in ADJUSTMENT. */
1802 static int
1803 ftfont_drive_otf (MFLTFont *font,
1804 MFLTOtfSpec *spec,
1805 MFLTGlyphString *in,
1806 int from,
1807 int to,
1808 MFLTGlyphString *out,
1809 MFLTGlyphAdjustment *adjustment)
1811 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1812 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
1813 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
1814 FT_Face ft_face = flt_font_ft->ft_face;
1815 OTF *otf = flt_font_ft->otf;
1816 int len = to - from;
1817 int i, j, gidx;
1818 OTF_Glyph *otfg;
1819 char script[5], *langsys = NULL;
1820 char *gsub_features = NULL, *gpos_features = NULL;
1821 OTF_Feature *features;
1823 if (len == 0)
1824 return from;
1825 OTF_tag_name (spec->script, script);
1827 char langsysbuf[5];
1828 if (spec->langsys)
1830 langsys = langsysbuf;
1831 OTF_tag_name (spec->langsys, langsys);
1834 USE_SAFE_ALLOCA;
1835 for (i = 0; i < 2; i++)
1837 char *p;
1839 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1841 for (j = 0; spec->features[i][j]; j++);
1842 SAFE_NALLOCA (p, 6, j);
1843 if (i == 0)
1844 gsub_features = p;
1845 else
1846 gpos_features = p;
1847 for (j = 0; spec->features[i][j]; j++)
1849 if (spec->features[i][j] == 0xFFFFFFFF)
1850 *p++ = '*', *p++ = ',';
1851 else
1853 OTF_tag_name (spec->features[i][j], p);
1854 p[4] = ',';
1855 p += 5;
1858 *--p = '\0';
1862 setup_otf_gstring (len);
1863 for (i = 0; i < len; i++)
1865 otf_gstring.glyphs[i].c = in_glyphs[i].g.c & 0x11FFFF;
1866 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
1867 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1868 otf_gstring.glyphs[i].positioning_type = in_glyphs[i].libotf_positioning_type;
1869 #endif
1872 OTF_drive_gdef (otf, &otf_gstring);
1873 gidx = out ? out->used : from;
1875 if (gsub_features && out)
1877 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1878 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1879 gsub_features) < 0)
1880 goto simple_copy;
1881 #else
1882 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1883 gsub_features) < 0)
1884 goto simple_copy;
1885 #endif
1886 if (out->allocated < out->used + otf_gstring.used)
1888 SAFE_FREE ();
1889 return -2;
1891 features = otf->gsub->FeatureList.Feature;
1892 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1894 MFLTGlyphFT *g;
1895 int min_from, max_to;
1896 int feature_idx;
1898 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1899 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1900 #else
1901 feature_idx = otfg->positioning_type >> 4;
1902 #endif
1903 g = out_glyphs + out->used;
1904 *g = in_glyphs[otfg->f.index.from];
1905 if (g->g.code != otfg->glyph_id)
1907 g->g.c = 0;
1908 g->g.code = otfg->glyph_id;
1909 g->g.measured = 0;
1911 out->used++;
1912 min_from = g->g.from;
1913 max_to = g->g.to;
1914 if (otfg->f.index.from < otfg->f.index.to)
1916 /* OTFG substitutes multiple glyphs in IN. */
1917 for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
1919 if (min_from > in_glyphs[j].g.from)
1920 min_from = in_glyphs[j].g.from;
1921 if (max_to < in_glyphs[j].g.to)
1922 max_to = in_glyphs[j].g.to;
1924 g->g.from = min_from;
1925 g->g.to = max_to;
1927 if (feature_idx)
1929 unsigned int tag = features[feature_idx - 1].FeatureTag;
1930 tag = PACK_OTF_TAG (tag);
1931 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1933 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1934 g->libotf_positioning_type
1935 = otfg->positioning_type & OTF_positioning_type_components_mask;
1936 #endif
1937 for (i++, otfg++; (i < otf_gstring.used
1938 && otfg->f.index.from == otfg[-1].f.index.from);
1939 i++, otfg++)
1941 g = out_glyphs + out->used;
1942 *g = in_glyphs[otfg->f.index.to];
1943 if (g->g.code != otfg->glyph_id)
1945 g->g.c = 0;
1946 g->g.code = otfg->glyph_id;
1947 g->g.measured = 0;
1949 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1950 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1951 #else
1952 feature_idx = otfg->positioning_type >> 4;
1953 #endif
1954 if (feature_idx)
1956 unsigned int tag = features[feature_idx - 1].FeatureTag;
1957 tag = PACK_OTF_TAG (tag);
1958 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1960 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1961 g->libotf_positioning_type
1962 = otfg->positioning_type & OTF_positioning_type_components_mask;
1963 #endif
1964 out->used++;
1968 else if (gsub_features)
1970 /* Just for checking which features will be applied. */
1971 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1972 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1973 gsub_features) < 0)
1974 goto simple_copy;
1975 #else
1976 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1977 gsub_features) < 0)
1978 goto simple_copy;
1979 #endif
1980 features = otf->gsub->FeatureList.Feature;
1981 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1982 otfg++)
1984 int feature_idx;
1985 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1986 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1987 #else
1988 feature_idx = otfg->positioning_type >> 4;
1989 #endif
1990 if (feature_idx)
1992 unsigned int tag = features[feature_idx - 1].FeatureTag;
1993 tag = PACK_OTF_TAG (tag);
1994 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1996 MFLTGlyphFT *g = in_glyphs + j;
1997 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2002 else if (out)
2004 if (out->allocated < out->used + len)
2006 SAFE_FREE ();
2007 return -2;
2009 for (i = 0; i < len; i++)
2010 out_glyphs[out->used++] = in_glyphs[i];
2013 if (gpos_features && out)
2015 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
2016 int x_ppem, y_ppem, x_scale, y_scale;
2018 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2019 if (OTF_drive_gpos_features (otf, &otf_gstring, script, langsys,
2020 gpos_features) < 0)
2022 SAFE_FREE ();
2023 return to;
2025 #else
2026 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2027 gpos_features) < 0)
2029 SAFE_FREE ();
2030 return to;
2032 #endif
2033 features = otf->gpos->FeatureList.Feature;
2034 x_ppem = ft_face->size->metrics.x_ppem;
2035 y_ppem = ft_face->size->metrics.y_ppem;
2036 x_scale = ft_face->size->metrics.x_scale;
2037 y_scale = ft_face->size->metrics.y_scale;
2039 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2040 i < otf_gstring.used; i++, otfg++)
2042 MFLTGlyphAdjustment *adjust = adjustment;
2043 MFLTGlyphFT *prev;
2044 int positioning_type, feature_idx;
2046 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2047 positioning_type = OTF_POSITIONING_TYPE_GET_FORMAT (otfg);
2048 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
2049 #else
2050 positioning_type = otfg->positioning_type & 0xF;
2051 feature_idx = otfg->positioning_type >> 4;
2052 #endif
2053 if (feature_idx)
2055 unsigned int tag = features[feature_idx - 1].FeatureTag;
2056 tag = PACK_OTF_TAG (tag);
2057 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2060 if (! otfg->glyph_id)
2061 /* This is a pseudo glyph that contains positioning
2062 information to be accumulated to a real glyph. */
2063 adjust--;
2064 switch (positioning_type)
2066 case 0:
2067 break;
2068 case 1: /* Single */
2069 case 2: /* Pair */
2071 int format = otfg->f.f1.format;
2073 if (format & OTF_XPlacement)
2074 adjust->xoff
2075 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2076 if (format & OTF_XPlaDevice)
2077 adjust->xoff
2078 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2079 if (format & OTF_YPlacement)
2080 adjust->yoff
2081 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2082 if (format & OTF_YPlaDevice)
2083 adjust->yoff
2084 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2085 if (format & OTF_XAdvance)
2086 adjust->xadv
2087 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2088 if (format & OTF_XAdvDevice)
2089 adjust->xadv
2090 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2091 if (format & OTF_YAdvance)
2092 adjust->yadv
2093 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2094 if (format & OTF_YAdvDevice)
2095 adjust->yadv
2096 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2097 adjust->set = 1;
2099 break;
2100 case 3: /* Cursive */
2101 /* Not yet supported. */
2102 break;
2103 case 4: /* Mark-to-Base */
2104 case 5: /* Mark-to-Ligature */
2105 if (! base)
2106 break;
2107 prev = base;
2108 goto label_adjust_anchor;
2109 default: /* i.e. case 6 Mark-to-Mark */
2110 if (! mark)
2111 break;
2112 prev = mark;
2113 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2115 int distance = OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg);
2117 if (distance > 0)
2119 prev = g - distance;
2120 if (prev < out_glyphs)
2121 prev = mark;
2124 #endif
2126 label_adjust_anchor:
2128 int base_x, base_y, mark_x, mark_y;
2129 int this_from, this_to;
2131 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2132 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2133 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2134 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2136 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2137 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2138 x_ppem, y_ppem, &base_x, &base_y);
2139 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2140 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2141 x_ppem, y_ppem, &mark_x, &mark_y);
2142 adjust->xoff = (base_x - mark_x);
2143 adjust->yoff = - (base_y - mark_y);
2144 adjust->back = (g - prev);
2145 adjust->xadv = 0;
2146 adjust->advance_is_absolute = 1;
2147 adjust->set = 1;
2148 this_from = g->g.from;
2149 this_to = g->g.to;
2150 for (j = 0; prev + j < g; j++)
2152 if (this_from > prev[j].g.from)
2153 this_from = prev[j].g.from;
2154 if (this_to < prev[j].g.to)
2155 this_to = prev[j].g.to;
2157 for (; prev <= g; prev++)
2159 prev->g.from = this_from;
2160 prev->g.to = this_to;
2164 if (otfg->glyph_id)
2166 if (otfg->GlyphClass == OTF_GlyphClass0)
2167 base = mark = g;
2168 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2169 mark = g;
2170 else
2171 base = g;
2172 g++, adjustment++;
2176 else if (gpos_features)
2178 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2179 gpos_features) < 0)
2181 SAFE_FREE ();
2182 return to;
2184 features = otf->gpos->FeatureList.Feature;
2185 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2186 i++, otfg++)
2187 if (otfg->positioning_type & 0xF)
2189 int feature_idx = otfg->positioning_type >> 4;
2191 if (feature_idx)
2193 unsigned int tag = features[feature_idx - 1].FeatureTag;
2194 tag = PACK_OTF_TAG (tag);
2195 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2197 MFLTGlyphFT *g = in_glyphs + j;
2198 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2203 SAFE_FREE ();
2204 return to;
2206 simple_copy:
2207 SAFE_FREE ();
2208 if (! out)
2209 return to;
2210 if (out->allocated < out->used + len)
2211 return -2;
2212 font->get_metrics (font, in, from, to);
2213 memcpy (out->glyphs + out->used, in_glyphs, sizeof (MFLTGlyphFT) * len);
2214 out->used += len;
2215 return to;
2218 static int
2219 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2220 MFLTGlyphString *in, int from, int to)
2222 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2225 #else /* not M17N_FLT_USE_NEW_FEATURE */
2227 static int
2228 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2229 int from, int to,
2230 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2232 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2233 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
2234 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
2235 FT_Face ft_face = flt_font_ft->ft_face;
2236 OTF *otf = flt_font_ft->otf;
2237 int len = to - from;
2238 int i, j, gidx;
2239 OTF_Glyph *otfg;
2240 char script[5], *langsys = NULL;
2241 char *gsub_features = NULL, *gpos_features = NULL;
2243 if (len == 0)
2244 return from;
2245 OTF_tag_name (spec->script, script);
2247 char langsysbuf[5];
2248 if (spec->langsys)
2250 langsys = langsysbuf;
2251 OTF_tag_name (spec->langsys, langsys);
2254 USE_SAFE_ALLOCA;
2255 for (i = 0; i < 2; i++)
2257 char *p;
2259 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2261 for (j = 0; spec->features[i][j]; j++);
2262 SAFE_NALLOCA (p, 6, j);
2263 if (i == 0)
2264 gsub_features = p;
2265 else
2266 gpos_features = p;
2267 for (j = 0; spec->features[i][j]; j++)
2269 if (spec->features[i][j] == 0xFFFFFFFF)
2270 *p++ = '*', *p++ = ',';
2271 else
2273 OTF_tag_name (spec->features[i][j], p);
2274 p[4] = ',';
2275 p += 5;
2278 *--p = '\0';
2282 setup_otf_gstring (len);
2283 for (i = 0; i < len; i++)
2285 otf_gstring.glyphs[i].c = in_glyphs[i].g.c;
2286 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
2289 OTF_drive_gdef (otf, &otf_gstring);
2290 gidx = out->used;
2292 if (gsub_features)
2294 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2295 < 0)
2296 goto simple_copy;
2297 if (out->allocated < out->used + otf_gstring.used)
2299 SAFE_FREE ();
2300 return -2;
2302 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2304 MFLTGlyphFT *g;
2305 int min_from, max_to;
2306 int j;
2308 g = out_glyphs + out->used;
2309 *g = in_glyphs[otfg->f.index.from];
2310 if (g->g.code != otfg->glyph_id)
2312 g->g.c = 0;
2313 g->g.code = otfg->glyph_id;
2314 g->g.measured = 0;
2316 out->used++;
2317 min_from = g->g.from;
2318 max_to = g->g.to;
2319 if (otfg->f.index.from < otfg->f.index.to)
2321 /* OTFG substitutes multiple glyphs in IN. */
2322 for (j = from + otfg->f.index.from + 1;
2323 j <= from + otfg->f.index.to; j++)
2325 if (min_from > in->glyphs[j].from)
2326 min_from = in->glyphs[j].from;
2327 if (max_to < in->glyphs[j].to)
2328 max_to = in->glyphs[j].to;
2330 g->g.from = min_from;
2331 g->g.to = max_to;
2333 for (i++, otfg++; (i < otf_gstring.used
2334 && otfg->f.index.from == otfg[-1].f.index.from);
2335 i++, otfg++)
2337 g = out_glyphs + out->used;
2338 *g = in_glyphs[otfg->f.index.to];
2339 if (g->g.code != otfg->glyph_id)
2341 g->g.c = 0;
2342 g->g.code = otfg->glyph_id;
2343 g->g.measured = 0;
2345 out->used++;
2349 else
2351 if (out->allocated < out->used + len)
2353 SAFE_FREE ();
2354 return -2;
2356 for (i = 0; i < len; i++)
2357 out_glyphs[out->used++] = in_glyphs[i];
2360 if (gpos_features)
2362 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
2363 int x_ppem, y_ppem, x_scale, y_scale;
2365 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2366 < 0)
2368 SAFE_FREE ();
2369 return to;
2372 x_ppem = ft_face->size->metrics.x_ppem;
2373 y_ppem = ft_face->size->metrics.y_ppem;
2374 x_scale = ft_face->size->metrics.x_scale;
2375 y_scale = ft_face->size->metrics.y_scale;
2377 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2378 i < otf_gstring.used; i++, otfg++, g++)
2380 MFLTGlyphFT *prev;
2382 if (! otfg->glyph_id)
2383 continue;
2384 switch (otfg->positioning_type)
2386 case 0:
2387 break;
2388 case 1: /* Single */
2389 case 2: /* Pair */
2391 int format = otfg->f.f1.format;
2393 if (format & OTF_XPlacement)
2394 adjustment[i].xoff
2395 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2396 if (format & OTF_XPlaDevice)
2397 adjustment[i].xoff
2398 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2399 if (format & OTF_YPlacement)
2400 adjustment[i].yoff
2401 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2402 if (format & OTF_YPlaDevice)
2403 adjustment[i].yoff
2404 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2405 if (format & OTF_XAdvance)
2406 adjustment[i].xadv
2407 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2408 if (format & OTF_XAdvDevice)
2409 adjustment[i].xadv
2410 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2411 if (format & OTF_YAdvance)
2412 adjustment[i].yadv
2413 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2414 if (format & OTF_YAdvDevice)
2415 adjustment[i].yadv
2416 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2417 adjustment[i].set = 1;
2419 break;
2420 case 3: /* Cursive */
2421 /* Not yet supported. */
2422 break;
2423 case 4: /* Mark-to-Base */
2424 case 5: /* Mark-to-Ligature */
2425 if (! base)
2426 break;
2427 prev = base;
2428 goto label_adjust_anchor;
2429 default: /* i.e. case 6 Mark-to-Mark */
2430 if (! mark)
2431 break;
2432 prev = mark;
2434 label_adjust_anchor:
2436 int base_x, base_y, mark_x, mark_y;
2437 int this_from, this_to;
2439 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2440 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2441 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2442 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2444 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2445 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2446 x_ppem, y_ppem, &base_x, &base_y);
2447 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2448 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2449 x_ppem, y_ppem, &mark_x, &mark_y);
2450 adjustment[i].xoff = (base_x - mark_x);
2451 adjustment[i].yoff = - (base_y - mark_y);
2452 adjustment[i].back = (g - prev);
2453 adjustment[i].xadv = 0;
2454 adjustment[i].advance_is_absolute = 1;
2455 adjustment[i].set = 1;
2456 this_from = g->g.from;
2457 this_to = g->g.to;
2458 for (j = 0; prev + j < g; j++)
2460 if (this_from > prev[j].g.from)
2461 this_from = prev[j].g.from;
2462 if (this_to < prev[j].g.to)
2463 this_to = prev[j].g.to;
2465 for (; prev <= g; prev++)
2467 prev->g.from = this_from;
2468 prev->g.to = this_to;
2472 if (otfg->GlyphClass == OTF_GlyphClass0)
2473 base = mark = g;
2474 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2475 mark = g;
2476 else
2477 base = g;
2480 SAFE_FREE ();
2481 return to;
2483 simple_copy:
2484 SAFE_FREE ();
2485 if (out->allocated < out->used + len)
2486 return -2;
2487 font->get_metrics (font, in, from, to);
2488 memcpy (out_glyphs + out->used, in_glyphs,
2489 sizeof (MFLTGlyphFT) * len);
2490 out->used += len;
2491 return to;
2494 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2496 static MFLTGlyphString gstring;
2498 static bool m17n_flt_initialized;
2500 static Lisp_Object
2501 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2502 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2504 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2505 ptrdiff_t i;
2506 struct MFLTFontFT flt_font_ft;
2507 MFLT *flt = NULL;
2508 bool with_variation_selector = 0;
2509 MFLTGlyphFT *glyphs;
2511 if (! m17n_flt_initialized)
2513 M17N_INIT ();
2514 #ifdef M17N_FLT_USE_NEW_FEATURE
2515 mflt_enable_new_feature = 1;
2516 mflt_try_otf = ftfont_try_otf;
2517 #endif /* M17N_FLT_USE_NEW_FEATURE */
2518 m17n_flt_initialized = 1;
2521 for (i = 0; i < len; i++)
2523 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2524 int c;
2526 if (NILP (g))
2527 break;
2528 c = LGLYPH_CHAR (g);
2529 if (CHAR_VARIATION_SELECTOR_P (c))
2530 with_variation_selector = 1;
2533 len = i;
2535 if (with_variation_selector)
2537 setup_otf_gstring (len);
2538 for (i = 0; i < len; i++)
2540 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2542 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2543 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2544 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2546 OTF_drive_cmap (otf, &otf_gstring);
2547 for (i = 0; i < otf_gstring.used; i++)
2549 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2550 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2551 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2553 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2554 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2555 LGSTRING_SET_GLYPH (lgstring, i, g0);
2557 if (len > otf_gstring.used)
2559 len = otf_gstring.used;
2560 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2564 if (INT_MAX / 2 < len)
2565 memory_full (SIZE_MAX);
2567 if (gstring.allocated == 0)
2569 gstring.glyph_size = sizeof (MFLTGlyphFT);
2570 gstring.glyphs = xnmalloc (len * 2, sizeof (MFLTGlyphFT));
2571 gstring.allocated = len * 2;
2573 else if (gstring.allocated < len * 2)
2575 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2,
2576 sizeof (MFLTGlyphFT));
2577 gstring.allocated = len * 2;
2579 glyphs = (MFLTGlyphFT *) (gstring.glyphs);
2580 memset (glyphs, 0, len * sizeof (MFLTGlyphFT));
2581 for (i = 0; i < len; i++)
2583 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2585 glyphs[i].g.c = LGLYPH_CHAR (g);
2586 if (with_variation_selector)
2588 glyphs[i].g.code = LGLYPH_CODE (g);
2589 glyphs[i].g.encoded = 1;
2593 gstring.used = len;
2594 gstring.r2l = 0;
2597 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2599 if (NILP (family))
2600 flt_font_ft.flt_font.family = Mnil;
2601 else
2602 flt_font_ft.flt_font.family
2603 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2605 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2606 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2607 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2608 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2609 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2610 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2611 flt_font_ft.flt_font.internal = NULL;
2612 flt_font_ft.font = font;
2613 flt_font_ft.ft_face = ft_face;
2614 flt_font_ft.otf = otf;
2615 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2616 if (len > 1
2617 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2618 /* A little bit ad hoc. Perhaps, shaper must get script and
2619 language information, and select a proper flt for them
2620 here. */
2621 flt = mflt_get (msymbol ("combining"));
2622 for (i = 0; i < 3; i++)
2624 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2625 if (result != -2)
2626 break;
2627 if (INT_MAX / 2 < gstring.allocated)
2628 memory_full (SIZE_MAX);
2629 gstring.glyphs = xnrealloc (gstring.glyphs,
2630 gstring.allocated, 2 * sizeof (MFLTGlyphFT));
2631 gstring.allocated *= 2;
2633 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2634 return Qnil;
2635 for (i = 0; i < gstring.used; i++)
2637 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2639 g->g.from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->g.from));
2640 g->g.to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->g.to));
2643 for (i = 0; i < gstring.used; i++)
2645 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2646 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2648 if (NILP (lglyph))
2650 lglyph = LGLYPH_NEW ();
2651 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2653 LGLYPH_SET_FROM (lglyph, g->g.from);
2654 LGLYPH_SET_TO (lglyph, g->g.to);
2655 LGLYPH_SET_CHAR (lglyph, g->g.c);
2656 LGLYPH_SET_CODE (lglyph, g->g.code);
2657 LGLYPH_SET_WIDTH (lglyph, g->g.xadv >> 6);
2658 LGLYPH_SET_LBEARING (lglyph, g->g.lbearing >> 6);
2659 LGLYPH_SET_RBEARING (lglyph, g->g.rbearing >> 6);
2660 LGLYPH_SET_ASCENT (lglyph, g->g.ascent >> 6);
2661 LGLYPH_SET_DESCENT (lglyph, g->g.descent >> 6);
2662 if (g->g.adjusted)
2664 Lisp_Object vec = make_uninit_vector (3);
2666 ASET (vec, 0, make_number (g->g.xoff >> 6));
2667 ASET (vec, 1, make_number (g->g.yoff >> 6));
2668 ASET (vec, 2, make_number (g->g.xadv >> 6));
2669 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2672 return make_number (i);
2675 Lisp_Object
2676 ftfont_shape (Lisp_Object lgstring)
2678 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2679 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2680 OTF *otf = ftfont_get_otf (ftfont_info);
2682 if (! otf)
2683 return make_number (0);
2684 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2685 &ftfont_info->matrix);
2688 #endif /* HAVE_M17N_FLT */
2690 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2692 static int
2693 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2695 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2696 OTF *otf = ftfont_get_otf (ftfont_info);
2698 if (! otf)
2699 return 0;
2700 return OTF_get_variation_glyphs (otf, c, variations);
2703 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2704 #endif /* HAVE_LIBOTF */
2706 static const char *const ftfont_booleans [] = {
2707 ":antialias",
2708 ":hinting",
2709 ":verticallayout",
2710 ":autohint",
2711 ":globaladvance",
2712 ":outline",
2713 ":scalable",
2714 ":minspace",
2715 ":embolden",
2716 NULL,
2719 static const char *const ftfont_non_booleans [] = {
2720 ":family",
2721 ":familylang",
2722 ":style",
2723 ":stylelang",
2724 ":fullname",
2725 ":fullnamelang",
2726 ":slant",
2727 ":weight",
2728 ":size",
2729 ":width",
2730 ":aspect",
2731 ":pixelsize",
2732 ":spacing",
2733 ":foundry",
2734 ":hintstyle",
2735 ":file",
2736 ":index",
2737 ":ftface",
2738 ":rasterizer",
2739 ":scale",
2740 ":dpi",
2741 ":rgba",
2742 ":lcdfilter",
2743 ":charset",
2744 ":lang",
2745 ":fontversion",
2746 ":capability",
2747 NULL,
2750 static void
2751 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2753 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2757 void
2758 syms_of_ftfont (void)
2760 /* Symbolic type of this font-driver. */
2761 DEFSYM (Qfreetype, "freetype");
2763 /* Fontconfig's generic families and their aliases. */
2764 DEFSYM (Qmonospace, "monospace");
2765 DEFSYM (Qsans_serif, "sans-serif");
2766 DEFSYM (Qsans, "sans");
2767 DEFSYM (Qsans__serif, "sans serif");
2769 staticpro (&freetype_font_cache);
2770 freetype_font_cache = list1 (Qt);
2772 staticpro (&ftfont_generic_family_list);
2773 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2774 Fcons (Qsans_serif, Qt),
2775 Fcons (Qsans, Qt));
2777 staticpro (&ft_face_cache);
2778 ft_face_cache = Qnil;
2780 ftfont_driver.type = Qfreetype;
2781 register_font_driver (&ftfont_driver, NULL);