Use save-excursion in xref-location-marker more
[emacs.git] / src / ftfont.c
blob7285aee9bd4129a4a84f4f8643ec89b633674768
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2016 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 <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 "category.h"
34 #include "composite.h"
35 #include "font.h"
36 #include "ftfont.h"
38 /* Flag to tell if FcInit is already called or not. */
39 static bool fc_initialized;
41 /* Handle to a FreeType library instance. */
42 static FT_Library ft_library;
44 /* Cache for FreeType fonts. */
45 static Lisp_Object freetype_font_cache;
47 /* Cache for FT_Face and FcCharSet. */
48 static Lisp_Object ft_face_cache;
50 /* The actual structure for FreeType font that can be cast to struct
51 font. */
53 struct ftfont_info
55 struct font font;
56 #ifdef HAVE_LIBOTF
57 /* The following four members must be here in this order to be
58 compatible with struct xftfont_info (in xftfont.c). */
59 bool maybe_otf; /* Flag to tell if this may be OTF or not. */
60 OTF *otf;
61 #endif /* HAVE_LIBOTF */
62 FT_Size ft_size;
63 int index;
64 FT_Matrix matrix;
67 size_t ftfont_info_size = sizeof (struct ftfont_info);
69 enum ftfont_cache_for
71 FTFONT_CACHE_FOR_FACE,
72 FTFONT_CACHE_FOR_CHARSET,
73 FTFONT_CACHE_FOR_ENTITY
76 static Lisp_Object ftfont_pattern_entity (FcPattern *, Lisp_Object);
78 static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
79 FcPattern *);
80 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
81 enum ftfont_cache_for);
83 static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
85 static Lisp_Object ftfont_combining_capability (struct font *);
87 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
89 static struct
91 /* registry name */
92 const char *name;
93 /* characters to distinguish the charset from the others */
94 int uniquifier[6];
95 /* additional constraint by language */
96 const char *lang;
97 /* set on demand */
98 FcCharSet *fc_charset;
99 } fc_charset_table[] =
100 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
101 { "iso8859-2", { 0x00A0, 0x010E }},
102 { "iso8859-3", { 0x00A0, 0x0108 }},
103 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
104 { "iso8859-5", { 0x00A0, 0x0401 }},
105 { "iso8859-6", { 0x00A0, 0x060C }},
106 { "iso8859-7", { 0x00A0, 0x0384 }},
107 { "iso8859-8", { 0x00A0, 0x05D0 }},
108 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
109 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
110 { "iso8859-11", { 0x00A0, 0x0E01 }},
111 { "iso8859-13", { 0x00A0, 0x201C }},
112 { "iso8859-14", { 0x00A0, 0x0174 }},
113 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
114 { "iso8859-16", { 0x00A0, 0x0218}},
115 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
116 { "big5-0", { 0xF6B1 }, "zh-tw" },
117 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
118 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
119 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
120 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
121 { "cns11643.1992-3", { 0x201A9 }},
122 { "cns11643.1992-4", { 0x20057 }},
123 { "cns11643.1992-5", { 0x20000 }},
124 { "cns11643.1992-6", { 0x20003 }},
125 { "cns11643.1992-7", { 0x20055 }},
126 { "gbk-0", { 0x4E06 }, "zh-cn"},
127 { "jisx0212.1990-0", { 0x4E44 }},
128 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
129 { "jisx0213.2000-2", { 0xFA49 }},
130 { "jisx0213.2004-1", { 0x20B9F }},
131 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
132 { "tis620.2529-1", { 0x0E01 }, "th"},
133 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
134 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
135 { "mulelao-1", { 0x0E81 }, "lo"},
136 { "unicode-sip", { 0x20000 }},
137 { NULL }
140 static bool
141 matching_prefix (char const *str, ptrdiff_t len, char const *pat)
143 return len == strlen (pat) && c_strncasecmp (str, pat, len) == 0;
146 /* Dirty hack for handing ADSTYLE property.
148 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
149 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
150 "Oblique", "Italic", or any non-normal SWIDTH property names
151 (e.g. SemiCondensed) are appended. In addition, if there's no
152 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
153 "Regular" is used for FC_STYLE (see the function
154 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
156 Unfortunately this behavior is not documented, so the following
157 code may fail if FreeType changes the behavior in the future. */
159 static Lisp_Object
160 get_adstyle_property (FcPattern *p)
162 FcChar8 *fcstr;
163 char *str, *end;
164 Lisp_Object adstyle;
166 #ifdef FC_FONTFORMAT
167 if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
168 && xstrcasecmp ((char *) fcstr, "bdf") != 0
169 && xstrcasecmp ((char *) fcstr, "pcf") != 0)
170 /* Not a BDF nor PCF font. */
171 return Qnil;
172 #endif
173 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
174 return Qnil;
175 str = (char *) fcstr;
176 for (end = str; *end && *end != ' '; end++);
177 if (matching_prefix (str, end - str, "Regular")
178 || matching_prefix (str, end - str, "Bold")
179 || matching_prefix (str, end - str, "Oblique")
180 || matching_prefix (str, end - str, "Italic"))
181 return Qnil;
182 adstyle = font_intern_prop (str, end - str, 1);
183 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
184 return Qnil;
185 return adstyle;
188 static Lisp_Object
189 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
191 Lisp_Object key, cache, entity;
192 FcChar8 *str;
193 char *file;
194 int idx;
195 int numeric;
196 double dbl;
197 FcBool b;
199 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
200 return Qnil;
201 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
202 return Qnil;
204 file = (char *) str;
205 key = Fcons (build_unibyte_string (file), make_number (idx));
206 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
207 entity = XCAR (cache);
208 if (! NILP (entity))
210 Lisp_Object val = font_make_entity ();
211 int i;
213 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
214 ASET (val, i, AREF (entity, i));
216 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
217 font_put_extra (val, QCfont_entity, key);
219 return val;
221 entity = font_make_entity ();
222 XSETCAR (cache, entity);
224 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
225 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
227 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
229 char *s = (char *) str;
230 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
232 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
234 char *s = (char *) str;
235 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
237 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
239 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
240 numeric = FC_WEIGHT_MEDIUM;
241 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
243 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
245 numeric += 100;
246 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
248 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
250 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
252 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
254 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
256 else
257 ASET (entity, FONT_SIZE_INDEX, make_number (0));
258 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
259 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
260 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
262 int dpi = dbl;
263 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
265 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
266 && b == FcTrue)
268 ASET (entity, FONT_SIZE_INDEX, make_number (0));
269 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
271 else
273 /* As this font is not scalable, perhaps this is a BDF or PCF
274 font. */
275 FT_Face ft_face;
277 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
278 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
279 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
281 BDF_PropertyRec rec;
283 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
284 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
285 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
286 FT_Done_Face (ft_face);
290 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
291 font_put_extra (entity, QCfont_entity, key);
292 return entity;
296 static Lisp_Object ftfont_generic_family_list;
298 static Lisp_Object
299 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
301 Lisp_Object slot;
302 FcPattern *match;
303 FcResult result;
304 FcLangSet *langset;
306 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
307 if (EQ (family, Qmono))
308 family = Qmonospace;
309 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
310 family = Qsans_serif;
311 slot = assq_no_quit (family, ftfont_generic_family_list);
312 if (! CONSP (slot))
313 return Qnil;
314 if (! EQ (XCDR (slot), Qt))
315 return XCDR (slot);
316 pattern = FcPatternDuplicate (pattern);
317 if (! pattern)
318 goto err;
319 FcPatternDel (pattern, FC_FOUNDRY);
320 FcPatternDel (pattern, FC_FAMILY);
321 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
322 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
324 /* This is to avoid the effect of locale. */
325 static const FcChar8 lang[] = "en";
326 langset = FcLangSetCreate ();
327 FcLangSetAdd (langset, lang);
328 FcPatternAddLangSet (pattern, FC_LANG, langset);
329 FcLangSetDestroy (langset);
331 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
332 FcDefaultSubstitute (pattern);
333 match = FcFontMatch (NULL, pattern, &result);
334 if (match)
336 FcChar8 *fam;
338 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
339 family = intern ((char *) fam);
341 else
342 family = Qnil;
343 XSETCDR (slot, family);
344 if (match) FcPatternDestroy (match);
345 err:
346 if (pattern) FcPatternDestroy (pattern);
347 return family;
350 struct ftfont_cache_data
352 FT_Face ft_face;
353 FcCharSet *fc_charset;
356 static Lisp_Object
357 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
359 Lisp_Object cache, val, entity;
360 struct ftfont_cache_data *cache_data;
362 if (FONT_ENTITY_P (key))
364 entity = key;
365 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
366 eassert (CONSP (val));
367 key = XCDR (val);
369 else
370 entity = Qnil;
372 if (NILP (ft_face_cache))
373 cache = Qnil;
374 else
375 cache = Fgethash (key, ft_face_cache, Qnil);
376 if (NILP (cache))
378 if (NILP (ft_face_cache))
379 ft_face_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
380 cache_data = xmalloc (sizeof *cache_data);
381 cache_data->ft_face = NULL;
382 cache_data->fc_charset = NULL;
383 val = make_save_ptr_int (cache_data, 0);
384 cache = Fcons (Qnil, val);
385 Fputhash (key, cache, ft_face_cache);
387 else
389 val = XCDR (cache);
390 cache_data = XSAVE_POINTER (val, 0);
393 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
394 return cache;
396 if (cache_for == FTFONT_CACHE_FOR_FACE
397 ? ! cache_data->ft_face : ! cache_data->fc_charset)
399 char *filename = SSDATA (XCAR (key));
400 int idx = XINT (XCDR (key));
402 if (cache_for == FTFONT_CACHE_FOR_FACE)
404 if (! ft_library
405 && FT_Init_FreeType (&ft_library) != 0)
406 return Qnil;
407 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
408 != 0)
409 return Qnil;
411 else
413 FcPattern *pat = NULL;
414 FcFontSet *fontset = NULL;
415 FcObjectSet *objset = NULL;
416 FcCharSet *charset = NULL;
418 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
419 FC_INDEX, FcTypeInteger, idx, NULL);
420 if (! pat)
421 goto finish;
422 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
423 if (! objset)
424 goto finish;
425 fontset = FcFontList (NULL, pat, objset);
426 if (! fontset)
427 goto finish;
428 if (fontset && fontset->nfont > 0
429 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
430 &charset)
431 == FcResultMatch))
432 cache_data->fc_charset = FcCharSetCopy (charset);
433 else
434 cache_data->fc_charset = FcCharSetCreate ();
436 finish:
437 if (fontset)
438 FcFontSetDestroy (fontset);
439 if (objset)
440 FcObjectSetDestroy (objset);
441 if (pat)
442 FcPatternDestroy (pat);
445 return cache;
448 FcCharSet *
449 ftfont_get_fc_charset (Lisp_Object entity)
451 Lisp_Object val, cache;
452 struct ftfont_cache_data *cache_data;
454 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
455 val = XCDR (cache);
456 cache_data = XSAVE_POINTER (val, 0);
457 return cache_data->fc_charset;
460 #ifdef HAVE_LIBOTF
461 static OTF *
462 ftfont_get_otf (struct ftfont_info *ftfont_info)
464 OTF *otf;
466 if (ftfont_info->otf)
467 return ftfont_info->otf;
468 if (! ftfont_info->maybe_otf)
469 return NULL;
470 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
471 if (! otf || OTF_get_table (otf, "head") < 0)
473 if (otf)
474 OTF_close (otf);
475 ftfont_info->maybe_otf = 0;
476 return NULL;
478 ftfont_info->otf = otf;
479 return otf;
481 #endif /* HAVE_LIBOTF */
483 static Lisp_Object ftfont_get_cache (struct frame *);
484 static Lisp_Object ftfont_list (struct frame *, Lisp_Object);
485 static Lisp_Object ftfont_match (struct frame *, Lisp_Object);
486 static Lisp_Object ftfont_list_family (struct frame *);
487 static Lisp_Object ftfont_open (struct frame *, Lisp_Object, int);
488 static void ftfont_close (struct font *);
489 static int ftfont_has_char (Lisp_Object, int);
490 static unsigned ftfont_encode_char (struct font *, int);
491 static void ftfont_text_extents (struct font *, unsigned *, int,
492 struct font_metrics *);
493 static int ftfont_get_bitmap (struct font *, unsigned,
494 struct font_bitmap *, int);
495 static int ftfont_anchor_point (struct font *, unsigned, int,
496 int *, int *);
497 #ifdef HAVE_LIBOTF
498 static Lisp_Object ftfont_otf_capability (struct font *);
499 # ifdef HAVE_M17N_FLT
500 static Lisp_Object ftfont_shape (Lisp_Object);
501 # endif
502 #endif
504 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
505 static int ftfont_variation_glyphs (struct font *, int c,
506 unsigned variations[256]);
507 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
509 struct font_driver ftfont_driver =
511 LISP_INITIALLY_ZERO, /* Qfreetype */
512 0, /* case insensitive */
513 ftfont_get_cache,
514 ftfont_list,
515 ftfont_match,
516 ftfont_list_family,
517 NULL, /* free_entity */
518 ftfont_open,
519 ftfont_close,
520 /* We can't draw a text without device dependent functions. */
521 NULL, /* prepare_face */
522 NULL, /* done_face */
523 ftfont_has_char,
524 ftfont_encode_char,
525 ftfont_text_extents,
526 /* We can't draw a text without device dependent functions. */
527 NULL, /* draw */
528 ftfont_get_bitmap,
529 NULL, /* free_bitmap */
530 ftfont_anchor_point,
531 #ifdef HAVE_LIBOTF
532 ftfont_otf_capability,
533 #else /* not HAVE_LIBOTF */
534 NULL,
535 #endif /* not HAVE_LIBOTF */
536 NULL, /* otf_drive */
537 NULL, /* start_for_frame */
538 NULL, /* end_for_frame */
539 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
540 ftfont_shape,
541 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
542 NULL,
543 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
544 NULL, /* check */
546 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
547 ftfont_variation_glyphs,
548 #else
549 NULL,
550 #endif
552 ftfont_filter_properties, /* filter_properties */
554 NULL, /* cached_font_ok */
556 ftfont_combining_capability,
559 static Lisp_Object
560 ftfont_get_cache (struct frame *f)
562 return freetype_font_cache;
565 static int
566 ftfont_get_charset (Lisp_Object registry)
568 char *str = SSDATA (SYMBOL_NAME (registry));
569 USE_SAFE_ALLOCA;
570 char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
571 Lisp_Object regexp;
572 int i, j;
574 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
576 if (str[i] == '.')
577 re[j++] = '\\';
578 else if (str[i] == '*')
579 re[j++] = '.';
580 re[j] = str[i];
581 if (re[j] == '?')
582 re[j] = '.';
584 re[j] = '\0';
585 regexp = make_unibyte_string (re, j);
586 SAFE_FREE ();
587 for (i = 0; fc_charset_table[i].name; i++)
588 if (fast_c_string_match_ignore_case
589 (regexp, fc_charset_table[i].name,
590 strlen (fc_charset_table[i].name)) >= 0)
591 break;
592 if (! fc_charset_table[i].name)
593 return -1;
594 if (! fc_charset_table[i].fc_charset)
596 FcCharSet *charset = FcCharSetCreate ();
597 int *uniquifier = fc_charset_table[i].uniquifier;
599 if (! charset)
600 return -1;
601 for (j = 0; uniquifier[j]; j++)
602 if (! FcCharSetAddChar (charset, uniquifier[j]))
604 FcCharSetDestroy (charset);
605 return -1;
607 fc_charset_table[i].fc_charset = charset;
609 return i;
612 struct OpenTypeSpec
614 Lisp_Object script;
615 unsigned int script_tag, langsys_tag;
616 int nfeatures[2];
617 unsigned int *features[2];
620 #define OTF_SYM_TAG(SYM, TAG) \
621 do { \
622 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
623 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
624 } while (0)
626 #define OTF_TAG_STR(TAG, P) \
627 do { \
628 (P)[0] = (char) (TAG >> 24); \
629 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
630 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
631 (P)[3] = (char) (TAG & 0xFF); \
632 (P)[4] = '\0'; \
633 } while (0)
635 #ifdef HAVE_LIBOTF
636 #define OTF_TAG_SYM(SYM, TAG) \
637 do { \
638 char str[5]; \
640 OTF_TAG_STR (TAG, str); \
641 (SYM) = font_intern_prop (str, 4, 1); \
642 } while (0)
643 #endif
646 static struct OpenTypeSpec *
647 ftfont_get_open_type_spec (Lisp_Object otf_spec)
649 struct OpenTypeSpec *spec = malloc (sizeof *spec);
650 Lisp_Object val;
651 int i, j;
652 bool negative;
654 if (! spec)
655 return NULL;
656 spec->script = XCAR (otf_spec);
657 if (! NILP (spec->script))
659 OTF_SYM_TAG (spec->script, spec->script_tag);
660 val = assq_no_quit (spec->script, Votf_script_alist);
661 if (CONSP (val) && SYMBOLP (XCDR (val)))
662 spec->script = XCDR (val);
663 else
664 spec->script = Qnil;
666 else
667 spec->script_tag = 0x44464C54; /* "DFLT" */
668 otf_spec = XCDR (otf_spec);
669 spec->langsys_tag = 0;
670 if (! NILP (otf_spec))
672 val = XCAR (otf_spec);
673 if (! NILP (val))
674 OTF_SYM_TAG (val, spec->langsys_tag);
675 otf_spec = XCDR (otf_spec);
677 spec->nfeatures[0] = spec->nfeatures[1] = 0;
678 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
680 Lisp_Object len;
682 val = XCAR (otf_spec);
683 if (NILP (val))
684 continue;
685 len = Flength (val);
686 spec->features[i] =
687 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
689 : malloc (XINT (len) * sizeof *spec->features[i]));
690 if (! spec->features[i])
692 if (i > 0 && spec->features[0])
693 free (spec->features[0]);
694 free (spec);
695 return NULL;
697 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
699 if (NILP (XCAR (val)))
700 negative = 1;
701 else
703 unsigned int tag;
705 OTF_SYM_TAG (XCAR (val), tag);
706 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
709 spec->nfeatures[i] = j;
711 return spec;
714 static FcPattern *
715 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
717 Lisp_Object tmp, extra;
718 FcPattern *pattern = NULL;
719 FcCharSet *charset = NULL;
720 FcLangSet *langset = NULL;
721 int n;
722 int dpi = -1;
723 int scalable = -1;
724 Lisp_Object script = Qnil;
725 Lisp_Object registry;
726 int fc_charset_idx;
728 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
729 && n < 100)
730 /* Fontconfig doesn't support reverse-italic/oblique. */
731 return NULL;
733 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
734 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
735 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
736 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
737 scalable = 1;
739 registry = AREF (spec, FONT_REGISTRY_INDEX);
740 if (NILP (registry)
741 || EQ (registry, Qascii_0)
742 || EQ (registry, Qiso10646_1)
743 || EQ (registry, Qunicode_bmp))
744 fc_charset_idx = -1;
745 else
747 FcChar8 *lang;
749 fc_charset_idx = ftfont_get_charset (registry);
750 if (fc_charset_idx < 0)
751 return NULL;
752 charset = fc_charset_table[fc_charset_idx].fc_charset;
753 *langname = fc_charset_table[fc_charset_idx].lang;
754 lang = (FcChar8 *) *langname;
755 if (lang)
757 langset = FcLangSetCreate ();
758 if (! langset)
759 goto err;
760 FcLangSetAdd (langset, lang);
764 otlayout[0] = '\0';
765 for (extra = AREF (spec, FONT_EXTRA_INDEX);
766 CONSP (extra); extra = XCDR (extra))
768 Lisp_Object key, val;
770 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
771 if (EQ (key, QCdpi))
773 if (INTEGERP (val))
774 dpi = XINT (val);
776 else if (EQ (key, QClang))
778 if (! langset)
779 langset = FcLangSetCreate ();
780 if (! langset)
781 goto err;
782 if (SYMBOLP (val))
784 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
785 goto err;
787 else
788 for (; CONSP (val); val = XCDR (val))
789 if (SYMBOLP (XCAR (val))
790 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
791 goto err;
793 else if (EQ (key, QCotf))
795 if (CONSP (val))
797 *otspec = ftfont_get_open_type_spec (val);
798 if (! *otspec)
799 return NULL;
800 strcpy (otlayout, "otlayout:");
801 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
802 script = (*otspec)->script;
805 else if (EQ (key, QCscript))
806 script = val;
807 else if (EQ (key, QCscalable))
808 scalable = ! NILP (val);
811 if (! NILP (script) && ! charset)
813 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
815 if (CONSP (chars) && CONSP (CDR (chars)))
817 charset = FcCharSetCreate ();
818 if (! charset)
819 goto err;
820 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
821 if (CHARACTERP (XCAR (chars))
822 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
823 goto err;
827 pattern = FcPatternCreate ();
828 if (! pattern)
829 goto err;
830 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
831 if (! NILP (tmp)
832 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
833 goto err;
834 tmp = AREF (spec, FONT_FAMILY_INDEX);
835 if (! NILP (tmp)
836 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
837 goto err;
838 if (charset
839 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
840 goto err;
841 if (langset
842 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
843 goto err;
844 if (dpi >= 0
845 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
846 goto err;
847 if (scalable >= 0
848 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
849 goto err;
851 goto finish;
853 err:
854 /* We come here because of unexpected error in fontconfig API call
855 (usually insufficient memory). */
856 if (pattern)
858 FcPatternDestroy (pattern);
859 pattern = NULL;
861 if (*otspec)
863 if ((*otspec)->nfeatures[0] > 0)
864 free ((*otspec)->features[0]);
865 if ((*otspec)->nfeatures[1] > 0)
866 free ((*otspec)->features[1]);
867 free (*otspec);
868 *otspec = NULL;
871 finish:
872 if (langset) FcLangSetDestroy (langset);
873 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
874 return pattern;
877 static Lisp_Object
878 ftfont_list (struct frame *f, Lisp_Object spec)
880 Lisp_Object val = Qnil, family, adstyle;
881 int i;
882 FcPattern *pattern;
883 FcFontSet *fontset = NULL;
884 FcObjectSet *objset = NULL;
885 FcCharSet *charset;
886 Lisp_Object chars = Qnil;
887 char otlayout[15]; /* For "otlayout:XXXX" */
888 struct OpenTypeSpec *otspec = NULL;
889 int spacing = -1;
890 const char *langname = NULL;
892 if (! fc_initialized)
894 FcInit ();
895 fc_initialized = 1;
898 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
899 if (! pattern)
900 return Qnil;
901 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
903 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
904 if (! NILP (val))
906 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
907 if (CONSP (val) && VECTORP (XCDR (val)))
908 chars = XCDR (val);
910 val = Qnil;
912 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
913 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
914 family = AREF (spec, FONT_FAMILY_INDEX);
915 if (! NILP (family))
917 Lisp_Object resolved;
919 resolved = ftfont_resolve_generic_family (family, pattern);
920 if (! NILP (resolved))
922 FcPatternDel (pattern, FC_FAMILY);
923 if (! FcPatternAddString (pattern, FC_FAMILY,
924 SYMBOL_FcChar8 (resolved)))
925 goto err;
928 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
929 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
930 adstyle = Qnil;
931 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
932 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
933 FC_STYLE, FC_FILE, FC_INDEX,
934 #ifdef FC_CAPABILITY
935 FC_CAPABILITY,
936 #endif /* FC_CAPABILITY */
937 #ifdef FC_FONTFORMAT
938 FC_FONTFORMAT,
939 #endif
940 NULL);
941 if (! objset)
942 goto err;
943 if (! NILP (chars))
944 FcObjectSetAdd (objset, FC_CHARSET);
946 fontset = FcFontList (NULL, pattern, objset);
947 if (! fontset || fontset->nfont == 0)
948 goto finish;
949 #if 0
950 /* Need fix because this finds any fonts. */
951 if (fontset->nfont == 0 && ! NILP (family))
953 /* Try matching with configuration. For instance, the
954 configuration may specify "Nimbus Mono L" as an alias of
955 "Courier". */
956 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
957 SYMBOL_FcChar8 (family), NULL);
958 FcChar8 *fam;
960 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
962 for (i = 0;
963 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
964 i++)
966 FcPatternDel (pattern, FC_FAMILY);
967 FcPatternAddString (pattern, FC_FAMILY, fam);
968 FcFontSetDestroy (fontset);
969 fontset = FcFontList (NULL, pattern, objset);
970 if (fontset && fontset->nfont > 0)
971 break;
975 #endif
976 for (i = 0; i < fontset->nfont; i++)
978 Lisp_Object entity;
980 if (spacing >= 0)
982 int this;
984 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
985 == FcResultMatch)
986 && spacing != this)
987 continue;
990 #ifdef FC_CAPABILITY
991 if (otlayout[0])
993 FcChar8 *this;
995 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
996 != FcResultMatch
997 || ! strstr ((char *) this, otlayout))
998 continue;
1000 #endif /* FC_CAPABILITY */
1001 #ifdef HAVE_LIBOTF
1002 if (otspec)
1004 FcChar8 *file;
1005 bool passed;
1006 OTF *otf;
1008 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1009 != FcResultMatch)
1010 continue;
1011 otf = OTF_open ((char *) file);
1012 if (! otf)
1013 continue;
1014 passed = (OTF_check_features (otf, 1, otspec->script_tag,
1015 otspec->langsys_tag,
1016 otspec->features[0],
1017 otspec->nfeatures[0]) == 1
1018 && OTF_check_features (otf, 0, otspec->script_tag,
1019 otspec->langsys_tag,
1020 otspec->features[1],
1021 otspec->nfeatures[1]) == 1);
1022 OTF_close (otf);
1023 if (!passed)
1024 continue;
1026 #endif /* HAVE_LIBOTF */
1027 if (VECTORP (chars))
1029 ptrdiff_t j;
1031 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1032 != FcResultMatch)
1033 continue;
1034 for (j = 0; j < ASIZE (chars); j++)
1035 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1036 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1037 break;
1038 if (j == ASIZE (chars))
1039 continue;
1041 if (! NILP (adstyle) || langname)
1043 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1045 if (! NILP (adstyle)
1046 && (NILP (this_adstyle)
1047 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1048 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1049 continue;
1050 if (langname
1051 && ! NILP (this_adstyle)
1052 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1053 continue;
1055 entity = ftfont_pattern_entity (fontset->fonts[i],
1056 AREF (spec, FONT_EXTRA_INDEX));
1057 if (! NILP (entity))
1058 val = Fcons (entity, val);
1060 val = Fnreverse (val);
1061 goto finish;
1063 err:
1064 /* We come here because of unexpected error in fontconfig API call
1065 (usually insufficient memory). */
1066 val = Qnil;
1068 finish:
1069 FONT_ADD_LOG ("ftfont-list", spec, val);
1070 if (objset) FcObjectSetDestroy (objset);
1071 if (fontset) FcFontSetDestroy (fontset);
1072 if (pattern) FcPatternDestroy (pattern);
1073 return val;
1076 static Lisp_Object
1077 ftfont_match (struct frame *f, Lisp_Object spec)
1079 Lisp_Object entity = Qnil;
1080 FcPattern *pattern, *match = NULL;
1081 FcResult result;
1082 char otlayout[15]; /* For "otlayout:XXXX" */
1083 struct OpenTypeSpec *otspec = NULL;
1084 const char *langname = NULL;
1086 if (! fc_initialized)
1088 FcInit ();
1089 fc_initialized = 1;
1092 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1093 if (! pattern)
1094 return Qnil;
1096 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1098 FcValue value;
1100 value.type = FcTypeDouble;
1101 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1102 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1104 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1106 FcDefaultSubstitute (pattern);
1107 match = FcFontMatch (NULL, pattern, &result);
1108 if (match)
1110 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1111 FcPatternDestroy (match);
1112 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1113 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1114 ftfont_generic_family_list))
1115 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1116 AREF (entity, FONT_FAMILY_INDEX))))
1117 entity = Qnil;
1120 FcPatternDestroy (pattern);
1122 FONT_ADD_LOG ("ftfont-match", spec, entity);
1123 return entity;
1126 static Lisp_Object
1127 ftfont_list_family (struct frame *f)
1129 Lisp_Object list = Qnil;
1130 FcPattern *pattern = NULL;
1131 FcFontSet *fontset = NULL;
1132 FcObjectSet *objset = NULL;
1133 int i;
1135 if (! fc_initialized)
1137 FcInit ();
1138 fc_initialized = 1;
1141 pattern = FcPatternCreate ();
1142 if (! pattern)
1143 goto finish;
1144 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1145 if (! objset)
1146 goto finish;
1147 fontset = FcFontList (NULL, pattern, objset);
1148 if (! fontset)
1149 goto finish;
1151 for (i = 0; i < fontset->nfont; i++)
1153 FcPattern *pat = fontset->fonts[i];
1154 FcChar8 *str;
1156 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1157 list = Fcons (intern ((char *) str), list);
1160 finish:
1161 if (objset) FcObjectSetDestroy (objset);
1162 if (fontset) FcFontSetDestroy (fontset);
1163 if (pattern) FcPatternDestroy (pattern);
1165 return list;
1169 Lisp_Object
1170 ftfont_open2 (struct frame *f,
1171 Lisp_Object entity,
1172 int pixel_size,
1173 Lisp_Object font_object)
1175 struct ftfont_info *ftfont_info;
1176 struct font *font;
1177 struct ftfont_cache_data *cache_data;
1178 FT_Face ft_face;
1179 FT_Size ft_size;
1180 FT_UInt size;
1181 Lisp_Object val, filename, idx, cache;
1182 bool scalable;
1183 int spacing;
1184 int i;
1185 double upEM;
1187 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1188 if (! CONSP (val))
1189 return Qnil;
1190 val = XCDR (val);
1191 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1192 if (NILP (cache))
1193 return Qnil;
1194 filename = XCAR (val);
1195 idx = XCDR (val);
1196 val = XCDR (cache);
1197 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1198 ft_face = cache_data->ft_face;
1199 if (XSAVE_INTEGER (val, 1) > 0)
1201 /* FT_Face in this cache is already used by the different size. */
1202 if (FT_New_Size (ft_face, &ft_size) != 0)
1203 return Qnil;
1204 if (FT_Activate_Size (ft_size) != 0)
1206 FT_Done_Size (ft_size);
1207 return Qnil;
1210 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1211 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1212 if (size == 0)
1213 size = pixel_size;
1214 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1216 if (XSAVE_INTEGER (val, 1) == 0)
1217 FT_Done_Face (ft_face);
1218 return Qnil;
1221 ASET (font_object, FONT_FILE_INDEX, filename);
1222 font = XFONT_OBJECT (font_object);
1223 ftfont_info = (struct ftfont_info *) font;
1224 ftfont_info->ft_size = ft_face->size;
1225 ftfont_info->index = XINT (idx);
1226 #ifdef HAVE_LIBOTF
1227 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1228 ftfont_info->otf = NULL;
1229 #endif /* HAVE_LIBOTF */
1230 /* This means that there's no need of transformation. */
1231 ftfont_info->matrix.xx = 0;
1232 font->pixel_size = size;
1233 font->driver = &ftfont_driver;
1234 font->encoding_charset = font->repertory_charset = -1;
1236 upEM = ft_face->units_per_EM;
1237 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1238 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1239 if (scalable)
1241 font->ascent = ft_face->ascender * size / upEM + 0.5;
1242 font->descent = - ft_face->descender * size / upEM + 0.5;
1243 font->height = ft_face->height * size / upEM + 0.5;
1245 else
1247 font->ascent = ft_face->size->metrics.ascender >> 6;
1248 font->descent = - ft_face->size->metrics.descender >> 6;
1249 font->height = ft_face->size->metrics.height >> 6;
1251 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1252 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1253 else
1254 spacing = FC_PROPORTIONAL;
1255 if (spacing != FC_PROPORTIONAL
1256 #ifdef FC_DUAL
1257 && spacing != FC_DUAL
1258 #endif /* FC_DUAL */
1260 font->min_width = font->average_width = font->space_width
1261 = (scalable ? ft_face->max_advance_width * size / upEM + 0.5
1262 : ft_face->size->metrics.max_advance >> 6);
1263 else
1265 int n;
1267 font->min_width = font->average_width = font->space_width = 0;
1268 for (i = 32, n = 0; i < 127; i++)
1269 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1271 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1273 if (this_width > 0
1274 && (! font->min_width || font->min_width > this_width))
1275 font->min_width = this_width;
1276 if (i == 32)
1277 font->space_width = this_width;
1278 font->average_width += this_width;
1279 n++;
1281 if (n > 0)
1282 font->average_width /= n;
1285 font->baseline_offset = 0;
1286 font->relative_compose = 0;
1287 font->default_ascent = 0;
1288 font->vertical_centering = 0;
1289 if (scalable)
1291 font->underline_position = (-ft_face->underline_position * size / upEM
1292 + 0.5);
1293 font->underline_thickness = (ft_face->underline_thickness * size / upEM
1294 + 0.5);
1296 else
1298 font->underline_position = -1;
1299 font->underline_thickness = 0;
1302 return font_object;
1305 static Lisp_Object
1306 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1308 Lisp_Object font_object;
1309 FT_UInt size;
1310 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1311 if (size == 0)
1312 size = pixel_size;
1313 font_object = font_build_object (VECSIZE (struct ftfont_info),
1314 Qfreetype, entity, size);
1315 return ftfont_open2 (f, entity, pixel_size, font_object);
1318 static void
1319 ftfont_close (struct font *font)
1321 /* FIXME: Although this function can be called while garbage-collecting,
1322 the function assumes that Lisp data structures are properly-formed.
1323 This invalid assumption can lead to core dumps (Bug#20890). */
1325 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1326 Lisp_Object val, cache;
1328 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1329 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1330 eassert (CONSP (cache));
1331 val = XCDR (cache);
1332 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1333 if (XSAVE_INTEGER (val, 1) == 0)
1335 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1337 FT_Done_Face (cache_data->ft_face);
1338 #ifdef HAVE_LIBOTF
1339 if (ftfont_info->otf)
1340 OTF_close (ftfont_info->otf);
1341 #endif
1342 cache_data->ft_face = NULL;
1344 else
1345 FT_Done_Size (ftfont_info->ft_size);
1348 static int
1349 ftfont_has_char (Lisp_Object font, int c)
1351 struct charset *cs = NULL;
1353 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1354 && charset_jisx0208 >= 0)
1355 cs = CHARSET_FROM_ID (charset_jisx0208);
1356 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1357 && charset_ksc5601 >= 0)
1358 cs = CHARSET_FROM_ID (charset_ksc5601);
1359 if (cs)
1360 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1362 if (FONT_ENTITY_P (font))
1364 FcCharSet *charset = ftfont_get_fc_charset (font);
1366 return (FcCharSetHasChar (charset, c) == FcTrue);
1368 else
1370 struct ftfont_info *ftfont_info;
1372 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1373 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1374 != 0);
1378 static unsigned
1379 ftfont_encode_char (struct font *font, int c)
1381 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1382 FT_Face ft_face = ftfont_info->ft_size->face;
1383 FT_ULong charcode = c;
1384 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1386 return (code > 0 ? code : FONT_INVALID_CODE);
1389 static void
1390 ftfont_text_extents (struct font *font, unsigned int *code,
1391 int nglyphs, struct font_metrics *metrics)
1393 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1394 FT_Face ft_face = ftfont_info->ft_size->face;
1395 int i, width = 0;
1396 bool first;
1398 if (ftfont_info->ft_size != ft_face->size)
1399 FT_Activate_Size (ftfont_info->ft_size);
1401 for (i = 0, first = 1; i < nglyphs; i++)
1403 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1405 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1407 if (first)
1409 metrics->lbearing = m->horiBearingX >> 6;
1410 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1411 metrics->ascent = m->horiBearingY >> 6;
1412 metrics->descent = (m->height - m->horiBearingY) >> 6;
1413 first = 0;
1415 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1416 metrics->lbearing = width + (m->horiBearingX >> 6);
1417 if (metrics->rbearing
1418 < width + ((m->horiBearingX + m->width) >> 6))
1419 metrics->rbearing
1420 = width + ((m->horiBearingX + m->width) >> 6);
1421 if (metrics->ascent < (m->horiBearingY >> 6))
1422 metrics->ascent = m->horiBearingY >> 6;
1423 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1424 metrics->descent = (m->height - m->horiBearingY) >> 6;
1425 width += m->horiAdvance >> 6;
1427 else
1428 width += font->space_width;
1430 metrics->width = width;
1433 static int
1434 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1436 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1437 FT_Face ft_face = ftfont_info->ft_size->face;
1438 FT_Int32 load_flags = FT_LOAD_RENDER;
1440 if (ftfont_info->ft_size != ft_face->size)
1441 FT_Activate_Size (ftfont_info->ft_size);
1442 if (bits_per_pixel == 1)
1444 #ifdef FT_LOAD_TARGET_MONO
1445 load_flags |= FT_LOAD_TARGET_MONO;
1446 #else
1447 load_flags |= FT_LOAD_MONOCHROME;
1448 #endif
1450 else if (bits_per_pixel != 8)
1451 /* We don't support such a rendering. */
1452 return -1;
1454 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1455 return -1;
1456 bitmap->bits_per_pixel
1457 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1458 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1459 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1460 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1461 : -1);
1462 if (bitmap->bits_per_pixel < 0)
1463 /* We don't support that kind of pixel mode. */
1464 return -1;
1465 bitmap->rows = ft_face->glyph->bitmap.rows;
1466 bitmap->width = ft_face->glyph->bitmap.width;
1467 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1468 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1469 bitmap->left = ft_face->glyph->bitmap_left;
1470 bitmap->top = ft_face->glyph->bitmap_top;
1471 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1473 return 0;
1476 static int
1477 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1478 int *x, int *y)
1480 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1481 FT_Face ft_face = ftfont_info->ft_size->face;
1483 if (ftfont_info->ft_size != ft_face->size)
1484 FT_Activate_Size (ftfont_info->ft_size);
1485 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1486 return -1;
1487 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1488 return -1;
1489 if (idx >= ft_face->glyph->outline.n_points)
1490 return -1;
1491 *x = ft_face->glyph->outline.points[idx].x;
1492 *y = ft_face->glyph->outline.points[idx].y;
1493 return 0;
1496 #ifdef HAVE_LIBOTF
1498 static Lisp_Object
1499 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1501 Lisp_Object scripts, langsyses, features, sym;
1502 int i, j, k, l;
1504 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1506 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1508 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1510 OTF_LangSys *otf_langsys;
1512 if (j >= 0)
1513 otf_langsys = otf_script->LangSys + j;
1514 else if (otf_script->DefaultLangSysOffset)
1515 otf_langsys = &otf_script->DefaultLangSys;
1516 else
1517 break;
1519 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1521 l = otf_langsys->FeatureIndex[k];
1522 if (l >= gsub_gpos->FeatureList.FeatureCount)
1523 continue;
1524 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1525 features = Fcons (sym, features);
1527 if (j >= 0)
1528 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1529 else
1530 sym = Qnil;
1531 langsyses = Fcons (Fcons (sym, features), langsyses);
1534 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1535 scripts = Fcons (Fcons (sym, langsyses), scripts);
1537 return scripts;
1542 static Lisp_Object
1543 ftfont_otf_capability (struct font *font)
1545 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1546 OTF *otf = ftfont_get_otf (ftfont_info);
1547 Lisp_Object gsub_gpos;
1549 if (! otf)
1550 return Qnil;
1551 gsub_gpos = Fcons (Qnil, Qnil);
1552 if (OTF_get_table (otf, "GSUB") == 0
1553 && otf->gsub->FeatureList.FeatureCount > 0)
1554 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1555 if (OTF_get_table (otf, "GPOS") == 0
1556 && otf->gpos->FeatureList.FeatureCount > 0)
1557 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1558 return gsub_gpos;
1561 #ifdef HAVE_M17N_FLT
1563 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1564 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1565 /* We can use the new feature of libotf and m17n-flt to handle the
1566 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1567 some Agian scripts. */
1568 #define M17N_FLT_USE_NEW_FEATURE
1569 #endif
1571 struct MFLTFontFT
1573 MFLTFont flt_font;
1574 struct font *font;
1575 FT_Face ft_face;
1576 OTF *otf;
1577 FT_Matrix *matrix;
1580 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1581 We use this structure instead of MFLTGlyph to utilize the new
1582 feature of libotf ver.0.9.15 which requires saving and restoring
1583 the value of OTF_GlyphString.positioning_type in the succeeding
1584 calls of the callback function MFLTFont.drive_otf (which is set to
1585 ftfont_drive_otf). */
1587 typedef struct {
1588 MFLTGlyph g;
1589 unsigned int libotf_positioning_type;
1590 } MFLTGlyphFT;
1592 static int
1593 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1594 int from, int to)
1596 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1597 FT_Face ft_face = flt_font_ft->ft_face;
1598 MFLTGlyphFT *g;
1600 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1601 if (! g->g.encoded)
1603 FT_UInt code = FT_Get_Char_Index (ft_face, g->g.code);
1605 g->g.code = code > 0 ? code : FONT_INVALID_CODE;
1606 g->g.encoded = 1;
1608 return 0;
1611 /* Operators for 26.6 fixed fractional pixel format */
1613 #define FLOOR(x) ((x) & -64)
1614 #define CEIL(x) (((x)+63) & -64)
1615 #define ROUND(x) (((x)+32) & -64)
1617 static int
1618 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1619 int from, int to)
1621 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1622 FT_Face ft_face = flt_font_ft->ft_face;
1623 MFLTGlyphFT *g;
1625 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1626 if (! g->g.measured)
1628 if (g->g.code != FONT_INVALID_CODE)
1630 FT_Glyph_Metrics *m;
1632 if (FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_DEFAULT) != 0)
1633 emacs_abort ();
1634 m = &ft_face->glyph->metrics;
1635 if (flt_font_ft->matrix)
1637 FT_Vector v[4];
1638 int i;
1640 v[0].x = v[1].x = m->horiBearingX;
1641 v[2].x = v[3].x = m->horiBearingX + m->width;
1642 v[0].y = v[2].y = m->horiBearingY;
1643 v[1].y = v[3].y = m->horiBearingY - m->height;
1644 for (i = 0; i < 4; i++)
1645 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1646 g->g.lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1647 g->g.rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1648 g->g.ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1649 g->g.descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1651 else
1653 g->g.lbearing = FLOOR (m->horiBearingX);
1654 g->g.rbearing = CEIL (m->horiBearingX + m->width);
1655 g->g.ascent = CEIL (m->horiBearingY);
1656 g->g.descent = - FLOOR (m->horiBearingY - m->height);
1658 g->g.xadv = ROUND (ft_face->glyph->advance.x);
1660 else
1662 g->g.lbearing = 0;
1663 g->g.rbearing = g->g.xadv = flt_font_ft->font->space_width << 6;
1664 g->g.ascent = flt_font_ft->font->ascent << 6;
1665 g->g.descent = flt_font_ft->font->descent << 6;
1667 g->g.yadv = 0;
1668 g->g.measured = 1;
1670 return 0;
1673 static int
1674 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1676 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1678 #define FEATURE_ANY(IDX) \
1679 (spec->features[IDX] \
1680 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1682 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1683 OTF *otf = flt_font_ft->otf;
1684 OTF_Tag *tags;
1685 int i, n;
1686 bool negative;
1688 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1689 /* Return true iff any of GSUB or GPOS support the script (and
1690 language). */
1691 return (otf
1692 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1693 NULL, 0) > 0
1694 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1695 NULL, 0) > 0));
1697 for (i = 0; i < 2; i++)
1698 if (! FEATURE_ANY (i))
1700 if (FEATURE_NONE (i))
1702 if (otf
1703 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1704 NULL, 0) > 0)
1705 return 0;
1706 continue;
1708 if (spec->features[i][0] == 0xFFFFFFFF)
1710 if (! otf
1711 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1712 NULL, 0) <= 0)
1713 continue;
1715 else if (! otf)
1716 return 0;
1717 for (n = 1; spec->features[i][n]; n++);
1718 USE_SAFE_ALLOCA;
1719 SAFE_NALLOCA (tags, 1, n);
1720 for (n = 0, negative = 0; spec->features[i][n]; n++)
1722 if (spec->features[i][n] == 0xFFFFFFFF)
1723 negative = 1;
1724 else if (negative)
1725 tags[n - 1] = spec->features[i][n] | 0x80000000;
1726 else
1727 tags[n] = spec->features[i][n];
1729 bool passed = true;
1730 #ifndef M17N_FLT_USE_NEW_FEATURE
1731 passed = n - negative > 0;
1732 #endif
1733 if (passed)
1734 passed = (OTF_check_features (otf, i == 0, spec->script,
1735 spec->langsys, tags, n - negative)
1736 != 1);
1737 SAFE_FREE ();
1738 if (passed)
1739 return 0;
1741 return 1;
1742 #undef FEATURE_NONE
1743 #undef FEATURE_ANY
1746 #define DEVICE_DELTA(table, size) \
1747 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1748 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1749 : 0)
1751 static void
1752 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1753 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1755 if (anchor->AnchorFormat == 2)
1757 FT_Outline *outline;
1758 int ap = anchor->f.f1.AnchorPoint;
1760 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1761 outline = &ft_face->glyph->outline;
1762 if (ap < outline->n_points)
1764 *x = outline->points[ap].x << 6;
1765 *y = outline->points[ap].y << 6;
1768 else if (anchor->AnchorFormat == 3)
1770 if (anchor->f.f2.XDeviceTable.offset
1771 && anchor->f.f2.XDeviceTable.DeltaValue)
1772 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1773 if (anchor->f.f2.YDeviceTable.offset
1774 && anchor->f.f2.YDeviceTable.DeltaValue)
1775 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1779 static OTF_GlyphString otf_gstring;
1781 static void
1782 setup_otf_gstring (int size)
1784 if (otf_gstring.size < size)
1786 ptrdiff_t new_size = otf_gstring.size;
1787 xfree (otf_gstring.glyphs);
1788 otf_gstring.glyphs = xpalloc (NULL, &new_size, size - otf_gstring.size,
1789 INT_MAX, sizeof *otf_gstring.glyphs);
1790 otf_gstring.size = new_size;
1792 otf_gstring.used = size;
1793 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1796 #ifdef M17N_FLT_USE_NEW_FEATURE
1798 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1799 #define PACK_OTF_TAG(TAG) \
1800 ((((TAG) & 0x7F000000) >> 3) \
1801 | (((TAG) & 0x7F0000) >> 2) \
1802 | (((TAG) & 0x7F00) >> 1) \
1803 | ((TAG) & 0x7F))
1805 /* Assuming that FONT is an OpenType font, apply OpenType features
1806 specified in SPEC on glyphs between FROM and TO of IN, and record
1807 the lastly applied feature in each glyph of IN. If OUT is not
1808 NULL, append the resulting glyphs to OUT while storing glyph
1809 position adjustment information in ADJUSTMENT. */
1811 static int
1812 ftfont_drive_otf (MFLTFont *font,
1813 MFLTOtfSpec *spec,
1814 MFLTGlyphString *in,
1815 int from,
1816 int to,
1817 MFLTGlyphString *out,
1818 MFLTGlyphAdjustment *adjustment)
1820 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1821 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
1822 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
1823 FT_Face ft_face = flt_font_ft->ft_face;
1824 OTF *otf = flt_font_ft->otf;
1825 int len = to - from;
1826 int i, j, gidx;
1827 OTF_Glyph *otfg;
1828 char script[5], *langsys = NULL;
1829 char *gsub_features = NULL, *gpos_features = NULL;
1830 OTF_Feature *features;
1832 if (len == 0)
1833 return from;
1834 OTF_tag_name (spec->script, script);
1836 char langsysbuf[5];
1837 if (spec->langsys)
1839 langsys = langsysbuf;
1840 OTF_tag_name (spec->langsys, langsys);
1843 USE_SAFE_ALLOCA;
1844 for (i = 0; i < 2; i++)
1846 char *p;
1848 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1850 for (j = 0; spec->features[i][j]; j++);
1851 SAFE_NALLOCA (p, 6, j);
1852 if (i == 0)
1853 gsub_features = p;
1854 else
1855 gpos_features = p;
1856 for (j = 0; spec->features[i][j]; j++)
1858 if (spec->features[i][j] == 0xFFFFFFFF)
1859 *p++ = '*', *p++ = ',';
1860 else
1862 OTF_tag_name (spec->features[i][j], p);
1863 p[4] = ',';
1864 p += 5;
1867 *--p = '\0';
1871 setup_otf_gstring (len);
1872 for (i = 0; i < len; i++)
1874 otf_gstring.glyphs[i].c = in_glyphs[i].g.c & 0x11FFFF;
1875 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
1876 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1877 otf_gstring.glyphs[i].positioning_type = in_glyphs[i].libotf_positioning_type;
1878 #endif
1881 OTF_drive_gdef (otf, &otf_gstring);
1882 gidx = out ? out->used : from;
1884 if (gsub_features && out)
1886 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1887 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1888 gsub_features) < 0)
1889 goto simple_copy;
1890 #else
1891 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1892 gsub_features) < 0)
1893 goto simple_copy;
1894 #endif
1895 if (out->allocated < out->used + otf_gstring.used)
1897 SAFE_FREE ();
1898 return -2;
1900 features = otf->gsub->FeatureList.Feature;
1901 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1903 MFLTGlyphFT *g;
1904 int min_from, max_to;
1905 int feature_idx;
1907 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1908 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1909 #else
1910 feature_idx = otfg->positioning_type >> 4;
1911 #endif
1912 g = out_glyphs + out->used;
1913 *g = in_glyphs[otfg->f.index.from];
1914 if (g->g.code != otfg->glyph_id)
1916 g->g.c = 0;
1917 g->g.code = otfg->glyph_id;
1918 g->g.measured = 0;
1920 out->used++;
1921 min_from = g->g.from;
1922 max_to = g->g.to;
1923 if (otfg->f.index.from < otfg->f.index.to)
1925 /* OTFG substitutes multiple glyphs in IN. */
1926 for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
1928 if (min_from > in_glyphs[j].g.from)
1929 min_from = in_glyphs[j].g.from;
1930 if (max_to < in_glyphs[j].g.to)
1931 max_to = in_glyphs[j].g.to;
1933 g->g.from = min_from;
1934 g->g.to = max_to;
1936 if (feature_idx)
1938 unsigned int tag = features[feature_idx - 1].FeatureTag;
1939 tag = PACK_OTF_TAG (tag);
1940 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1942 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1943 g->libotf_positioning_type
1944 = otfg->positioning_type & OTF_positioning_type_components_mask;
1945 #endif
1946 for (i++, otfg++; (i < otf_gstring.used
1947 && otfg->f.index.from == otfg[-1].f.index.from);
1948 i++, otfg++)
1950 g = out_glyphs + out->used;
1951 *g = in_glyphs[otfg->f.index.to];
1952 if (g->g.code != otfg->glyph_id)
1954 g->g.c = 0;
1955 g->g.code = otfg->glyph_id;
1956 g->g.measured = 0;
1958 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1959 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1960 #else
1961 feature_idx = otfg->positioning_type >> 4;
1962 #endif
1963 if (feature_idx)
1965 unsigned int tag = features[feature_idx - 1].FeatureTag;
1966 tag = PACK_OTF_TAG (tag);
1967 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1969 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1970 g->libotf_positioning_type
1971 = otfg->positioning_type & OTF_positioning_type_components_mask;
1972 #endif
1973 out->used++;
1977 else if (gsub_features)
1979 /* Just for checking which features will be applied. */
1980 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1981 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1982 gsub_features) < 0)
1983 goto simple_copy;
1984 #else
1985 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1986 gsub_features) < 0)
1987 goto simple_copy;
1988 #endif
1989 features = otf->gsub->FeatureList.Feature;
1990 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1991 otfg++)
1993 int feature_idx;
1994 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1995 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1996 #else
1997 feature_idx = otfg->positioning_type >> 4;
1998 #endif
1999 if (feature_idx)
2001 unsigned int tag = features[feature_idx - 1].FeatureTag;
2002 tag = PACK_OTF_TAG (tag);
2003 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2005 MFLTGlyphFT *g = in_glyphs + j;
2006 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2011 else if (out)
2013 if (out->allocated < out->used + len)
2015 SAFE_FREE ();
2016 return -2;
2018 for (i = 0; i < len; i++)
2019 out_glyphs[out->used++] = in_glyphs[i];
2022 if (gpos_features && out)
2024 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
2025 int x_ppem, y_ppem, x_scale, y_scale;
2027 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2028 if (OTF_drive_gpos_features (otf, &otf_gstring, script, langsys,
2029 gpos_features) < 0)
2031 SAFE_FREE ();
2032 return to;
2034 #else
2035 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2036 gpos_features) < 0)
2038 SAFE_FREE ();
2039 return to;
2041 #endif
2042 features = otf->gpos->FeatureList.Feature;
2043 x_ppem = ft_face->size->metrics.x_ppem;
2044 y_ppem = ft_face->size->metrics.y_ppem;
2045 x_scale = ft_face->size->metrics.x_scale;
2046 y_scale = ft_face->size->metrics.y_scale;
2048 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2049 i < otf_gstring.used; i++, otfg++)
2051 MFLTGlyphAdjustment *adjust = adjustment;
2052 MFLTGlyphFT *prev;
2053 int positioning_type, feature_idx;
2055 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2056 positioning_type = OTF_POSITIONING_TYPE_GET_FORMAT (otfg);
2057 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
2058 #else
2059 positioning_type = otfg->positioning_type & 0xF;
2060 feature_idx = otfg->positioning_type >> 4;
2061 #endif
2062 if (feature_idx)
2064 unsigned int tag = features[feature_idx - 1].FeatureTag;
2065 tag = PACK_OTF_TAG (tag);
2066 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2069 if (! otfg->glyph_id)
2070 /* This is a pseudo glyph that contains positioning
2071 information to be accumulated to a real glyph. */
2072 adjust--;
2073 switch (positioning_type)
2075 case 0:
2076 break;
2077 case 1: /* Single */
2078 case 2: /* Pair */
2080 int format = otfg->f.f1.format;
2082 if (format & OTF_XPlacement)
2083 adjust->xoff
2084 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2085 if (format & OTF_XPlaDevice)
2086 adjust->xoff
2087 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2088 if (format & OTF_YPlacement)
2089 adjust->yoff
2090 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2091 if (format & OTF_YPlaDevice)
2092 adjust->yoff
2093 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2094 if (format & OTF_XAdvance)
2095 adjust->xadv
2096 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2097 if (format & OTF_XAdvDevice)
2098 adjust->xadv
2099 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2100 if (format & OTF_YAdvance)
2101 adjust->yadv
2102 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2103 if (format & OTF_YAdvDevice)
2104 adjust->yadv
2105 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2106 adjust->set = 1;
2108 break;
2109 case 3: /* Cursive */
2110 /* Not yet supported. */
2111 break;
2112 case 4: /* Mark-to-Base */
2113 case 5: /* Mark-to-Ligature */
2114 if (! base)
2115 break;
2116 prev = base;
2117 goto label_adjust_anchor;
2118 default: /* i.e. case 6 Mark-to-Mark */
2119 if (! mark)
2120 break;
2121 prev = mark;
2122 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2124 int distance = OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg);
2126 if (distance > 0)
2128 prev = g - distance;
2129 if (prev < out_glyphs)
2130 prev = mark;
2133 #endif
2135 label_adjust_anchor:
2137 int base_x, base_y, mark_x, mark_y;
2138 int this_from, this_to;
2140 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2141 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2142 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2143 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2145 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2146 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2147 x_ppem, y_ppem, &base_x, &base_y);
2148 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2149 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2150 x_ppem, y_ppem, &mark_x, &mark_y);
2151 adjust->xoff = (base_x - mark_x);
2152 adjust->yoff = - (base_y - mark_y);
2153 adjust->back = (g - prev);
2154 adjust->xadv = 0;
2155 adjust->advance_is_absolute = 1;
2156 adjust->set = 1;
2157 this_from = g->g.from;
2158 this_to = g->g.to;
2159 for (j = 0; prev + j < g; j++)
2161 if (this_from > prev[j].g.from)
2162 this_from = prev[j].g.from;
2163 if (this_to < prev[j].g.to)
2164 this_to = prev[j].g.to;
2166 for (; prev <= g; prev++)
2168 prev->g.from = this_from;
2169 prev->g.to = this_to;
2173 if (otfg->glyph_id)
2175 if (otfg->GlyphClass == OTF_GlyphClass0)
2176 base = mark = g;
2177 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2178 mark = g;
2179 else
2180 base = g;
2181 g++, adjustment++;
2185 else if (gpos_features)
2187 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2188 gpos_features) < 0)
2190 SAFE_FREE ();
2191 return to;
2193 features = otf->gpos->FeatureList.Feature;
2194 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2195 i++, otfg++)
2196 if (otfg->positioning_type & 0xF)
2198 int feature_idx = otfg->positioning_type >> 4;
2200 if (feature_idx)
2202 unsigned int tag = features[feature_idx - 1].FeatureTag;
2203 tag = PACK_OTF_TAG (tag);
2204 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2206 MFLTGlyphFT *g = in_glyphs + j;
2207 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2212 SAFE_FREE ();
2213 return to;
2215 simple_copy:
2216 SAFE_FREE ();
2217 if (! out)
2218 return to;
2219 if (out->allocated < out->used + len)
2220 return -2;
2221 font->get_metrics (font, in, from, to);
2222 memcpy (out->glyphs + out->used, in_glyphs, sizeof (MFLTGlyphFT) * len);
2223 out->used += len;
2224 return to;
2227 static int
2228 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2229 MFLTGlyphString *in, int from, int to)
2231 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2234 #else /* not M17N_FLT_USE_NEW_FEATURE */
2236 static int
2237 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2238 int from, int to,
2239 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2241 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2242 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
2243 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
2244 FT_Face ft_face = flt_font_ft->ft_face;
2245 OTF *otf = flt_font_ft->otf;
2246 int len = to - from;
2247 int i, j, gidx;
2248 OTF_Glyph *otfg;
2249 char script[5], *langsys = NULL;
2250 char *gsub_features = NULL, *gpos_features = NULL;
2252 if (len == 0)
2253 return from;
2254 OTF_tag_name (spec->script, script);
2256 char langsysbuf[5];
2257 if (spec->langsys)
2259 langsys = langsysbuf;
2260 OTF_tag_name (spec->langsys, langsys);
2263 USE_SAFE_ALLOCA;
2264 for (i = 0; i < 2; i++)
2266 char *p;
2268 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2270 for (j = 0; spec->features[i][j]; j++);
2271 SAFE_NALLOCA (p, 6, j);
2272 if (i == 0)
2273 gsub_features = p;
2274 else
2275 gpos_features = p;
2276 for (j = 0; spec->features[i][j]; j++)
2278 if (spec->features[i][j] == 0xFFFFFFFF)
2279 *p++ = '*', *p++ = ',';
2280 else
2282 OTF_tag_name (spec->features[i][j], p);
2283 p[4] = ',';
2284 p += 5;
2287 *--p = '\0';
2291 setup_otf_gstring (len);
2292 for (i = 0; i < len; i++)
2294 otf_gstring.glyphs[i].c = in_glyphs[i].g.c;
2295 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
2298 OTF_drive_gdef (otf, &otf_gstring);
2299 gidx = out->used;
2301 if (gsub_features)
2303 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2304 < 0)
2305 goto simple_copy;
2306 if (out->allocated < out->used + otf_gstring.used)
2308 SAFE_FREE ();
2309 return -2;
2311 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2313 MFLTGlyphFT *g;
2314 int min_from, max_to;
2315 int j;
2317 g = out_glyphs + out->used;
2318 *g = in_glyphs[otfg->f.index.from];
2319 if (g->g.code != otfg->glyph_id)
2321 g->g.c = 0;
2322 g->g.code = otfg->glyph_id;
2323 g->g.measured = 0;
2325 out->used++;
2326 min_from = g->g.from;
2327 max_to = g->g.to;
2328 if (otfg->f.index.from < otfg->f.index.to)
2330 /* OTFG substitutes multiple glyphs in IN. */
2331 for (j = from + otfg->f.index.from + 1;
2332 j <= from + otfg->f.index.to; j++)
2334 if (min_from > in->glyphs[j].from)
2335 min_from = in->glyphs[j].from;
2336 if (max_to < in->glyphs[j].to)
2337 max_to = in->glyphs[j].to;
2339 g->g.from = min_from;
2340 g->g.to = max_to;
2342 for (i++, otfg++; (i < otf_gstring.used
2343 && otfg->f.index.from == otfg[-1].f.index.from);
2344 i++, otfg++)
2346 g = out_glyphs + out->used;
2347 *g = in_glyphs[otfg->f.index.to];
2348 if (g->g.code != otfg->glyph_id)
2350 g->g.c = 0;
2351 g->g.code = otfg->glyph_id;
2352 g->g.measured = 0;
2354 out->used++;
2358 else
2360 if (out->allocated < out->used + len)
2362 SAFE_FREE ();
2363 return -2;
2365 for (i = 0; i < len; i++)
2366 out_glyphs[out->used++] = in_glyphs[i];
2369 if (gpos_features)
2371 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
2372 int x_ppem, y_ppem, x_scale, y_scale;
2374 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2375 < 0)
2377 SAFE_FREE ();
2378 return to;
2381 x_ppem = ft_face->size->metrics.x_ppem;
2382 y_ppem = ft_face->size->metrics.y_ppem;
2383 x_scale = ft_face->size->metrics.x_scale;
2384 y_scale = ft_face->size->metrics.y_scale;
2386 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2387 i < otf_gstring.used; i++, otfg++, g++)
2389 MFLTGlyphFT *prev;
2391 if (! otfg->glyph_id)
2392 continue;
2393 switch (otfg->positioning_type)
2395 case 0:
2396 break;
2397 case 1: /* Single */
2398 case 2: /* Pair */
2400 int format = otfg->f.f1.format;
2402 if (format & OTF_XPlacement)
2403 adjustment[i].xoff
2404 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2405 if (format & OTF_XPlaDevice)
2406 adjustment[i].xoff
2407 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2408 if (format & OTF_YPlacement)
2409 adjustment[i].yoff
2410 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2411 if (format & OTF_YPlaDevice)
2412 adjustment[i].yoff
2413 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2414 if (format & OTF_XAdvance)
2415 adjustment[i].xadv
2416 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2417 if (format & OTF_XAdvDevice)
2418 adjustment[i].xadv
2419 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2420 if (format & OTF_YAdvance)
2421 adjustment[i].yadv
2422 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2423 if (format & OTF_YAdvDevice)
2424 adjustment[i].yadv
2425 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2426 adjustment[i].set = 1;
2428 break;
2429 case 3: /* Cursive */
2430 /* Not yet supported. */
2431 break;
2432 case 4: /* Mark-to-Base */
2433 case 5: /* Mark-to-Ligature */
2434 if (! base)
2435 break;
2436 prev = base;
2437 goto label_adjust_anchor;
2438 default: /* i.e. case 6 Mark-to-Mark */
2439 if (! mark)
2440 break;
2441 prev = mark;
2443 label_adjust_anchor:
2445 int base_x, base_y, mark_x, mark_y;
2446 int this_from, this_to;
2448 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2449 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2450 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2451 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2453 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2454 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2455 x_ppem, y_ppem, &base_x, &base_y);
2456 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2457 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2458 x_ppem, y_ppem, &mark_x, &mark_y);
2459 adjustment[i].xoff = (base_x - mark_x);
2460 adjustment[i].yoff = - (base_y - mark_y);
2461 adjustment[i].back = (g - prev);
2462 adjustment[i].xadv = 0;
2463 adjustment[i].advance_is_absolute = 1;
2464 adjustment[i].set = 1;
2465 this_from = g->g.from;
2466 this_to = g->g.to;
2467 for (j = 0; prev + j < g; j++)
2469 if (this_from > prev[j].g.from)
2470 this_from = prev[j].g.from;
2471 if (this_to < prev[j].g.to)
2472 this_to = prev[j].g.to;
2474 for (; prev <= g; prev++)
2476 prev->g.from = this_from;
2477 prev->g.to = this_to;
2481 if (otfg->GlyphClass == OTF_GlyphClass0)
2482 base = mark = g;
2483 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2484 mark = g;
2485 else
2486 base = g;
2489 SAFE_FREE ();
2490 return to;
2492 simple_copy:
2493 SAFE_FREE ();
2494 if (out->allocated < out->used + len)
2495 return -2;
2496 font->get_metrics (font, in, from, to);
2497 memcpy (out_glyphs + out->used, in_glyphs,
2498 sizeof (MFLTGlyphFT) * len);
2499 out->used += len;
2500 return to;
2503 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2505 static MFLTGlyphString gstring;
2507 static bool m17n_flt_initialized;
2509 static Lisp_Object
2510 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2511 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2513 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2514 ptrdiff_t i;
2515 struct MFLTFontFT flt_font_ft;
2516 MFLT *flt = NULL;
2517 bool with_variation_selector = false;
2519 if (! m17n_flt_initialized)
2521 M17N_INIT ();
2522 #ifdef M17N_FLT_USE_NEW_FEATURE
2523 mflt_enable_new_feature = 1;
2524 mflt_try_otf = ftfont_try_otf;
2525 #endif /* M17N_FLT_USE_NEW_FEATURE */
2526 m17n_flt_initialized = 1;
2529 for (i = 0; i < len; i++)
2531 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2532 int c;
2534 if (NILP (g))
2535 break;
2536 c = LGLYPH_CHAR (g);
2537 if (CHAR_VARIATION_SELECTOR_P (c))
2538 with_variation_selector = true;
2541 len = i;
2543 if (otf && with_variation_selector)
2545 setup_otf_gstring (len);
2546 for (i = 0; i < len; i++)
2548 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2550 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2551 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2552 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2554 OTF_drive_cmap (otf, &otf_gstring);
2555 for (i = 0; i < otf_gstring.used; i++)
2557 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2558 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2559 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2561 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2562 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2563 LGSTRING_SET_GLYPH (lgstring, i, g0);
2565 if (len > otf_gstring.used)
2567 len = otf_gstring.used;
2568 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2573 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2575 if (NILP (family))
2576 flt_font_ft.flt_font.family = Mnil;
2577 else
2578 flt_font_ft.flt_font.family
2579 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2581 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2582 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2583 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2584 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2585 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2586 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2587 flt_font_ft.flt_font.internal = NULL;
2588 flt_font_ft.font = font;
2589 flt_font_ft.ft_face = ft_face;
2590 flt_font_ft.otf = otf;
2591 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2593 if (1 < len)
2595 /* A little bit ad hoc. Perhaps, shaper must get script and
2596 language information, and select a proper flt for them
2597 here. */
2598 int c1 = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 1));
2599 /* For the combining characters in the range U+300..U+36F,
2600 "combining" is the sole FLT provided by the m17n-lib. In
2601 addition, it is the sole FLT that can handle the other
2602 combining characters with non-OTF fonts. */
2603 if ((0x300 <= c1 && c1 <= 0x36F)
2604 || (! otf && CHAR_HAS_CATEGORY (c1, '^')))
2605 flt = mflt_get (msymbol ("combining"));
2607 if (! flt && ! otf)
2609 flt = mflt_find (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 0)),
2610 &flt_font_ft.flt_font);
2611 if (! flt)
2612 return make_number (0);
2615 MFLTGlyphFT *glyphs = (MFLTGlyphFT *) gstring.glyphs;
2616 ptrdiff_t allocated = gstring.allocated;
2617 ptrdiff_t incr_min = len - allocated;
2621 if (0 < incr_min)
2623 xfree (glyphs);
2624 glyphs = xpalloc (NULL, &allocated, incr_min, INT_MAX, sizeof *glyphs);
2626 incr_min = 1;
2628 for (i = 0; i < len; i++)
2630 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2631 memset (&glyphs[i], 0, sizeof glyphs[i]);
2632 glyphs[i].g.c = LGLYPH_CHAR (g);
2633 if (with_variation_selector)
2635 glyphs[i].g.code = LGLYPH_CODE (g);
2636 glyphs[i].g.encoded = 1;
2640 gstring.glyph_size = sizeof *glyphs;
2641 gstring.glyphs = (MFLTGlyph *) glyphs;
2642 gstring.allocated = allocated;
2643 gstring.used = len;
2644 gstring.r2l = 0;
2646 while (mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt) == -2);
2648 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2649 return Qnil;
2650 for (i = 0; i < gstring.used; i++)
2652 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2654 g->g.from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->g.from));
2655 g->g.to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->g.to));
2658 for (i = 0; i < gstring.used; i++)
2660 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2661 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2663 if (NILP (lglyph))
2665 lglyph = LGLYPH_NEW ();
2666 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2668 LGLYPH_SET_FROM (lglyph, g->g.from);
2669 LGLYPH_SET_TO (lglyph, g->g.to);
2670 LGLYPH_SET_CHAR (lglyph, g->g.c);
2671 LGLYPH_SET_CODE (lglyph, g->g.code);
2672 LGLYPH_SET_WIDTH (lglyph, g->g.xadv >> 6);
2673 LGLYPH_SET_LBEARING (lglyph, g->g.lbearing >> 6);
2674 LGLYPH_SET_RBEARING (lglyph, g->g.rbearing >> 6);
2675 LGLYPH_SET_ASCENT (lglyph, g->g.ascent >> 6);
2676 LGLYPH_SET_DESCENT (lglyph, g->g.descent >> 6);
2677 if (g->g.adjusted)
2679 Lisp_Object vec = make_uninit_vector (3);
2681 ASET (vec, 0, make_number (g->g.xoff >> 6));
2682 ASET (vec, 1, make_number (g->g.yoff >> 6));
2683 ASET (vec, 2, make_number (g->g.xadv >> 6));
2684 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2687 return make_number (i);
2690 Lisp_Object
2691 ftfont_shape (Lisp_Object lgstring)
2693 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2694 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2695 OTF *otf = ftfont_get_otf (ftfont_info);
2697 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2698 &ftfont_info->matrix);
2701 #endif /* HAVE_M17N_FLT */
2703 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2705 static int
2706 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2708 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2709 OTF *otf = ftfont_get_otf (ftfont_info);
2711 if (! otf)
2712 return 0;
2713 return OTF_get_variation_glyphs (otf, c, variations);
2716 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2717 #endif /* HAVE_LIBOTF */
2719 static const char *const ftfont_booleans [] = {
2720 ":antialias",
2721 ":hinting",
2722 ":verticallayout",
2723 ":autohint",
2724 ":globaladvance",
2725 ":outline",
2726 ":scalable",
2727 ":minspace",
2728 ":embolden",
2729 NULL,
2732 static const char *const ftfont_non_booleans [] = {
2733 ":family",
2734 ":familylang",
2735 ":style",
2736 ":stylelang",
2737 ":fullname",
2738 ":fullnamelang",
2739 ":slant",
2740 ":weight",
2741 ":size",
2742 ":width",
2743 ":aspect",
2744 ":pixelsize",
2745 ":spacing",
2746 ":foundry",
2747 ":hintstyle",
2748 ":file",
2749 ":index",
2750 ":ftface",
2751 ":rasterizer",
2752 ":scale",
2753 ":dpi",
2754 ":rgba",
2755 ":lcdfilter",
2756 ":charset",
2757 ":lang",
2758 ":fontversion",
2759 ":capability",
2760 NULL,
2763 static void
2764 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2766 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2770 static Lisp_Object
2771 ftfont_combining_capability (struct font *font)
2773 #ifdef HAVE_M17N_FLT
2774 return Qt;
2775 #else
2776 return Qnil;
2777 #endif
2780 void
2781 syms_of_ftfont (void)
2783 /* Symbolic type of this font-driver. */
2784 DEFSYM (Qfreetype, "freetype");
2786 /* Fontconfig's generic families and their aliases. */
2787 DEFSYM (Qmonospace, "monospace");
2788 DEFSYM (Qsans_serif, "sans-serif");
2789 DEFSYM (Qsans, "sans");
2790 DEFSYM (Qsans__serif, "sans serif");
2792 staticpro (&freetype_font_cache);
2793 freetype_font_cache = list1 (Qt);
2795 staticpro (&ftfont_generic_family_list);
2796 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2797 Fcons (Qsans_serif, Qt),
2798 Fcons (Qsans, Qt));
2800 staticpro (&ft_face_cache);
2801 ft_face_cache = Qnil;
2803 ftfont_driver.type = Qfreetype;
2804 register_font_driver (&ftfont_driver, NULL);