Fix GNUC_PREREQ off-by-1 typo
[emacs.git] / src / ftfont.c
blob1ae3f88daa31911e635cea8e0709d7f0dd4ac896
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 int i, j;
573 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
575 if (str[i] == '.')
576 re[j++] = '\\';
577 else if (str[i] == '*')
578 re[j++] = '.';
579 re[j] = str[i];
580 if (re[j] == '?')
581 re[j] = '.';
583 re[j] = '\0';
584 AUTO_STRING_WITH_LEN (regexp, re, j);
585 for (i = 0; fc_charset_table[i].name; i++)
586 if (fast_c_string_match_ignore_case
587 (regexp, fc_charset_table[i].name,
588 strlen (fc_charset_table[i].name)) >= 0)
589 break;
590 SAFE_FREE ();
591 if (! fc_charset_table[i].name)
592 return -1;
593 if (! fc_charset_table[i].fc_charset)
595 FcCharSet *charset = FcCharSetCreate ();
596 int *uniquifier = fc_charset_table[i].uniquifier;
598 if (! charset)
599 return -1;
600 for (j = 0; uniquifier[j]; j++)
601 if (! FcCharSetAddChar (charset, uniquifier[j]))
603 FcCharSetDestroy (charset);
604 return -1;
606 fc_charset_table[i].fc_charset = charset;
608 return i;
611 struct OpenTypeSpec
613 Lisp_Object script;
614 unsigned int script_tag, langsys_tag;
615 int nfeatures[2];
616 unsigned int *features[2];
619 #define OTF_SYM_TAG(SYM, TAG) \
620 do { \
621 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
622 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
623 } while (0)
625 #define OTF_TAG_STR(TAG, P) \
626 do { \
627 (P)[0] = (char) (TAG >> 24); \
628 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
629 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
630 (P)[3] = (char) (TAG & 0xFF); \
631 (P)[4] = '\0'; \
632 } while (0)
634 #ifdef HAVE_LIBOTF
635 #define OTF_TAG_SYM(SYM, TAG) \
636 do { \
637 char str[5]; \
639 OTF_TAG_STR (TAG, str); \
640 (SYM) = font_intern_prop (str, 4, 1); \
641 } while (0)
642 #endif
645 static struct OpenTypeSpec *
646 ftfont_get_open_type_spec (Lisp_Object otf_spec)
648 struct OpenTypeSpec *spec = malloc (sizeof *spec);
649 Lisp_Object val;
650 int i, j;
651 bool negative;
653 if (! spec)
654 return NULL;
655 spec->script = XCAR (otf_spec);
656 if (! NILP (spec->script))
658 OTF_SYM_TAG (spec->script, spec->script_tag);
659 val = assq_no_quit (spec->script, Votf_script_alist);
660 if (CONSP (val) && SYMBOLP (XCDR (val)))
661 spec->script = XCDR (val);
662 else
663 spec->script = Qnil;
665 else
666 spec->script_tag = 0x44464C54; /* "DFLT" */
667 otf_spec = XCDR (otf_spec);
668 spec->langsys_tag = 0;
669 if (! NILP (otf_spec))
671 val = XCAR (otf_spec);
672 if (! NILP (val))
673 OTF_SYM_TAG (val, spec->langsys_tag);
674 otf_spec = XCDR (otf_spec);
676 spec->nfeatures[0] = spec->nfeatures[1] = 0;
677 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
679 Lisp_Object len;
681 val = XCAR (otf_spec);
682 if (NILP (val))
683 continue;
684 len = Flength (val);
685 spec->features[i] =
686 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
688 : malloc (XINT (len) * sizeof *spec->features[i]));
689 if (! spec->features[i])
691 if (i > 0 && spec->features[0])
692 free (spec->features[0]);
693 free (spec);
694 return NULL;
696 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
698 if (NILP (XCAR (val)))
699 negative = 1;
700 else
702 unsigned int tag;
704 OTF_SYM_TAG (XCAR (val), tag);
705 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
708 spec->nfeatures[i] = j;
710 return spec;
713 static FcPattern *
714 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
716 Lisp_Object tmp, extra;
717 FcPattern *pattern = NULL;
718 FcCharSet *charset = NULL;
719 FcLangSet *langset = NULL;
720 int n;
721 int dpi = -1;
722 int scalable = -1;
723 Lisp_Object script = Qnil;
724 Lisp_Object registry;
725 int fc_charset_idx;
727 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
728 && n < 100)
729 /* Fontconfig doesn't support reverse-italic/oblique. */
730 return NULL;
732 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
733 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
734 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
735 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
736 scalable = 1;
738 registry = AREF (spec, FONT_REGISTRY_INDEX);
739 if (NILP (registry)
740 || EQ (registry, Qascii_0)
741 || EQ (registry, Qiso10646_1)
742 || EQ (registry, Qunicode_bmp))
743 fc_charset_idx = -1;
744 else
746 FcChar8 *lang;
748 fc_charset_idx = ftfont_get_charset (registry);
749 if (fc_charset_idx < 0)
750 return NULL;
751 charset = fc_charset_table[fc_charset_idx].fc_charset;
752 *langname = fc_charset_table[fc_charset_idx].lang;
753 lang = (FcChar8 *) *langname;
754 if (lang)
756 langset = FcLangSetCreate ();
757 if (! langset)
758 goto err;
759 FcLangSetAdd (langset, lang);
763 otlayout[0] = '\0';
764 for (extra = AREF (spec, FONT_EXTRA_INDEX);
765 CONSP (extra); extra = XCDR (extra))
767 Lisp_Object key, val;
769 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
770 if (EQ (key, QCdpi))
772 if (INTEGERP (val))
773 dpi = XINT (val);
775 else if (EQ (key, QClang))
777 if (! langset)
778 langset = FcLangSetCreate ();
779 if (! langset)
780 goto err;
781 if (SYMBOLP (val))
783 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
784 goto err;
786 else
787 for (; CONSP (val); val = XCDR (val))
788 if (SYMBOLP (XCAR (val))
789 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
790 goto err;
792 else if (EQ (key, QCotf))
794 if (CONSP (val))
796 *otspec = ftfont_get_open_type_spec (val);
797 if (! *otspec)
798 return NULL;
799 strcpy (otlayout, "otlayout:");
800 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
801 script = (*otspec)->script;
804 else if (EQ (key, QCscript))
805 script = val;
806 else if (EQ (key, QCscalable))
807 scalable = ! NILP (val);
810 if (! NILP (script) && ! charset)
812 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
814 if (CONSP (chars) && CONSP (CDR (chars)))
816 charset = FcCharSetCreate ();
817 if (! charset)
818 goto err;
819 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
820 if (CHARACTERP (XCAR (chars))
821 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
822 goto err;
826 pattern = FcPatternCreate ();
827 if (! pattern)
828 goto err;
829 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
830 if (! NILP (tmp)
831 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
832 goto err;
833 tmp = AREF (spec, FONT_FAMILY_INDEX);
834 if (! NILP (tmp)
835 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
836 goto err;
837 if (charset
838 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
839 goto err;
840 if (langset
841 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
842 goto err;
843 if (dpi >= 0
844 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
845 goto err;
846 if (scalable >= 0
847 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
848 goto err;
850 goto finish;
852 err:
853 /* We come here because of unexpected error in fontconfig API call
854 (usually insufficient memory). */
855 if (pattern)
857 FcPatternDestroy (pattern);
858 pattern = NULL;
860 if (*otspec)
862 if ((*otspec)->nfeatures[0] > 0)
863 free ((*otspec)->features[0]);
864 if ((*otspec)->nfeatures[1] > 0)
865 free ((*otspec)->features[1]);
866 free (*otspec);
867 *otspec = NULL;
870 finish:
871 if (langset) FcLangSetDestroy (langset);
872 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
873 return pattern;
876 static Lisp_Object
877 ftfont_list (struct frame *f, Lisp_Object spec)
879 Lisp_Object val = Qnil, family, adstyle;
880 int i;
881 FcPattern *pattern;
882 FcFontSet *fontset = NULL;
883 FcObjectSet *objset = NULL;
884 FcCharSet *charset;
885 Lisp_Object chars = Qnil;
886 char otlayout[15]; /* For "otlayout:XXXX" */
887 struct OpenTypeSpec *otspec = NULL;
888 int spacing = -1;
889 const char *langname = NULL;
891 if (! fc_initialized)
893 FcInit ();
894 fc_initialized = 1;
897 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
898 if (! pattern)
899 return Qnil;
900 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
902 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
903 if (! NILP (val))
905 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
906 if (CONSP (val) && VECTORP (XCDR (val)))
907 chars = XCDR (val);
909 val = Qnil;
911 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
912 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
913 family = AREF (spec, FONT_FAMILY_INDEX);
914 if (! NILP (family))
916 Lisp_Object resolved;
918 resolved = ftfont_resolve_generic_family (family, pattern);
919 if (! NILP (resolved))
921 FcPatternDel (pattern, FC_FAMILY);
922 if (! FcPatternAddString (pattern, FC_FAMILY,
923 SYMBOL_FcChar8 (resolved)))
924 goto err;
927 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
928 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
929 adstyle = Qnil;
930 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
931 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
932 FC_STYLE, FC_FILE, FC_INDEX,
933 #ifdef FC_CAPABILITY
934 FC_CAPABILITY,
935 #endif /* FC_CAPABILITY */
936 #ifdef FC_FONTFORMAT
937 FC_FONTFORMAT,
938 #endif
939 NULL);
940 if (! objset)
941 goto err;
942 if (! NILP (chars))
943 FcObjectSetAdd (objset, FC_CHARSET);
945 fontset = FcFontList (NULL, pattern, objset);
946 if (! fontset || fontset->nfont == 0)
947 goto finish;
948 #if 0
949 /* Need fix because this finds any fonts. */
950 if (fontset->nfont == 0 && ! NILP (family))
952 /* Try matching with configuration. For instance, the
953 configuration may specify "Nimbus Mono L" as an alias of
954 "Courier". */
955 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
956 SYMBOL_FcChar8 (family), NULL);
957 FcChar8 *fam;
959 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
961 for (i = 0;
962 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
963 i++)
965 FcPatternDel (pattern, FC_FAMILY);
966 FcPatternAddString (pattern, FC_FAMILY, fam);
967 FcFontSetDestroy (fontset);
968 fontset = FcFontList (NULL, pattern, objset);
969 if (fontset && fontset->nfont > 0)
970 break;
974 #endif
975 for (i = 0; i < fontset->nfont; i++)
977 Lisp_Object entity;
979 if (spacing >= 0)
981 int this;
983 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
984 == FcResultMatch)
985 && spacing != this)
986 continue;
989 #ifdef FC_CAPABILITY
990 if (otlayout[0])
992 FcChar8 *this;
994 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
995 != FcResultMatch
996 || ! strstr ((char *) this, otlayout))
997 continue;
999 #endif /* FC_CAPABILITY */
1000 #ifdef HAVE_LIBOTF
1001 if (otspec)
1003 FcChar8 *file;
1004 bool passed;
1005 OTF *otf;
1007 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1008 != FcResultMatch)
1009 continue;
1010 otf = OTF_open ((char *) file);
1011 if (! otf)
1012 continue;
1013 passed = (OTF_check_features (otf, 1, otspec->script_tag,
1014 otspec->langsys_tag,
1015 otspec->features[0],
1016 otspec->nfeatures[0]) == 1
1017 && OTF_check_features (otf, 0, otspec->script_tag,
1018 otspec->langsys_tag,
1019 otspec->features[1],
1020 otspec->nfeatures[1]) == 1);
1021 OTF_close (otf);
1022 if (!passed)
1023 continue;
1025 #endif /* HAVE_LIBOTF */
1026 if (VECTORP (chars))
1028 ptrdiff_t j;
1030 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1031 != FcResultMatch)
1032 continue;
1033 for (j = 0; j < ASIZE (chars); j++)
1034 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1035 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1036 break;
1037 if (j == ASIZE (chars))
1038 continue;
1040 if (! NILP (adstyle) || langname)
1042 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1044 if (! NILP (adstyle)
1045 && (NILP (this_adstyle)
1046 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1047 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1048 continue;
1049 if (langname
1050 && ! NILP (this_adstyle)
1051 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1052 continue;
1054 entity = ftfont_pattern_entity (fontset->fonts[i],
1055 AREF (spec, FONT_EXTRA_INDEX));
1056 if (! NILP (entity))
1057 val = Fcons (entity, val);
1059 val = Fnreverse (val);
1060 goto finish;
1062 err:
1063 /* We come here because of unexpected error in fontconfig API call
1064 (usually insufficient memory). */
1065 val = Qnil;
1067 finish:
1068 FONT_ADD_LOG ("ftfont-list", spec, val);
1069 if (objset) FcObjectSetDestroy (objset);
1070 if (fontset) FcFontSetDestroy (fontset);
1071 if (pattern) FcPatternDestroy (pattern);
1072 return val;
1075 static Lisp_Object
1076 ftfont_match (struct frame *f, Lisp_Object spec)
1078 Lisp_Object entity = Qnil;
1079 FcPattern *pattern, *match = NULL;
1080 FcResult result;
1081 char otlayout[15]; /* For "otlayout:XXXX" */
1082 struct OpenTypeSpec *otspec = NULL;
1083 const char *langname = NULL;
1085 if (! fc_initialized)
1087 FcInit ();
1088 fc_initialized = 1;
1091 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1092 if (! pattern)
1093 return Qnil;
1095 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1097 FcValue value;
1099 value.type = FcTypeDouble;
1100 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1101 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1103 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1105 FcDefaultSubstitute (pattern);
1106 match = FcFontMatch (NULL, pattern, &result);
1107 if (match)
1109 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1110 FcPatternDestroy (match);
1111 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1112 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1113 ftfont_generic_family_list))
1114 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1115 AREF (entity, FONT_FAMILY_INDEX))))
1116 entity = Qnil;
1119 FcPatternDestroy (pattern);
1121 FONT_ADD_LOG ("ftfont-match", spec, entity);
1122 return entity;
1125 static Lisp_Object
1126 ftfont_list_family (struct frame *f)
1128 Lisp_Object list = Qnil;
1129 FcPattern *pattern = NULL;
1130 FcFontSet *fontset = NULL;
1131 FcObjectSet *objset = NULL;
1132 int i;
1134 if (! fc_initialized)
1136 FcInit ();
1137 fc_initialized = 1;
1140 pattern = FcPatternCreate ();
1141 if (! pattern)
1142 goto finish;
1143 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1144 if (! objset)
1145 goto finish;
1146 fontset = FcFontList (NULL, pattern, objset);
1147 if (! fontset)
1148 goto finish;
1150 for (i = 0; i < fontset->nfont; i++)
1152 FcPattern *pat = fontset->fonts[i];
1153 FcChar8 *str;
1155 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1156 list = Fcons (intern ((char *) str), list);
1159 finish:
1160 if (objset) FcObjectSetDestroy (objset);
1161 if (fontset) FcFontSetDestroy (fontset);
1162 if (pattern) FcPatternDestroy (pattern);
1164 return list;
1168 Lisp_Object
1169 ftfont_open2 (struct frame *f,
1170 Lisp_Object entity,
1171 int pixel_size,
1172 Lisp_Object font_object)
1174 struct ftfont_info *ftfont_info;
1175 struct font *font;
1176 struct ftfont_cache_data *cache_data;
1177 FT_Face ft_face;
1178 FT_Size ft_size;
1179 FT_UInt size;
1180 Lisp_Object val, filename, idx, cache;
1181 bool scalable;
1182 int spacing;
1183 int i;
1184 double upEM;
1186 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1187 if (! CONSP (val))
1188 return Qnil;
1189 val = XCDR (val);
1190 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1191 if (NILP (cache))
1192 return Qnil;
1193 filename = XCAR (val);
1194 idx = XCDR (val);
1195 val = XCDR (cache);
1196 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1197 ft_face = cache_data->ft_face;
1198 if (XSAVE_INTEGER (val, 1) > 0)
1200 /* FT_Face in this cache is already used by the different size. */
1201 if (FT_New_Size (ft_face, &ft_size) != 0)
1202 return Qnil;
1203 if (FT_Activate_Size (ft_size) != 0)
1205 FT_Done_Size (ft_size);
1206 return Qnil;
1209 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1210 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1211 if (size == 0)
1212 size = pixel_size;
1213 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1215 if (XSAVE_INTEGER (val, 1) == 0)
1216 FT_Done_Face (ft_face);
1217 return Qnil;
1220 ASET (font_object, FONT_FILE_INDEX, filename);
1221 font = XFONT_OBJECT (font_object);
1222 ftfont_info = (struct ftfont_info *) font;
1223 ftfont_info->ft_size = ft_face->size;
1224 ftfont_info->index = XINT (idx);
1225 #ifdef HAVE_LIBOTF
1226 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1227 ftfont_info->otf = NULL;
1228 #endif /* HAVE_LIBOTF */
1229 /* This means that there's no need of transformation. */
1230 ftfont_info->matrix.xx = 0;
1231 font->pixel_size = size;
1232 font->driver = &ftfont_driver;
1233 font->encoding_charset = font->repertory_charset = -1;
1235 upEM = ft_face->units_per_EM;
1236 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1237 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1238 if (scalable)
1240 font->ascent = ft_face->ascender * size / upEM + 0.5;
1241 font->descent = - ft_face->descender * size / upEM + 0.5;
1242 font->height = ft_face->height * size / upEM + 0.5;
1244 else
1246 font->ascent = ft_face->size->metrics.ascender >> 6;
1247 font->descent = - ft_face->size->metrics.descender >> 6;
1248 font->height = ft_face->size->metrics.height >> 6;
1250 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1251 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1252 else
1253 spacing = FC_PROPORTIONAL;
1254 if (spacing != FC_PROPORTIONAL
1255 #ifdef FC_DUAL
1256 && spacing != FC_DUAL
1257 #endif /* FC_DUAL */
1259 font->min_width = font->average_width = font->space_width
1260 = (scalable ? ft_face->max_advance_width * size / upEM + 0.5
1261 : ft_face->size->metrics.max_advance >> 6);
1262 else
1264 int n;
1266 font->min_width = font->average_width = font->space_width = 0;
1267 for (i = 32, n = 0; i < 127; i++)
1268 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1270 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1272 if (this_width > 0
1273 && (! font->min_width || font->min_width > this_width))
1274 font->min_width = this_width;
1275 if (i == 32)
1276 font->space_width = this_width;
1277 font->average_width += this_width;
1278 n++;
1280 if (n > 0)
1281 font->average_width /= n;
1284 font->baseline_offset = 0;
1285 font->relative_compose = 0;
1286 font->default_ascent = 0;
1287 font->vertical_centering = 0;
1288 if (scalable)
1290 font->underline_position = (-ft_face->underline_position * size / upEM
1291 + 0.5);
1292 font->underline_thickness = (ft_face->underline_thickness * size / upEM
1293 + 0.5);
1295 else
1297 font->underline_position = -1;
1298 font->underline_thickness = 0;
1301 return font_object;
1304 static Lisp_Object
1305 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1307 Lisp_Object font_object;
1308 FT_UInt size;
1309 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1310 if (size == 0)
1311 size = pixel_size;
1312 font_object = font_build_object (VECSIZE (struct ftfont_info),
1313 Qfreetype, entity, size);
1314 return ftfont_open2 (f, entity, pixel_size, font_object);
1317 static void
1318 ftfont_close (struct font *font)
1320 /* FIXME: Although this function can be called while garbage-collecting,
1321 the function assumes that Lisp data structures are properly-formed.
1322 This invalid assumption can lead to core dumps (Bug#20890). */
1324 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1325 Lisp_Object val, cache;
1327 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1328 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1329 eassert (CONSP (cache));
1330 val = XCDR (cache);
1331 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1332 if (XSAVE_INTEGER (val, 1) == 0)
1334 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1336 FT_Done_Face (cache_data->ft_face);
1337 #ifdef HAVE_LIBOTF
1338 if (ftfont_info->otf)
1339 OTF_close (ftfont_info->otf);
1340 #endif
1341 cache_data->ft_face = NULL;
1343 else
1344 FT_Done_Size (ftfont_info->ft_size);
1347 static int
1348 ftfont_has_char (Lisp_Object font, int c)
1350 struct charset *cs = NULL;
1352 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1353 && charset_jisx0208 >= 0)
1354 cs = CHARSET_FROM_ID (charset_jisx0208);
1355 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1356 && charset_ksc5601 >= 0)
1357 cs = CHARSET_FROM_ID (charset_ksc5601);
1358 if (cs)
1359 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1361 if (FONT_ENTITY_P (font))
1363 FcCharSet *charset = ftfont_get_fc_charset (font);
1365 return (FcCharSetHasChar (charset, c) == FcTrue);
1367 else
1369 struct ftfont_info *ftfont_info;
1371 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1372 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1373 != 0);
1377 static unsigned
1378 ftfont_encode_char (struct font *font, int c)
1380 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1381 FT_Face ft_face = ftfont_info->ft_size->face;
1382 FT_ULong charcode = c;
1383 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1385 return (code > 0 ? code : FONT_INVALID_CODE);
1388 static void
1389 ftfont_text_extents (struct font *font, unsigned int *code,
1390 int nglyphs, struct font_metrics *metrics)
1392 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1393 FT_Face ft_face = ftfont_info->ft_size->face;
1394 int i, width = 0;
1395 bool first;
1397 if (ftfont_info->ft_size != ft_face->size)
1398 FT_Activate_Size (ftfont_info->ft_size);
1400 for (i = 0, first = 1; i < nglyphs; i++)
1402 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1404 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1406 if (first)
1408 metrics->lbearing = m->horiBearingX >> 6;
1409 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1410 metrics->ascent = m->horiBearingY >> 6;
1411 metrics->descent = (m->height - m->horiBearingY) >> 6;
1412 first = 0;
1414 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1415 metrics->lbearing = width + (m->horiBearingX >> 6);
1416 if (metrics->rbearing
1417 < width + ((m->horiBearingX + m->width) >> 6))
1418 metrics->rbearing
1419 = width + ((m->horiBearingX + m->width) >> 6);
1420 if (metrics->ascent < (m->horiBearingY >> 6))
1421 metrics->ascent = m->horiBearingY >> 6;
1422 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1423 metrics->descent = (m->height - m->horiBearingY) >> 6;
1424 width += m->horiAdvance >> 6;
1426 else
1427 width += font->space_width;
1429 metrics->width = width;
1432 static int
1433 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1435 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1436 FT_Face ft_face = ftfont_info->ft_size->face;
1437 FT_Int32 load_flags = FT_LOAD_RENDER;
1439 if (ftfont_info->ft_size != ft_face->size)
1440 FT_Activate_Size (ftfont_info->ft_size);
1441 if (bits_per_pixel == 1)
1443 #ifdef FT_LOAD_TARGET_MONO
1444 load_flags |= FT_LOAD_TARGET_MONO;
1445 #else
1446 load_flags |= FT_LOAD_MONOCHROME;
1447 #endif
1449 else if (bits_per_pixel != 8)
1450 /* We don't support such a rendering. */
1451 return -1;
1453 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1454 return -1;
1455 bitmap->bits_per_pixel
1456 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1457 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1458 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1459 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1460 : -1);
1461 if (bitmap->bits_per_pixel < 0)
1462 /* We don't support that kind of pixel mode. */
1463 return -1;
1464 bitmap->rows = ft_face->glyph->bitmap.rows;
1465 bitmap->width = ft_face->glyph->bitmap.width;
1466 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1467 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1468 bitmap->left = ft_face->glyph->bitmap_left;
1469 bitmap->top = ft_face->glyph->bitmap_top;
1470 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1472 return 0;
1475 static int
1476 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1477 int *x, int *y)
1479 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1480 FT_Face ft_face = ftfont_info->ft_size->face;
1482 if (ftfont_info->ft_size != ft_face->size)
1483 FT_Activate_Size (ftfont_info->ft_size);
1484 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1485 return -1;
1486 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1487 return -1;
1488 if (idx >= ft_face->glyph->outline.n_points)
1489 return -1;
1490 *x = ft_face->glyph->outline.points[idx].x;
1491 *y = ft_face->glyph->outline.points[idx].y;
1492 return 0;
1495 #ifdef HAVE_LIBOTF
1497 static Lisp_Object
1498 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1500 Lisp_Object scripts, langsyses, features, sym;
1501 int i, j, k, l;
1503 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1505 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1507 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1509 OTF_LangSys *otf_langsys;
1511 if (j >= 0)
1512 otf_langsys = otf_script->LangSys + j;
1513 else if (otf_script->DefaultLangSysOffset)
1514 otf_langsys = &otf_script->DefaultLangSys;
1515 else
1516 break;
1518 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1520 l = otf_langsys->FeatureIndex[k];
1521 if (l >= gsub_gpos->FeatureList.FeatureCount)
1522 continue;
1523 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1524 features = Fcons (sym, features);
1526 if (j >= 0)
1527 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1528 else
1529 sym = Qnil;
1530 langsyses = Fcons (Fcons (sym, features), langsyses);
1533 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1534 scripts = Fcons (Fcons (sym, langsyses), scripts);
1536 return scripts;
1541 static Lisp_Object
1542 ftfont_otf_capability (struct font *font)
1544 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1545 OTF *otf = ftfont_get_otf (ftfont_info);
1546 Lisp_Object gsub_gpos;
1548 if (! otf)
1549 return Qnil;
1550 gsub_gpos = Fcons (Qnil, Qnil);
1551 if (OTF_get_table (otf, "GSUB") == 0
1552 && otf->gsub->FeatureList.FeatureCount > 0)
1553 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1554 if (OTF_get_table (otf, "GPOS") == 0
1555 && otf->gpos->FeatureList.FeatureCount > 0)
1556 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1557 return gsub_gpos;
1560 #ifdef HAVE_M17N_FLT
1562 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1563 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1564 /* We can use the new feature of libotf and m17n-flt to handle the
1565 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1566 some Agian scripts. */
1567 #define M17N_FLT_USE_NEW_FEATURE
1568 #endif
1570 struct MFLTFontFT
1572 MFLTFont flt_font;
1573 struct font *font;
1574 FT_Face ft_face;
1575 OTF *otf;
1576 FT_Matrix *matrix;
1579 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1580 We use this structure instead of MFLTGlyph to utilize the new
1581 feature of libotf ver.0.9.15 which requires saving and restoring
1582 the value of OTF_GlyphString.positioning_type in the succeeding
1583 calls of the callback function MFLTFont.drive_otf (which is set to
1584 ftfont_drive_otf). */
1586 typedef struct {
1587 MFLTGlyph g;
1588 unsigned int libotf_positioning_type;
1589 } MFLTGlyphFT;
1591 static int
1592 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1593 int from, int to)
1595 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1596 FT_Face ft_face = flt_font_ft->ft_face;
1597 MFLTGlyphFT *g;
1599 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1600 if (! g->g.encoded)
1602 FT_UInt code = FT_Get_Char_Index (ft_face, g->g.code);
1604 g->g.code = code > 0 ? code : FONT_INVALID_CODE;
1605 g->g.encoded = 1;
1607 return 0;
1610 /* Operators for 26.6 fixed fractional pixel format */
1612 #define FLOOR(x) ((x) & -64)
1613 #define CEIL(x) (((x)+63) & -64)
1614 #define ROUND(x) (((x)+32) & -64)
1616 static int
1617 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1618 int from, int to)
1620 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1621 FT_Face ft_face = flt_font_ft->ft_face;
1622 MFLTGlyphFT *g;
1624 for (g = (MFLTGlyphFT *) (gstring->glyphs) + from; from < to; g++, from++)
1625 if (! g->g.measured)
1627 if (g->g.code != FONT_INVALID_CODE)
1629 FT_Glyph_Metrics *m;
1631 if (FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_DEFAULT) != 0)
1632 emacs_abort ();
1633 m = &ft_face->glyph->metrics;
1634 if (flt_font_ft->matrix)
1636 FT_Vector v[4];
1637 int i;
1639 v[0].x = v[1].x = m->horiBearingX;
1640 v[2].x = v[3].x = m->horiBearingX + m->width;
1641 v[0].y = v[2].y = m->horiBearingY;
1642 v[1].y = v[3].y = m->horiBearingY - m->height;
1643 for (i = 0; i < 4; i++)
1644 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1645 g->g.lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1646 g->g.rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1647 g->g.ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1648 g->g.descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1650 else
1652 g->g.lbearing = FLOOR (m->horiBearingX);
1653 g->g.rbearing = CEIL (m->horiBearingX + m->width);
1654 g->g.ascent = CEIL (m->horiBearingY);
1655 g->g.descent = - FLOOR (m->horiBearingY - m->height);
1657 g->g.xadv = ROUND (ft_face->glyph->advance.x);
1659 else
1661 g->g.lbearing = 0;
1662 g->g.rbearing = g->g.xadv = flt_font_ft->font->space_width << 6;
1663 g->g.ascent = flt_font_ft->font->ascent << 6;
1664 g->g.descent = flt_font_ft->font->descent << 6;
1666 g->g.yadv = 0;
1667 g->g.measured = 1;
1669 return 0;
1672 static int
1673 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1675 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1677 #define FEATURE_ANY(IDX) \
1678 (spec->features[IDX] \
1679 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1681 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1682 OTF *otf = flt_font_ft->otf;
1683 OTF_Tag *tags;
1684 int i, n;
1685 bool negative;
1687 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1688 /* Return true iff any of GSUB or GPOS support the script (and
1689 language). */
1690 return (otf
1691 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1692 NULL, 0) > 0
1693 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1694 NULL, 0) > 0));
1696 for (i = 0; i < 2; i++)
1697 if (! FEATURE_ANY (i))
1699 if (FEATURE_NONE (i))
1701 if (otf
1702 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1703 NULL, 0) > 0)
1704 return 0;
1705 continue;
1707 if (spec->features[i][0] == 0xFFFFFFFF)
1709 if (! otf
1710 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1711 NULL, 0) <= 0)
1712 continue;
1714 else if (! otf)
1715 return 0;
1716 for (n = 1; spec->features[i][n]; n++);
1717 USE_SAFE_ALLOCA;
1718 SAFE_NALLOCA (tags, 1, n);
1719 for (n = 0, negative = 0; spec->features[i][n]; n++)
1721 if (spec->features[i][n] == 0xFFFFFFFF)
1722 negative = 1;
1723 else if (negative)
1724 tags[n - 1] = spec->features[i][n] | 0x80000000;
1725 else
1726 tags[n] = spec->features[i][n];
1728 bool passed = true;
1729 #ifndef M17N_FLT_USE_NEW_FEATURE
1730 passed = n - negative > 0;
1731 #endif
1732 if (passed)
1733 passed = (OTF_check_features (otf, i == 0, spec->script,
1734 spec->langsys, tags, n - negative)
1735 != 1);
1736 SAFE_FREE ();
1737 if (passed)
1738 return 0;
1740 return 1;
1741 #undef FEATURE_NONE
1742 #undef FEATURE_ANY
1745 #define DEVICE_DELTA(table, size) \
1746 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1747 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1748 : 0)
1750 static void
1751 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1752 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1754 if (anchor->AnchorFormat == 2)
1756 FT_Outline *outline;
1757 int ap = anchor->f.f1.AnchorPoint;
1759 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1760 outline = &ft_face->glyph->outline;
1761 if (ap < outline->n_points)
1763 *x = outline->points[ap].x << 6;
1764 *y = outline->points[ap].y << 6;
1767 else if (anchor->AnchorFormat == 3)
1769 if (anchor->f.f2.XDeviceTable.offset
1770 && anchor->f.f2.XDeviceTable.DeltaValue)
1771 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1772 if (anchor->f.f2.YDeviceTable.offset
1773 && anchor->f.f2.YDeviceTable.DeltaValue)
1774 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1778 static OTF_GlyphString otf_gstring;
1780 static void
1781 setup_otf_gstring (int size)
1783 if (otf_gstring.size < size)
1785 ptrdiff_t new_size = otf_gstring.size;
1786 xfree (otf_gstring.glyphs);
1787 otf_gstring.glyphs = xpalloc (NULL, &new_size, size - otf_gstring.size,
1788 INT_MAX, sizeof *otf_gstring.glyphs);
1789 otf_gstring.size = new_size;
1791 otf_gstring.used = size;
1792 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1795 #ifdef M17N_FLT_USE_NEW_FEATURE
1797 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1798 #define PACK_OTF_TAG(TAG) \
1799 ((((TAG) & 0x7F000000) >> 3) \
1800 | (((TAG) & 0x7F0000) >> 2) \
1801 | (((TAG) & 0x7F00) >> 1) \
1802 | ((TAG) & 0x7F))
1804 /* Assuming that FONT is an OpenType font, apply OpenType features
1805 specified in SPEC on glyphs between FROM and TO of IN, and record
1806 the lastly applied feature in each glyph of IN. If OUT is not
1807 NULL, append the resulting glyphs to OUT while storing glyph
1808 position adjustment information in ADJUSTMENT. */
1810 static int
1811 ftfont_drive_otf (MFLTFont *font,
1812 MFLTOtfSpec *spec,
1813 MFLTGlyphString *in,
1814 int from,
1815 int to,
1816 MFLTGlyphString *out,
1817 MFLTGlyphAdjustment *adjustment)
1819 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1820 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
1821 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
1822 FT_Face ft_face = flt_font_ft->ft_face;
1823 OTF *otf = flt_font_ft->otf;
1824 int len = to - from;
1825 int i, j, gidx;
1826 OTF_Glyph *otfg;
1827 char script[5], *langsys = NULL;
1828 char *gsub_features = NULL, *gpos_features = NULL;
1829 OTF_Feature *features;
1831 if (len == 0)
1832 return from;
1833 OTF_tag_name (spec->script, script);
1835 char langsysbuf[5];
1836 if (spec->langsys)
1838 langsys = langsysbuf;
1839 OTF_tag_name (spec->langsys, langsys);
1842 USE_SAFE_ALLOCA;
1843 for (i = 0; i < 2; i++)
1845 char *p;
1847 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1849 for (j = 0; spec->features[i][j]; j++);
1850 SAFE_NALLOCA (p, 6, j);
1851 if (i == 0)
1852 gsub_features = p;
1853 else
1854 gpos_features = p;
1855 for (j = 0; spec->features[i][j]; j++)
1857 if (spec->features[i][j] == 0xFFFFFFFF)
1858 *p++ = '*', *p++ = ',';
1859 else
1861 OTF_tag_name (spec->features[i][j], p);
1862 p[4] = ',';
1863 p += 5;
1866 *--p = '\0';
1870 setup_otf_gstring (len);
1871 for (i = 0; i < len; i++)
1873 otf_gstring.glyphs[i].c = in_glyphs[i].g.c & 0x11FFFF;
1874 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
1875 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1876 otf_gstring.glyphs[i].positioning_type = in_glyphs[i].libotf_positioning_type;
1877 #endif
1880 OTF_drive_gdef (otf, &otf_gstring);
1881 gidx = out ? out->used : from;
1883 if (gsub_features && out)
1885 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1886 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1887 gsub_features) < 0)
1888 goto simple_copy;
1889 #else
1890 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1891 gsub_features) < 0)
1892 goto simple_copy;
1893 #endif
1894 if (out->allocated < out->used + otf_gstring.used)
1896 SAFE_FREE ();
1897 return -2;
1899 features = otf->gsub->FeatureList.Feature;
1900 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1902 MFLTGlyphFT *g;
1903 int min_from, max_to;
1904 int feature_idx;
1906 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1907 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1908 #else
1909 feature_idx = otfg->positioning_type >> 4;
1910 #endif
1911 g = out_glyphs + out->used;
1912 *g = in_glyphs[otfg->f.index.from];
1913 if (g->g.code != otfg->glyph_id)
1915 g->g.c = 0;
1916 g->g.code = otfg->glyph_id;
1917 g->g.measured = 0;
1919 out->used++;
1920 min_from = g->g.from;
1921 max_to = g->g.to;
1922 if (otfg->f.index.from < otfg->f.index.to)
1924 /* OTFG substitutes multiple glyphs in IN. */
1925 for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
1927 if (min_from > in_glyphs[j].g.from)
1928 min_from = in_glyphs[j].g.from;
1929 if (max_to < in_glyphs[j].g.to)
1930 max_to = in_glyphs[j].g.to;
1932 g->g.from = min_from;
1933 g->g.to = max_to;
1935 if (feature_idx)
1937 unsigned int tag = features[feature_idx - 1].FeatureTag;
1938 tag = PACK_OTF_TAG (tag);
1939 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1941 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1942 g->libotf_positioning_type
1943 = otfg->positioning_type & OTF_positioning_type_components_mask;
1944 #endif
1945 for (i++, otfg++; (i < otf_gstring.used
1946 && otfg->f.index.from == otfg[-1].f.index.from);
1947 i++, otfg++)
1949 g = out_glyphs + out->used;
1950 *g = in_glyphs[otfg->f.index.to];
1951 if (g->g.code != otfg->glyph_id)
1953 g->g.c = 0;
1954 g->g.code = otfg->glyph_id;
1955 g->g.measured = 0;
1957 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1958 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1959 #else
1960 feature_idx = otfg->positioning_type >> 4;
1961 #endif
1962 if (feature_idx)
1964 unsigned int tag = features[feature_idx - 1].FeatureTag;
1965 tag = PACK_OTF_TAG (tag);
1966 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
1968 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1969 g->libotf_positioning_type
1970 = otfg->positioning_type & OTF_positioning_type_components_mask;
1971 #endif
1972 out->used++;
1976 else if (gsub_features)
1978 /* Just for checking which features will be applied. */
1979 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1980 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
1981 gsub_features) < 0)
1982 goto simple_copy;
1983 #else
1984 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1985 gsub_features) < 0)
1986 goto simple_copy;
1987 #endif
1988 features = otf->gsub->FeatureList.Feature;
1989 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1990 otfg++)
1992 int feature_idx;
1993 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1994 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
1995 #else
1996 feature_idx = otfg->positioning_type >> 4;
1997 #endif
1998 if (feature_idx)
2000 unsigned int tag = features[feature_idx - 1].FeatureTag;
2001 tag = PACK_OTF_TAG (tag);
2002 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2004 MFLTGlyphFT *g = in_glyphs + j;
2005 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2010 else if (out)
2012 if (out->allocated < out->used + len)
2014 SAFE_FREE ();
2015 return -2;
2017 for (i = 0; i < len; i++)
2018 out_glyphs[out->used++] = in_glyphs[i];
2021 if (gpos_features && out)
2023 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
2024 int x_ppem, y_ppem, x_scale, y_scale;
2026 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2027 if (OTF_drive_gpos_features (otf, &otf_gstring, script, langsys,
2028 gpos_features) < 0)
2030 SAFE_FREE ();
2031 return to;
2033 #else
2034 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2035 gpos_features) < 0)
2037 SAFE_FREE ();
2038 return to;
2040 #endif
2041 features = otf->gpos->FeatureList.Feature;
2042 x_ppem = ft_face->size->metrics.x_ppem;
2043 y_ppem = ft_face->size->metrics.y_ppem;
2044 x_scale = ft_face->size->metrics.x_scale;
2045 y_scale = ft_face->size->metrics.y_scale;
2047 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2048 i < otf_gstring.used; i++, otfg++)
2050 MFLTGlyphAdjustment *adjust = adjustment;
2051 MFLTGlyphFT *prev;
2052 int positioning_type, feature_idx;
2054 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2055 positioning_type = OTF_POSITIONING_TYPE_GET_FORMAT (otfg);
2056 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
2057 #else
2058 positioning_type = otfg->positioning_type & 0xF;
2059 feature_idx = otfg->positioning_type >> 4;
2060 #endif
2061 if (feature_idx)
2063 unsigned int tag = features[feature_idx - 1].FeatureTag;
2064 tag = PACK_OTF_TAG (tag);
2065 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2068 if (! otfg->glyph_id)
2069 /* This is a pseudo glyph that contains positioning
2070 information to be accumulated to a real glyph. */
2071 adjust--;
2072 switch (positioning_type)
2074 case 0:
2075 break;
2076 case 1: /* Single */
2077 case 2: /* Pair */
2079 int format = otfg->f.f1.format;
2081 if (format & OTF_XPlacement)
2082 adjust->xoff
2083 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2084 if (format & OTF_XPlaDevice)
2085 adjust->xoff
2086 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2087 if (format & OTF_YPlacement)
2088 adjust->yoff
2089 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2090 if (format & OTF_YPlaDevice)
2091 adjust->yoff
2092 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2093 if (format & OTF_XAdvance)
2094 adjust->xadv
2095 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2096 if (format & OTF_XAdvDevice)
2097 adjust->xadv
2098 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2099 if (format & OTF_YAdvance)
2100 adjust->yadv
2101 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2102 if (format & OTF_YAdvDevice)
2103 adjust->yadv
2104 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2105 adjust->set = 1;
2107 break;
2108 case 3: /* Cursive */
2109 /* Not yet supported. */
2110 break;
2111 case 4: /* Mark-to-Base */
2112 case 5: /* Mark-to-Ligature */
2113 if (! base)
2114 break;
2115 prev = base;
2116 goto label_adjust_anchor;
2117 default: /* i.e. case 6 Mark-to-Mark */
2118 if (! mark)
2119 break;
2120 prev = mark;
2121 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2123 int distance = OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg);
2125 if (distance > 0)
2127 prev = g - distance;
2128 if (prev < out_glyphs)
2129 prev = mark;
2132 #endif
2134 label_adjust_anchor:
2136 int base_x, base_y, mark_x, mark_y;
2137 int this_from, this_to;
2139 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2140 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2141 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2142 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2144 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2145 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2146 x_ppem, y_ppem, &base_x, &base_y);
2147 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2148 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2149 x_ppem, y_ppem, &mark_x, &mark_y);
2150 adjust->xoff = (base_x - mark_x);
2151 adjust->yoff = - (base_y - mark_y);
2152 adjust->back = (g - prev);
2153 adjust->xadv = 0;
2154 adjust->advance_is_absolute = 1;
2155 adjust->set = 1;
2156 this_from = g->g.from;
2157 this_to = g->g.to;
2158 for (j = 0; prev + j < g; j++)
2160 if (this_from > prev[j].g.from)
2161 this_from = prev[j].g.from;
2162 if (this_to < prev[j].g.to)
2163 this_to = prev[j].g.to;
2165 for (; prev <= g; prev++)
2167 prev->g.from = this_from;
2168 prev->g.to = this_to;
2172 if (otfg->glyph_id)
2174 if (otfg->GlyphClass == OTF_GlyphClass0)
2175 base = mark = g;
2176 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2177 mark = g;
2178 else
2179 base = g;
2180 g++, adjustment++;
2184 else if (gpos_features)
2186 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2187 gpos_features) < 0)
2189 SAFE_FREE ();
2190 return to;
2192 features = otf->gpos->FeatureList.Feature;
2193 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2194 i++, otfg++)
2195 if (otfg->positioning_type & 0xF)
2197 int feature_idx = otfg->positioning_type >> 4;
2199 if (feature_idx)
2201 unsigned int tag = features[feature_idx - 1].FeatureTag;
2202 tag = PACK_OTF_TAG (tag);
2203 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2205 MFLTGlyphFT *g = in_glyphs + j;
2206 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2211 SAFE_FREE ();
2212 return to;
2214 simple_copy:
2215 SAFE_FREE ();
2216 if (! out)
2217 return to;
2218 if (out->allocated < out->used + len)
2219 return -2;
2220 font->get_metrics (font, in, from, to);
2221 memcpy (out->glyphs + out->used, in_glyphs, sizeof (MFLTGlyphFT) * len);
2222 out->used += len;
2223 return to;
2226 static int
2227 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2228 MFLTGlyphString *in, int from, int to)
2230 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2233 #else /* not M17N_FLT_USE_NEW_FEATURE */
2235 static int
2236 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2237 int from, int to,
2238 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2240 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2241 MFLTGlyphFT *in_glyphs = (MFLTGlyphFT *) (in->glyphs) + from;
2242 MFLTGlyphFT *out_glyphs = out ? (MFLTGlyphFT *) (out->glyphs) : NULL;
2243 FT_Face ft_face = flt_font_ft->ft_face;
2244 OTF *otf = flt_font_ft->otf;
2245 int len = to - from;
2246 int i, j, gidx;
2247 OTF_Glyph *otfg;
2248 char script[5], *langsys = NULL;
2249 char *gsub_features = NULL, *gpos_features = NULL;
2251 if (len == 0)
2252 return from;
2253 OTF_tag_name (spec->script, script);
2255 char langsysbuf[5];
2256 if (spec->langsys)
2258 langsys = langsysbuf;
2259 OTF_tag_name (spec->langsys, langsys);
2262 USE_SAFE_ALLOCA;
2263 for (i = 0; i < 2; i++)
2265 char *p;
2267 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2269 for (j = 0; spec->features[i][j]; j++);
2270 SAFE_NALLOCA (p, 6, j);
2271 if (i == 0)
2272 gsub_features = p;
2273 else
2274 gpos_features = p;
2275 for (j = 0; spec->features[i][j]; j++)
2277 if (spec->features[i][j] == 0xFFFFFFFF)
2278 *p++ = '*', *p++ = ',';
2279 else
2281 OTF_tag_name (spec->features[i][j], p);
2282 p[4] = ',';
2283 p += 5;
2286 *--p = '\0';
2290 setup_otf_gstring (len);
2291 for (i = 0; i < len; i++)
2293 otf_gstring.glyphs[i].c = in_glyphs[i].g.c;
2294 otf_gstring.glyphs[i].glyph_id = in_glyphs[i].g.code;
2297 OTF_drive_gdef (otf, &otf_gstring);
2298 gidx = out->used;
2300 if (gsub_features)
2302 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2303 < 0)
2304 goto simple_copy;
2305 if (out->allocated < out->used + otf_gstring.used)
2307 SAFE_FREE ();
2308 return -2;
2310 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2312 MFLTGlyphFT *g;
2313 int min_from, max_to;
2314 int j;
2316 g = out_glyphs + out->used;
2317 *g = in_glyphs[otfg->f.index.from];
2318 if (g->g.code != otfg->glyph_id)
2320 g->g.c = 0;
2321 g->g.code = otfg->glyph_id;
2322 g->g.measured = 0;
2324 out->used++;
2325 min_from = g->g.from;
2326 max_to = g->g.to;
2327 if (otfg->f.index.from < otfg->f.index.to)
2329 /* OTFG substitutes multiple glyphs in IN. */
2330 for (j = from + otfg->f.index.from + 1;
2331 j <= from + otfg->f.index.to; j++)
2333 if (min_from > in->glyphs[j].from)
2334 min_from = in->glyphs[j].from;
2335 if (max_to < in->glyphs[j].to)
2336 max_to = in->glyphs[j].to;
2338 g->g.from = min_from;
2339 g->g.to = max_to;
2341 for (i++, otfg++; (i < otf_gstring.used
2342 && otfg->f.index.from == otfg[-1].f.index.from);
2343 i++, otfg++)
2345 g = out_glyphs + out->used;
2346 *g = in_glyphs[otfg->f.index.to];
2347 if (g->g.code != otfg->glyph_id)
2349 g->g.c = 0;
2350 g->g.code = otfg->glyph_id;
2351 g->g.measured = 0;
2353 out->used++;
2357 else
2359 if (out->allocated < out->used + len)
2361 SAFE_FREE ();
2362 return -2;
2364 for (i = 0; i < len; i++)
2365 out_glyphs[out->used++] = in_glyphs[i];
2368 if (gpos_features)
2370 MFLTGlyphFT *base = NULL, *mark = NULL, *g;
2371 int x_ppem, y_ppem, x_scale, y_scale;
2373 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2374 < 0)
2376 SAFE_FREE ();
2377 return to;
2380 x_ppem = ft_face->size->metrics.x_ppem;
2381 y_ppem = ft_face->size->metrics.y_ppem;
2382 x_scale = ft_face->size->metrics.x_scale;
2383 y_scale = ft_face->size->metrics.y_scale;
2385 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2386 i < otf_gstring.used; i++, otfg++, g++)
2388 MFLTGlyphFT *prev;
2390 if (! otfg->glyph_id)
2391 continue;
2392 switch (otfg->positioning_type)
2394 case 0:
2395 break;
2396 case 1: /* Single */
2397 case 2: /* Pair */
2399 int format = otfg->f.f1.format;
2401 if (format & OTF_XPlacement)
2402 adjustment[i].xoff
2403 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2404 if (format & OTF_XPlaDevice)
2405 adjustment[i].xoff
2406 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2407 if (format & OTF_YPlacement)
2408 adjustment[i].yoff
2409 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2410 if (format & OTF_YPlaDevice)
2411 adjustment[i].yoff
2412 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2413 if (format & OTF_XAdvance)
2414 adjustment[i].xadv
2415 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2416 if (format & OTF_XAdvDevice)
2417 adjustment[i].xadv
2418 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2419 if (format & OTF_YAdvance)
2420 adjustment[i].yadv
2421 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2422 if (format & OTF_YAdvDevice)
2423 adjustment[i].yadv
2424 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2425 adjustment[i].set = 1;
2427 break;
2428 case 3: /* Cursive */
2429 /* Not yet supported. */
2430 break;
2431 case 4: /* Mark-to-Base */
2432 case 5: /* Mark-to-Ligature */
2433 if (! base)
2434 break;
2435 prev = base;
2436 goto label_adjust_anchor;
2437 default: /* i.e. case 6 Mark-to-Mark */
2438 if (! mark)
2439 break;
2440 prev = mark;
2442 label_adjust_anchor:
2444 int base_x, base_y, mark_x, mark_y;
2445 int this_from, this_to;
2447 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2448 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2449 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2450 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2452 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2453 adjust_anchor (ft_face, otfg->f.f4.base_anchor, prev->g.code,
2454 x_ppem, y_ppem, &base_x, &base_y);
2455 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2456 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->g.code,
2457 x_ppem, y_ppem, &mark_x, &mark_y);
2458 adjustment[i].xoff = (base_x - mark_x);
2459 adjustment[i].yoff = - (base_y - mark_y);
2460 adjustment[i].back = (g - prev);
2461 adjustment[i].xadv = 0;
2462 adjustment[i].advance_is_absolute = 1;
2463 adjustment[i].set = 1;
2464 this_from = g->g.from;
2465 this_to = g->g.to;
2466 for (j = 0; prev + j < g; j++)
2468 if (this_from > prev[j].g.from)
2469 this_from = prev[j].g.from;
2470 if (this_to < prev[j].g.to)
2471 this_to = prev[j].g.to;
2473 for (; prev <= g; prev++)
2475 prev->g.from = this_from;
2476 prev->g.to = this_to;
2480 if (otfg->GlyphClass == OTF_GlyphClass0)
2481 base = mark = g;
2482 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2483 mark = g;
2484 else
2485 base = g;
2488 SAFE_FREE ();
2489 return to;
2491 simple_copy:
2492 SAFE_FREE ();
2493 if (out->allocated < out->used + len)
2494 return -2;
2495 font->get_metrics (font, in, from, to);
2496 memcpy (out_glyphs + out->used, in_glyphs,
2497 sizeof (MFLTGlyphFT) * len);
2498 out->used += len;
2499 return to;
2502 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2504 static MFLTGlyphString gstring;
2506 static bool m17n_flt_initialized;
2508 static Lisp_Object
2509 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2510 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2512 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2513 ptrdiff_t i;
2514 struct MFLTFontFT flt_font_ft;
2515 MFLT *flt = NULL;
2516 bool with_variation_selector = false;
2518 if (! m17n_flt_initialized)
2520 M17N_INIT ();
2521 #ifdef M17N_FLT_USE_NEW_FEATURE
2522 mflt_enable_new_feature = 1;
2523 mflt_try_otf = ftfont_try_otf;
2524 #endif /* M17N_FLT_USE_NEW_FEATURE */
2525 m17n_flt_initialized = 1;
2528 for (i = 0; i < len; i++)
2530 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2531 int c;
2533 if (NILP (g))
2534 break;
2535 c = LGLYPH_CHAR (g);
2536 if (CHAR_VARIATION_SELECTOR_P (c))
2537 with_variation_selector = true;
2540 len = i;
2542 if (otf && with_variation_selector)
2544 setup_otf_gstring (len);
2545 for (i = 0; i < len; i++)
2547 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2549 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2550 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2551 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2553 OTF_drive_cmap (otf, &otf_gstring);
2554 for (i = 0; i < otf_gstring.used; i++)
2556 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2557 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2558 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2560 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2561 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2562 LGSTRING_SET_GLYPH (lgstring, i, g0);
2564 if (len > otf_gstring.used)
2566 len = otf_gstring.used;
2567 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2572 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2574 if (NILP (family))
2575 flt_font_ft.flt_font.family = Mnil;
2576 else
2577 flt_font_ft.flt_font.family
2578 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2580 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2581 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2582 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2583 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2584 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2585 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2586 flt_font_ft.flt_font.internal = NULL;
2587 flt_font_ft.font = font;
2588 flt_font_ft.ft_face = ft_face;
2589 flt_font_ft.otf = otf;
2590 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2592 if (1 < len)
2594 /* A little bit ad hoc. Perhaps, shaper must get script and
2595 language information, and select a proper flt for them
2596 here. */
2597 int c1 = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 1));
2598 /* For the combining characters in the range U+300..U+36F,
2599 "combining" is the sole FLT provided by the m17n-lib. In
2600 addition, it is the sole FLT that can handle the other
2601 combining characters with non-OTF fonts. */
2602 if ((0x300 <= c1 && c1 <= 0x36F)
2603 || (! otf && CHAR_HAS_CATEGORY (c1, '^')))
2604 flt = mflt_get (msymbol ("combining"));
2606 if (! flt && ! otf)
2608 flt = mflt_find (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 0)),
2609 &flt_font_ft.flt_font);
2610 if (! flt)
2611 return make_number (0);
2614 MFLTGlyphFT *glyphs = (MFLTGlyphFT *) gstring.glyphs;
2615 ptrdiff_t allocated = gstring.allocated;
2616 ptrdiff_t incr_min = len - allocated;
2620 if (0 < incr_min)
2622 xfree (glyphs);
2623 glyphs = xpalloc (NULL, &allocated, incr_min, INT_MAX, sizeof *glyphs);
2625 incr_min = 1;
2627 for (i = 0; i < len; i++)
2629 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2630 memset (&glyphs[i], 0, sizeof glyphs[i]);
2631 glyphs[i].g.c = LGLYPH_CHAR (g);
2632 if (with_variation_selector)
2634 glyphs[i].g.code = LGLYPH_CODE (g);
2635 glyphs[i].g.encoded = 1;
2639 gstring.glyph_size = sizeof *glyphs;
2640 gstring.glyphs = (MFLTGlyph *) glyphs;
2641 gstring.allocated = allocated;
2642 gstring.used = len;
2643 gstring.r2l = 0;
2645 while (mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt) == -2);
2647 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2648 return Qnil;
2649 for (i = 0; i < gstring.used; i++)
2651 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2653 g->g.from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->g.from));
2654 g->g.to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->g.to));
2657 for (i = 0; i < gstring.used; i++)
2659 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2660 MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
2662 if (NILP (lglyph))
2664 lglyph = LGLYPH_NEW ();
2665 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2667 LGLYPH_SET_FROM (lglyph, g->g.from);
2668 LGLYPH_SET_TO (lglyph, g->g.to);
2669 LGLYPH_SET_CHAR (lglyph, g->g.c);
2670 LGLYPH_SET_CODE (lglyph, g->g.code);
2671 LGLYPH_SET_WIDTH (lglyph, g->g.xadv >> 6);
2672 LGLYPH_SET_LBEARING (lglyph, g->g.lbearing >> 6);
2673 LGLYPH_SET_RBEARING (lglyph, g->g.rbearing >> 6);
2674 LGLYPH_SET_ASCENT (lglyph, g->g.ascent >> 6);
2675 LGLYPH_SET_DESCENT (lglyph, g->g.descent >> 6);
2676 if (g->g.adjusted)
2678 Lisp_Object vec = make_uninit_vector (3);
2680 ASET (vec, 0, make_number (g->g.xoff >> 6));
2681 ASET (vec, 1, make_number (g->g.yoff >> 6));
2682 ASET (vec, 2, make_number (g->g.xadv >> 6));
2683 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2686 return make_number (i);
2689 Lisp_Object
2690 ftfont_shape (Lisp_Object lgstring)
2692 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2693 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2694 OTF *otf = ftfont_get_otf (ftfont_info);
2696 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2697 &ftfont_info->matrix);
2700 #endif /* HAVE_M17N_FLT */
2702 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2704 static int
2705 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2707 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2708 OTF *otf = ftfont_get_otf (ftfont_info);
2710 if (! otf)
2711 return 0;
2712 return OTF_get_variation_glyphs (otf, c, variations);
2715 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2716 #endif /* HAVE_LIBOTF */
2718 static const char *const ftfont_booleans [] = {
2719 ":antialias",
2720 ":hinting",
2721 ":verticallayout",
2722 ":autohint",
2723 ":globaladvance",
2724 ":outline",
2725 ":scalable",
2726 ":minspace",
2727 ":embolden",
2728 NULL,
2731 static const char *const ftfont_non_booleans [] = {
2732 ":family",
2733 ":familylang",
2734 ":style",
2735 ":stylelang",
2736 ":fullname",
2737 ":fullnamelang",
2738 ":slant",
2739 ":weight",
2740 ":size",
2741 ":width",
2742 ":aspect",
2743 ":pixelsize",
2744 ":spacing",
2745 ":foundry",
2746 ":hintstyle",
2747 ":file",
2748 ":index",
2749 ":ftface",
2750 ":rasterizer",
2751 ":scale",
2752 ":dpi",
2753 ":rgba",
2754 ":lcdfilter",
2755 ":charset",
2756 ":lang",
2757 ":fontversion",
2758 ":capability",
2759 NULL,
2762 static void
2763 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2765 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2769 static Lisp_Object
2770 ftfont_combining_capability (struct font *font)
2772 #ifdef HAVE_M17N_FLT
2773 return Qt;
2774 #else
2775 return Qnil;
2776 #endif
2779 void
2780 syms_of_ftfont (void)
2782 /* Symbolic type of this font-driver. */
2783 DEFSYM (Qfreetype, "freetype");
2785 /* Fontconfig's generic families and their aliases. */
2786 DEFSYM (Qmonospace, "monospace");
2787 DEFSYM (Qsans_serif, "sans-serif");
2788 DEFSYM (Qsans, "sans");
2789 DEFSYM (Qsans__serif, "sans serif");
2791 staticpro (&freetype_font_cache);
2792 freetype_font_cache = list1 (Qt);
2794 staticpro (&ftfont_generic_family_list);
2795 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2796 Fcons (Qsans_serif, Qt),
2797 Fcons (Qsans, Qt));
2799 staticpro (&ft_face_cache);
2800 ft_face_cache = Qnil;
2802 ftfont_driver.type = Qfreetype;
2803 register_font_driver (&ftfont_driver, NULL);