Bind grep-highlight-matches around the rgrep call
[emacs.git] / src / ftfont.c
blobb37b404c5ef6404031d9630b64d32ec68370795d
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2015 Free Software Foundation, Inc.
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
7 This file is part of GNU Emacs.
9 GNU Emacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 #include <config.h>
23 #include <stdio.h>
24 #include <fontconfig/fontconfig.h>
25 #include <fontconfig/fcfreetype.h>
27 #include <c-strcase.h>
29 #include "lisp.h"
30 #include "dispextern.h"
31 #include "frame.h"
32 #include "blockinput.h"
33 #include "character.h"
34 #include "charset.h"
35 #include "coding.h"
36 #include "composite.h"
37 #include "fontset.h"
38 #include "font.h"
39 #include "ftfont.h"
41 /* Flag to tell if FcInit is already called or not. */
42 static bool fc_initialized;
44 /* Handle to a FreeType library instance. */
45 static FT_Library ft_library;
47 /* Cache for FreeType fonts. */
48 static Lisp_Object freetype_font_cache;
50 /* Cache for FT_Face and FcCharSet. */
51 static Lisp_Object ft_face_cache;
53 /* The actual structure for FreeType font that can be cast to struct
54 font. */
56 struct ftfont_info
58 struct font font;
59 #ifdef HAVE_LIBOTF
60 /* The following four members must be here in this order to be
61 compatible with struct xftfont_info (in xftfont.c). */
62 bool maybe_otf; /* Flag to tell if this may be OTF or not. */
63 OTF *otf;
64 #endif /* HAVE_LIBOTF */
65 FT_Size ft_size;
66 int index;
67 FT_Matrix matrix;
70 size_t ftfont_info_size = sizeof (struct ftfont_info);
72 enum ftfont_cache_for
74 FTFONT_CACHE_FOR_FACE,
75 FTFONT_CACHE_FOR_CHARSET,
76 FTFONT_CACHE_FOR_ENTITY
79 static Lisp_Object ftfont_pattern_entity (FcPattern *, Lisp_Object);
81 static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
82 FcPattern *);
83 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
84 enum ftfont_cache_for);
86 static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
88 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
90 static struct
92 /* registry name */
93 const char *name;
94 /* characters to distinguish the charset from the others */
95 int uniquifier[6];
96 /* additional constraint by language */
97 const char *lang;
98 /* set on demand */
99 FcCharSet *fc_charset;
100 } fc_charset_table[] =
101 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
102 { "iso8859-2", { 0x00A0, 0x010E }},
103 { "iso8859-3", { 0x00A0, 0x0108 }},
104 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
105 { "iso8859-5", { 0x00A0, 0x0401 }},
106 { "iso8859-6", { 0x00A0, 0x060C }},
107 { "iso8859-7", { 0x00A0, 0x0384 }},
108 { "iso8859-8", { 0x00A0, 0x05D0 }},
109 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
110 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
111 { "iso8859-11", { 0x00A0, 0x0E01 }},
112 { "iso8859-13", { 0x00A0, 0x201C }},
113 { "iso8859-14", { 0x00A0, 0x0174 }},
114 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
115 { "iso8859-16", { 0x00A0, 0x0218}},
116 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
117 { "big5-0", { 0xF6B1 }, "zh-tw" },
118 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
119 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
120 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
121 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
122 { "cns11643.1992-3", { 0x201A9 }},
123 { "cns11643.1992-4", { 0x20057 }},
124 { "cns11643.1992-5", { 0x20000 }},
125 { "cns11643.1992-6", { 0x20003 }},
126 { "cns11643.1992-7", { 0x20055 }},
127 { "gbk-0", { 0x4E06 }, "zh-cn"},
128 { "jisx0212.1990-0", { 0x4E44 }},
129 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
130 { "jisx0213.2000-2", { 0xFA49 }},
131 { "jisx0213.2004-1", { 0x20B9F }},
132 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
133 { "tis620.2529-1", { 0x0E01 }, "th"},
134 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
135 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
136 { "mulelao-1", { 0x0E81 }, "lo"},
137 { "unicode-sip", { 0x20000 }},
138 { NULL }
141 static bool
142 matching_prefix (char const *str, ptrdiff_t len, char const *pat)
144 return len == strlen (pat) && c_strncasecmp (str, pat, len) == 0;
147 /* Dirty hack for handing ADSTYLE property.
149 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
150 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
151 "Oblique", "Italic", or any non-normal SWIDTH property names
152 (e.g. SemiCondensed) are appended. In addition, if there's no
153 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
154 "Regular" is used for FC_STYLE (see the function
155 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
157 Unfortunately this behavior is not documented, so the following
158 code may fail if FreeType changes the behavior in the future. */
160 static Lisp_Object
161 get_adstyle_property (FcPattern *p)
163 FcChar8 *fcstr;
164 char *str, *end;
165 Lisp_Object adstyle;
167 #ifdef FC_FONTFORMAT
168 if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
169 && xstrcasecmp ((char *) fcstr, "bdf") != 0
170 && xstrcasecmp ((char *) fcstr, "pcf") != 0)
171 /* Not a BDF nor PCF font. */
172 return Qnil;
173 #endif
174 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
175 return Qnil;
176 str = (char *) fcstr;
177 for (end = str; *end && *end != ' '; end++);
178 if (matching_prefix (str, end - str, "Regular")
179 || matching_prefix (str, end - str, "Bold")
180 || matching_prefix (str, end - str, "Oblique")
181 || matching_prefix (str, end - str, "Italic"))
182 return Qnil;
183 adstyle = font_intern_prop (str, end - str, 1);
184 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
185 return Qnil;
186 return adstyle;
189 static Lisp_Object
190 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
192 Lisp_Object key, cache, entity;
193 FcChar8 *str;
194 char *file;
195 int idx;
196 int numeric;
197 double dbl;
198 FcBool b;
200 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
201 return Qnil;
202 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
203 return Qnil;
205 file = (char *) str;
206 key = Fcons (build_unibyte_string (file), make_number (idx));
207 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
208 entity = XCAR (cache);
209 if (! NILP (entity))
211 Lisp_Object val = font_make_entity ();
212 int i;
214 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
215 ASET (val, i, AREF (entity, i));
217 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
218 font_put_extra (val, QCfont_entity, key);
220 return val;
222 entity = font_make_entity ();
223 XSETCAR (cache, entity);
225 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
226 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
228 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
230 char *s = (char *) str;
231 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
233 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
235 char *s = (char *) str;
236 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
238 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
240 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
241 numeric = FC_WEIGHT_MEDIUM;
242 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
244 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
246 numeric += 100;
247 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
249 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
251 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
253 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
255 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
257 else
258 ASET (entity, FONT_SIZE_INDEX, make_number (0));
259 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
260 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
261 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
263 int dpi = dbl;
264 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
266 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
267 && b == FcTrue)
269 ASET (entity, FONT_SIZE_INDEX, make_number (0));
270 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
272 else
274 /* As this font is not scalable, perhaps this is a BDF or PCF
275 font. */
276 FT_Face ft_face;
278 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
279 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
280 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
282 BDF_PropertyRec rec;
284 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
285 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
286 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
287 FT_Done_Face (ft_face);
291 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
292 font_put_extra (entity, QCfont_entity, key);
293 return entity;
297 static Lisp_Object ftfont_generic_family_list;
299 static Lisp_Object
300 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
302 Lisp_Object slot;
303 FcPattern *match;
304 FcResult result;
305 FcLangSet *langset;
307 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
308 if (EQ (family, Qmono))
309 family = Qmonospace;
310 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
311 family = Qsans_serif;
312 slot = assq_no_quit (family, ftfont_generic_family_list);
313 if (! CONSP (slot))
314 return Qnil;
315 if (! EQ (XCDR (slot), Qt))
316 return XCDR (slot);
317 pattern = FcPatternDuplicate (pattern);
318 if (! pattern)
319 goto err;
320 FcPatternDel (pattern, FC_FOUNDRY);
321 FcPatternDel (pattern, FC_FAMILY);
322 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
323 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
325 /* This is to avoid the effect of locale. */
326 static const FcChar8 lang[] = "en";
327 langset = FcLangSetCreate ();
328 FcLangSetAdd (langset, lang);
329 FcPatternAddLangSet (pattern, FC_LANG, langset);
330 FcLangSetDestroy (langset);
332 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
333 FcDefaultSubstitute (pattern);
334 match = FcFontMatch (NULL, pattern, &result);
335 if (match)
337 FcChar8 *fam;
339 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
340 family = intern ((char *) fam);
342 else
343 family = Qnil;
344 XSETCDR (slot, family);
345 if (match) FcPatternDestroy (match);
346 err:
347 if (pattern) FcPatternDestroy (pattern);
348 return family;
351 struct ftfont_cache_data
353 FT_Face ft_face;
354 FcCharSet *fc_charset;
357 static Lisp_Object
358 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
360 Lisp_Object cache, val, entity;
361 struct ftfont_cache_data *cache_data;
363 if (FONT_ENTITY_P (key))
365 entity = key;
366 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
367 eassert (CONSP (val));
368 key = XCDR (val);
370 else
371 entity = Qnil;
373 if (NILP (ft_face_cache))
374 cache = Qnil;
375 else
376 cache = Fgethash (key, ft_face_cache, Qnil);
377 if (NILP (cache))
379 if (NILP (ft_face_cache))
380 ft_face_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
381 cache_data = xmalloc (sizeof *cache_data);
382 cache_data->ft_face = NULL;
383 cache_data->fc_charset = NULL;
384 val = make_save_ptr_int (cache_data, 0);
385 cache = Fcons (Qnil, val);
386 Fputhash (key, cache, ft_face_cache);
388 else
390 val = XCDR (cache);
391 cache_data = XSAVE_POINTER (val, 0);
394 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
395 return cache;
397 if (cache_for == FTFONT_CACHE_FOR_FACE
398 ? ! cache_data->ft_face : ! cache_data->fc_charset)
400 char *filename = SSDATA (XCAR (key));
401 int idx = XINT (XCDR (key));
403 if (cache_for == FTFONT_CACHE_FOR_FACE)
405 if (! ft_library
406 && FT_Init_FreeType (&ft_library) != 0)
407 return Qnil;
408 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
409 != 0)
410 return Qnil;
412 else
414 FcPattern *pat = NULL;
415 FcFontSet *fontset = NULL;
416 FcObjectSet *objset = NULL;
417 FcCharSet *charset = NULL;
419 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
420 FC_INDEX, FcTypeInteger, idx, NULL);
421 if (! pat)
422 goto finish;
423 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
424 if (! objset)
425 goto finish;
426 fontset = FcFontList (NULL, pat, objset);
427 if (! fontset)
428 goto finish;
429 if (fontset && fontset->nfont > 0
430 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
431 &charset)
432 == FcResultMatch))
433 cache_data->fc_charset = FcCharSetCopy (charset);
434 else
435 cache_data->fc_charset = FcCharSetCreate ();
437 finish:
438 if (fontset)
439 FcFontSetDestroy (fontset);
440 if (objset)
441 FcObjectSetDestroy (objset);
442 if (pat)
443 FcPatternDestroy (pat);
446 return cache;
449 FcCharSet *
450 ftfont_get_fc_charset (Lisp_Object entity)
452 Lisp_Object val, cache;
453 struct ftfont_cache_data *cache_data;
455 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
456 val = XCDR (cache);
457 cache_data = XSAVE_POINTER (val, 0);
458 return cache_data->fc_charset;
461 #ifdef HAVE_LIBOTF
462 static OTF *
463 ftfont_get_otf (struct ftfont_info *ftfont_info)
465 OTF *otf;
467 if (ftfont_info->otf)
468 return ftfont_info->otf;
469 if (! ftfont_info->maybe_otf)
470 return NULL;
471 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
472 if (! otf || OTF_get_table (otf, "head") < 0)
474 if (otf)
475 OTF_close (otf);
476 ftfont_info->maybe_otf = 0;
477 return NULL;
479 ftfont_info->otf = otf;
480 return otf;
482 #endif /* HAVE_LIBOTF */
484 static Lisp_Object ftfont_get_cache (struct frame *);
485 static Lisp_Object ftfont_list (struct frame *, Lisp_Object);
486 static Lisp_Object ftfont_match (struct frame *, Lisp_Object);
487 static Lisp_Object ftfont_list_family (struct frame *);
488 static Lisp_Object ftfont_open (struct frame *, Lisp_Object, int);
489 static void ftfont_close (struct font *);
490 static int ftfont_has_char (Lisp_Object, int);
491 static unsigned ftfont_encode_char (struct font *, int);
492 static void ftfont_text_extents (struct font *, unsigned *, int,
493 struct font_metrics *);
494 static int ftfont_get_bitmap (struct font *, unsigned,
495 struct font_bitmap *, int);
496 static int ftfont_anchor_point (struct font *, unsigned, int,
497 int *, int *);
498 #ifdef HAVE_LIBOTF
499 static Lisp_Object ftfont_otf_capability (struct font *);
500 # ifdef HAVE_M17N_FLT
501 static Lisp_Object ftfont_shape (Lisp_Object);
502 # endif
503 #endif
505 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
506 static int ftfont_variation_glyphs (struct font *, int c,
507 unsigned variations[256]);
508 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
510 struct font_driver ftfont_driver =
512 LISP_INITIALLY_ZERO, /* Qfreetype */
513 0, /* case insensitive */
514 ftfont_get_cache,
515 ftfont_list,
516 ftfont_match,
517 ftfont_list_family,
518 NULL, /* free_entity */
519 ftfont_open,
520 ftfont_close,
521 /* We can't draw a text without device dependent functions. */
522 NULL, /* prepare_face */
523 NULL, /* done_face */
524 ftfont_has_char,
525 ftfont_encode_char,
526 ftfont_text_extents,
527 /* We can't draw a text without device dependent functions. */
528 NULL, /* draw */
529 ftfont_get_bitmap,
530 NULL, /* free_bitmap */
531 ftfont_anchor_point,
532 #ifdef HAVE_LIBOTF
533 ftfont_otf_capability,
534 #else /* not HAVE_LIBOTF */
535 NULL,
536 #endif /* not HAVE_LIBOTF */
537 NULL, /* otf_drive */
538 NULL, /* start_for_frame */
539 NULL, /* end_for_frame */
540 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
541 ftfont_shape,
542 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
543 NULL,
544 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
545 NULL, /* check */
547 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
548 ftfont_variation_glyphs,
549 #else
550 NULL,
551 #endif
553 ftfont_filter_properties, /* filter_properties */
556 static Lisp_Object
557 ftfont_get_cache (struct frame *f)
559 return freetype_font_cache;
562 static int
563 ftfont_get_charset (Lisp_Object registry)
565 char *str = SSDATA (SYMBOL_NAME (registry));
566 USE_SAFE_ALLOCA;
567 char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
568 Lisp_Object regexp;
569 int i, j;
571 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
573 if (str[i] == '.')
574 re[j++] = '\\';
575 else if (str[i] == '*')
576 re[j++] = '.';
577 re[j] = str[i];
578 if (re[j] == '?')
579 re[j] = '.';
581 re[j] = '\0';
582 regexp = make_unibyte_string (re, j);
583 SAFE_FREE ();
584 for (i = 0; fc_charset_table[i].name; i++)
585 if (fast_c_string_match_ignore_case
586 (regexp, fc_charset_table[i].name,
587 strlen (fc_charset_table[i].name)) >= 0)
588 break;
589 if (! fc_charset_table[i].name)
590 return -1;
591 if (! fc_charset_table[i].fc_charset)
593 FcCharSet *charset = FcCharSetCreate ();
594 int *uniquifier = fc_charset_table[i].uniquifier;
596 if (! charset)
597 return -1;
598 for (j = 0; uniquifier[j]; j++)
599 if (! FcCharSetAddChar (charset, uniquifier[j]))
601 FcCharSetDestroy (charset);
602 return -1;
604 fc_charset_table[i].fc_charset = charset;
606 return i;
609 struct OpenTypeSpec
611 Lisp_Object script;
612 unsigned int script_tag, langsys_tag;
613 int nfeatures[2];
614 unsigned int *features[2];
617 #define OTF_SYM_TAG(SYM, TAG) \
618 do { \
619 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
620 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
621 } while (0)
623 #define OTF_TAG_STR(TAG, P) \
624 do { \
625 (P)[0] = (char) (TAG >> 24); \
626 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
627 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
628 (P)[3] = (char) (TAG & 0xFF); \
629 (P)[4] = '\0'; \
630 } while (0)
632 #ifdef HAVE_LIBOTF
633 #define OTF_TAG_SYM(SYM, TAG) \
634 do { \
635 char str[5]; \
637 OTF_TAG_STR (TAG, str); \
638 (SYM) = font_intern_prop (str, 4, 1); \
639 } while (0)
640 #endif
643 static struct OpenTypeSpec *
644 ftfont_get_open_type_spec (Lisp_Object otf_spec)
646 struct OpenTypeSpec *spec = malloc (sizeof *spec);
647 Lisp_Object val;
648 int i, j;
649 bool negative;
651 if (! spec)
652 return NULL;
653 spec->script = XCAR (otf_spec);
654 if (! NILP (spec->script))
656 OTF_SYM_TAG (spec->script, spec->script_tag);
657 val = assq_no_quit (spec->script, Votf_script_alist);
658 if (CONSP (val) && SYMBOLP (XCDR (val)))
659 spec->script = XCDR (val);
660 else
661 spec->script = Qnil;
663 else
664 spec->script_tag = 0x44464C54; /* "DFLT" */
665 otf_spec = XCDR (otf_spec);
666 spec->langsys_tag = 0;
667 if (! NILP (otf_spec))
669 val = XCAR (otf_spec);
670 if (! NILP (val))
671 OTF_SYM_TAG (val, spec->langsys_tag);
672 otf_spec = XCDR (otf_spec);
674 spec->nfeatures[0] = spec->nfeatures[1] = 0;
675 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
677 Lisp_Object len;
679 val = XCAR (otf_spec);
680 if (NILP (val))
681 continue;
682 len = Flength (val);
683 spec->features[i] =
684 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
686 : malloc (XINT (len) * sizeof *spec->features[i]));
687 if (! spec->features[i])
689 if (i > 0 && spec->features[0])
690 free (spec->features[0]);
691 free (spec);
692 return NULL;
694 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
696 if (NILP (XCAR (val)))
697 negative = 1;
698 else
700 unsigned int tag;
702 OTF_SYM_TAG (XCAR (val), tag);
703 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
706 spec->nfeatures[i] = j;
708 return spec;
711 static FcPattern *
712 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
714 Lisp_Object tmp, extra;
715 FcPattern *pattern = NULL;
716 FcCharSet *charset = NULL;
717 FcLangSet *langset = NULL;
718 int n;
719 int dpi = -1;
720 int scalable = -1;
721 Lisp_Object script = Qnil;
722 Lisp_Object registry;
723 int fc_charset_idx;
725 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
726 && n < 100)
727 /* Fontconfig doesn't support reverse-italic/oblique. */
728 return NULL;
730 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
731 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
732 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
733 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
734 scalable = 1;
736 registry = AREF (spec, FONT_REGISTRY_INDEX);
737 if (NILP (registry)
738 || EQ (registry, Qascii_0)
739 || EQ (registry, Qiso10646_1)
740 || EQ (registry, Qunicode_bmp))
741 fc_charset_idx = -1;
742 else
744 FcChar8 *lang;
746 fc_charset_idx = ftfont_get_charset (registry);
747 if (fc_charset_idx < 0)
748 return NULL;
749 charset = fc_charset_table[fc_charset_idx].fc_charset;
750 *langname = fc_charset_table[fc_charset_idx].lang;
751 lang = (FcChar8 *) *langname;
752 if (lang)
754 langset = FcLangSetCreate ();
755 if (! langset)
756 goto err;
757 FcLangSetAdd (langset, lang);
761 otlayout[0] = '\0';
762 for (extra = AREF (spec, FONT_EXTRA_INDEX);
763 CONSP (extra); extra = XCDR (extra))
765 Lisp_Object key, val;
767 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
768 if (EQ (key, QCdpi))
770 if (INTEGERP (val))
771 dpi = XINT (val);
773 else if (EQ (key, QClang))
775 if (! langset)
776 langset = FcLangSetCreate ();
777 if (! langset)
778 goto err;
779 if (SYMBOLP (val))
781 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
782 goto err;
784 else
785 for (; CONSP (val); val = XCDR (val))
786 if (SYMBOLP (XCAR (val))
787 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
788 goto err;
790 else if (EQ (key, QCotf))
792 if (CONSP (val))
794 *otspec = ftfont_get_open_type_spec (val);
795 if (! *otspec)
796 return NULL;
797 strcpy (otlayout, "otlayout:");
798 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
799 script = (*otspec)->script;
802 else if (EQ (key, QCscript))
803 script = val;
804 else if (EQ (key, QCscalable))
805 scalable = ! NILP (val);
808 if (! NILP (script) && ! charset)
810 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
812 if (CONSP (chars) && CONSP (CDR (chars)))
814 charset = FcCharSetCreate ();
815 if (! charset)
816 goto err;
817 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
818 if (CHARACTERP (XCAR (chars))
819 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
820 goto err;
824 pattern = FcPatternCreate ();
825 if (! pattern)
826 goto err;
827 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
828 if (! NILP (tmp)
829 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
830 goto err;
831 tmp = AREF (spec, FONT_FAMILY_INDEX);
832 if (! NILP (tmp)
833 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
834 goto err;
835 if (charset
836 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
837 goto err;
838 if (langset
839 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
840 goto err;
841 if (dpi >= 0
842 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
843 goto err;
844 if (scalable >= 0
845 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
846 goto err;
848 goto finish;
850 err:
851 /* We come here because of unexpected error in fontconfig API call
852 (usually insufficient memory). */
853 if (pattern)
855 FcPatternDestroy (pattern);
856 pattern = NULL;
858 if (*otspec)
860 if ((*otspec)->nfeatures[0] > 0)
861 free ((*otspec)->features[0]);
862 if ((*otspec)->nfeatures[1] > 0)
863 free ((*otspec)->features[1]);
864 free (*otspec);
865 *otspec = NULL;
868 finish:
869 if (langset) FcLangSetDestroy (langset);
870 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
871 return pattern;
874 static Lisp_Object
875 ftfont_list (struct frame *f, Lisp_Object spec)
877 Lisp_Object val = Qnil, family, adstyle;
878 int i;
879 FcPattern *pattern;
880 FcFontSet *fontset = NULL;
881 FcObjectSet *objset = NULL;
882 FcCharSet *charset;
883 Lisp_Object chars = Qnil;
884 char otlayout[15]; /* For "otlayout:XXXX" */
885 struct OpenTypeSpec *otspec = NULL;
886 int spacing = -1;
887 const char *langname = NULL;
889 if (! fc_initialized)
891 FcInit ();
892 fc_initialized = 1;
895 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
896 if (! pattern)
897 return Qnil;
898 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
900 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
901 if (! NILP (val))
903 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
904 if (CONSP (val) && VECTORP (XCDR (val)))
905 chars = XCDR (val);
907 val = Qnil;
909 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
910 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
911 family = AREF (spec, FONT_FAMILY_INDEX);
912 if (! NILP (family))
914 Lisp_Object resolved;
916 resolved = ftfont_resolve_generic_family (family, pattern);
917 if (! NILP (resolved))
919 FcPatternDel (pattern, FC_FAMILY);
920 if (! FcPatternAddString (pattern, FC_FAMILY,
921 SYMBOL_FcChar8 (resolved)))
922 goto err;
925 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
926 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
927 adstyle = Qnil;
928 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
929 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
930 FC_STYLE, FC_FILE, FC_INDEX,
931 #ifdef FC_CAPABILITY
932 FC_CAPABILITY,
933 #endif /* FC_CAPABILITY */
934 #ifdef FC_FONTFORMAT
935 FC_FONTFORMAT,
936 #endif
937 NULL);
938 if (! objset)
939 goto err;
940 if (! NILP (chars))
941 FcObjectSetAdd (objset, FC_CHARSET);
943 fontset = FcFontList (NULL, pattern, objset);
944 if (! fontset || fontset->nfont == 0)
945 goto finish;
946 #if 0
947 /* Need fix because this finds any fonts. */
948 if (fontset->nfont == 0 && ! NILP (family))
950 /* Try matching with configuration. For instance, the
951 configuration may specify "Nimbus Mono L" as an alias of
952 "Courier". */
953 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
954 SYMBOL_FcChar8 (family), NULL);
955 FcChar8 *fam;
957 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
959 for (i = 0;
960 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
961 i++)
963 FcPatternDel (pattern, FC_FAMILY);
964 FcPatternAddString (pattern, FC_FAMILY, fam);
965 FcFontSetDestroy (fontset);
966 fontset = FcFontList (NULL, pattern, objset);
967 if (fontset && fontset->nfont > 0)
968 break;
972 #endif
973 for (i = 0; i < fontset->nfont; i++)
975 Lisp_Object entity;
977 if (spacing >= 0)
979 int this;
981 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
982 == FcResultMatch)
983 && spacing != this)
984 continue;
987 #ifdef FC_CAPABILITY
988 if (otlayout[0])
990 FcChar8 *this;
992 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
993 != FcResultMatch
994 || ! strstr ((char *) this, otlayout))
995 continue;
997 #endif /* FC_CAPABILITY */
998 #ifdef HAVE_LIBOTF
999 if (otspec)
1001 FcChar8 *file;
1002 bool passed;
1003 OTF *otf;
1005 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1006 != FcResultMatch)
1007 continue;
1008 otf = OTF_open ((char *) file);
1009 if (! otf)
1010 continue;
1011 passed = (OTF_check_features (otf, 1, otspec->script_tag,
1012 otspec->langsys_tag,
1013 otspec->features[0],
1014 otspec->nfeatures[0]) == 1
1015 && OTF_check_features (otf, 0, otspec->script_tag,
1016 otspec->langsys_tag,
1017 otspec->features[1],
1018 otspec->nfeatures[1]) == 1);
1019 OTF_close (otf);
1020 if (!passed)
1021 continue;
1023 #endif /* HAVE_LIBOTF */
1024 if (VECTORP (chars))
1026 ptrdiff_t j;
1028 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1029 != FcResultMatch)
1030 continue;
1031 for (j = 0; j < ASIZE (chars); j++)
1032 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1033 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1034 break;
1035 if (j == ASIZE (chars))
1036 continue;
1038 if (! NILP (adstyle) || langname)
1040 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1042 if (! NILP (adstyle)
1043 && (NILP (this_adstyle)
1044 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1045 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1046 continue;
1047 if (langname
1048 && ! NILP (this_adstyle)
1049 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1050 continue;
1052 entity = ftfont_pattern_entity (fontset->fonts[i],
1053 AREF (spec, FONT_EXTRA_INDEX));
1054 if (! NILP (entity))
1055 val = Fcons (entity, val);
1057 val = Fnreverse (val);
1058 goto finish;
1060 err:
1061 /* We come here because of unexpected error in fontconfig API call
1062 (usually insufficient memory). */
1063 val = Qnil;
1065 finish:
1066 FONT_ADD_LOG ("ftfont-list", spec, val);
1067 if (objset) FcObjectSetDestroy (objset);
1068 if (fontset) FcFontSetDestroy (fontset);
1069 if (pattern) FcPatternDestroy (pattern);
1070 return val;
1073 static Lisp_Object
1074 ftfont_match (struct frame *f, Lisp_Object spec)
1076 Lisp_Object entity = Qnil;
1077 FcPattern *pattern, *match = NULL;
1078 FcResult result;
1079 char otlayout[15]; /* For "otlayout:XXXX" */
1080 struct OpenTypeSpec *otspec = NULL;
1081 const char *langname = NULL;
1083 if (! fc_initialized)
1085 FcInit ();
1086 fc_initialized = 1;
1089 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1090 if (! pattern)
1091 return Qnil;
1093 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1095 FcValue value;
1097 value.type = FcTypeDouble;
1098 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1099 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1101 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1103 FcDefaultSubstitute (pattern);
1104 match = FcFontMatch (NULL, pattern, &result);
1105 if (match)
1107 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1108 FcPatternDestroy (match);
1109 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1110 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1111 ftfont_generic_family_list))
1112 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1113 AREF (entity, FONT_FAMILY_INDEX))))
1114 entity = Qnil;
1117 FcPatternDestroy (pattern);
1119 FONT_ADD_LOG ("ftfont-match", spec, entity);
1120 return entity;
1123 static Lisp_Object
1124 ftfont_list_family (struct frame *f)
1126 Lisp_Object list = Qnil;
1127 FcPattern *pattern = NULL;
1128 FcFontSet *fontset = NULL;
1129 FcObjectSet *objset = NULL;
1130 int i;
1132 if (! fc_initialized)
1134 FcInit ();
1135 fc_initialized = 1;
1138 pattern = FcPatternCreate ();
1139 if (! pattern)
1140 goto finish;
1141 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1142 if (! objset)
1143 goto finish;
1144 fontset = FcFontList (NULL, pattern, objset);
1145 if (! fontset)
1146 goto finish;
1148 for (i = 0; i < fontset->nfont; i++)
1150 FcPattern *pat = fontset->fonts[i];
1151 FcChar8 *str;
1153 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1154 list = Fcons (intern ((char *) str), list);
1157 finish:
1158 if (objset) FcObjectSetDestroy (objset);
1159 if (fontset) FcFontSetDestroy (fontset);
1160 if (pattern) FcPatternDestroy (pattern);
1162 return list;
1166 Lisp_Object
1167 ftfont_open2 (struct frame *f,
1168 Lisp_Object entity,
1169 int pixel_size,
1170 Lisp_Object font_object)
1172 struct ftfont_info *ftfont_info;
1173 struct font *font;
1174 struct ftfont_cache_data *cache_data;
1175 FT_Face ft_face;
1176 FT_Size ft_size;
1177 FT_UInt size;
1178 Lisp_Object val, filename, idx, cache;
1179 bool scalable;
1180 int spacing;
1181 int i;
1182 double upEM;
1184 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1185 if (! CONSP (val))
1186 return Qnil;
1187 val = XCDR (val);
1188 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1189 if (NILP (cache))
1190 return Qnil;
1191 filename = XCAR (val);
1192 idx = XCDR (val);
1193 val = XCDR (cache);
1194 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1195 ft_face = cache_data->ft_face;
1196 if (XSAVE_INTEGER (val, 1) > 0)
1198 /* FT_Face in this cache is already used by the different size. */
1199 if (FT_New_Size (ft_face, &ft_size) != 0)
1200 return Qnil;
1201 if (FT_Activate_Size (ft_size) != 0)
1203 FT_Done_Size (ft_size);
1204 return Qnil;
1207 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1208 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1209 if (size == 0)
1210 size = pixel_size;
1211 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1213 if (XSAVE_INTEGER (val, 1) == 0)
1214 FT_Done_Face (ft_face);
1215 return Qnil;
1218 ASET (font_object, FONT_FILE_INDEX, filename);
1219 font = XFONT_OBJECT (font_object);
1220 ftfont_info = (struct ftfont_info *) font;
1221 ftfont_info->ft_size = ft_face->size;
1222 ftfont_info->index = XINT (idx);
1223 #ifdef HAVE_LIBOTF
1224 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1225 ftfont_info->otf = NULL;
1226 #endif /* HAVE_LIBOTF */
1227 /* This means that there's no need of transformation. */
1228 ftfont_info->matrix.xx = 0;
1229 font->pixel_size = size;
1230 font->driver = &ftfont_driver;
1231 font->encoding_charset = font->repertory_charset = -1;
1233 upEM = ft_face->units_per_EM;
1234 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1235 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1236 if (scalable)
1238 font->ascent = ft_face->ascender * size / upEM + 0.5;
1239 font->descent = - ft_face->descender * size / upEM + 0.5;
1240 font->height = ft_face->height * size / upEM + 0.5;
1242 else
1244 font->ascent = ft_face->size->metrics.ascender >> 6;
1245 font->descent = - ft_face->size->metrics.descender >> 6;
1246 font->height = ft_face->size->metrics.height >> 6;
1248 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1249 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1250 else
1251 spacing = FC_PROPORTIONAL;
1252 if (spacing != FC_PROPORTIONAL
1253 #ifdef FC_DUAL
1254 && spacing != FC_DUAL
1255 #endif /* FC_DUAL */
1257 font->min_width = font->average_width = font->space_width
1258 = (scalable ? ft_face->max_advance_width * size / upEM + 0.5
1259 : ft_face->size->metrics.max_advance >> 6);
1260 else
1262 int n;
1264 font->min_width = font->average_width = font->space_width = 0;
1265 for (i = 32, n = 0; i < 127; i++)
1266 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1268 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1270 if (this_width > 0
1271 && (! font->min_width || font->min_width > this_width))
1272 font->min_width = this_width;
1273 if (i == 32)
1274 font->space_width = this_width;
1275 font->average_width += this_width;
1276 n++;
1278 if (n > 0)
1279 font->average_width /= n;
1282 font->baseline_offset = 0;
1283 font->relative_compose = 0;
1284 font->default_ascent = 0;
1285 font->vertical_centering = 0;
1286 if (scalable)
1288 font->underline_position = (-ft_face->underline_position * size / upEM
1289 + 0.5);
1290 font->underline_thickness = (ft_face->underline_thickness * size / upEM
1291 + 0.5);
1293 else
1295 font->underline_position = -1;
1296 font->underline_thickness = 0;
1299 return font_object;
1302 static Lisp_Object
1303 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1305 Lisp_Object font_object;
1306 FT_UInt size;
1307 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1308 if (size == 0)
1309 size = pixel_size;
1310 font_object = font_build_object (VECSIZE (struct ftfont_info),
1311 Qfreetype, entity, size);
1312 return ftfont_open2 (f, entity, pixel_size, font_object);
1315 static void
1316 ftfont_close (struct font *font)
1318 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1319 Lisp_Object val, cache;
1321 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1322 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1323 eassert (CONSP (cache));
1324 val = XCDR (cache);
1325 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1326 if (XSAVE_INTEGER (val, 1) == 0)
1328 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1330 FT_Done_Face (cache_data->ft_face);
1331 #ifdef HAVE_LIBOTF
1332 if (ftfont_info->otf)
1333 OTF_close (ftfont_info->otf);
1334 #endif
1335 cache_data->ft_face = NULL;
1337 else
1338 FT_Done_Size (ftfont_info->ft_size);
1341 static int
1342 ftfont_has_char (Lisp_Object font, int c)
1344 struct charset *cs = NULL;
1346 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1347 && charset_jisx0208 >= 0)
1348 cs = CHARSET_FROM_ID (charset_jisx0208);
1349 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1350 && charset_ksc5601 >= 0)
1351 cs = CHARSET_FROM_ID (charset_ksc5601);
1352 if (cs)
1353 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1355 if (FONT_ENTITY_P (font))
1357 FcCharSet *charset = ftfont_get_fc_charset (font);
1359 return (FcCharSetHasChar (charset, c) == FcTrue);
1361 else
1363 struct ftfont_info *ftfont_info;
1365 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1366 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1367 != 0);
1371 static unsigned
1372 ftfont_encode_char (struct font *font, int c)
1374 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1375 FT_Face ft_face = ftfont_info->ft_size->face;
1376 FT_ULong charcode = c;
1377 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1379 return (code > 0 ? code : FONT_INVALID_CODE);
1382 static void
1383 ftfont_text_extents (struct font *font, unsigned int *code,
1384 int nglyphs, struct font_metrics *metrics)
1386 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1387 FT_Face ft_face = ftfont_info->ft_size->face;
1388 int i, width = 0;
1389 bool first;
1391 if (ftfont_info->ft_size != ft_face->size)
1392 FT_Activate_Size (ftfont_info->ft_size);
1394 for (i = 0, first = 1; i < nglyphs; i++)
1396 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1398 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1400 if (first)
1402 metrics->lbearing = m->horiBearingX >> 6;
1403 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1404 metrics->ascent = m->horiBearingY >> 6;
1405 metrics->descent = (m->height - m->horiBearingY) >> 6;
1406 first = 0;
1408 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1409 metrics->lbearing = width + (m->horiBearingX >> 6);
1410 if (metrics->rbearing
1411 < width + ((m->horiBearingX + m->width) >> 6))
1412 metrics->rbearing
1413 = width + ((m->horiBearingX + m->width) >> 6);
1414 if (metrics->ascent < (m->horiBearingY >> 6))
1415 metrics->ascent = m->horiBearingY >> 6;
1416 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1417 metrics->descent = (m->height - m->horiBearingY) >> 6;
1418 width += m->horiAdvance >> 6;
1420 else
1421 width += font->space_width;
1423 metrics->width = width;
1426 static int
1427 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1429 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1430 FT_Face ft_face = ftfont_info->ft_size->face;
1431 FT_Int32 load_flags = FT_LOAD_RENDER;
1433 if (ftfont_info->ft_size != ft_face->size)
1434 FT_Activate_Size (ftfont_info->ft_size);
1435 if (bits_per_pixel == 1)
1437 #ifdef FT_LOAD_TARGET_MONO
1438 load_flags |= FT_LOAD_TARGET_MONO;
1439 #else
1440 load_flags |= FT_LOAD_MONOCHROME;
1441 #endif
1443 else if (bits_per_pixel != 8)
1444 /* We don't support such a rendering. */
1445 return -1;
1447 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1448 return -1;
1449 bitmap->bits_per_pixel
1450 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1451 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1452 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1453 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1454 : -1);
1455 if (bitmap->bits_per_pixel < 0)
1456 /* We don't support that kind of pixel mode. */
1457 return -1;
1458 bitmap->rows = ft_face->glyph->bitmap.rows;
1459 bitmap->width = ft_face->glyph->bitmap.width;
1460 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1461 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1462 bitmap->left = ft_face->glyph->bitmap_left;
1463 bitmap->top = ft_face->glyph->bitmap_top;
1464 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1466 return 0;
1469 static int
1470 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1471 int *x, int *y)
1473 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1474 FT_Face ft_face = ftfont_info->ft_size->face;
1476 if (ftfont_info->ft_size != ft_face->size)
1477 FT_Activate_Size (ftfont_info->ft_size);
1478 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1479 return -1;
1480 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1481 return -1;
1482 if (idx >= ft_face->glyph->outline.n_points)
1483 return -1;
1484 *x = ft_face->glyph->outline.points[idx].x;
1485 *y = ft_face->glyph->outline.points[idx].y;
1486 return 0;
1489 #ifdef HAVE_LIBOTF
1491 static Lisp_Object
1492 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1494 Lisp_Object scripts, langsyses, features, sym;
1495 int i, j, k, l;
1497 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1499 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1501 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1503 OTF_LangSys *otf_langsys;
1505 if (j >= 0)
1506 otf_langsys = otf_script->LangSys + j;
1507 else if (otf_script->DefaultLangSysOffset)
1508 otf_langsys = &otf_script->DefaultLangSys;
1509 else
1510 break;
1512 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1514 l = otf_langsys->FeatureIndex[k];
1515 if (l >= gsub_gpos->FeatureList.FeatureCount)
1516 continue;
1517 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1518 features = Fcons (sym, features);
1520 if (j >= 0)
1521 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1522 else
1523 sym = Qnil;
1524 langsyses = Fcons (Fcons (sym, features), langsyses);
1527 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1528 scripts = Fcons (Fcons (sym, langsyses), scripts);
1530 return scripts;
1535 static Lisp_Object
1536 ftfont_otf_capability (struct font *font)
1538 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1539 OTF *otf = ftfont_get_otf (ftfont_info);
1540 Lisp_Object gsub_gpos;
1542 if (! otf)
1543 return Qnil;
1544 gsub_gpos = Fcons (Qnil, Qnil);
1545 if (OTF_get_table (otf, "GSUB") == 0
1546 && otf->gsub->FeatureList.FeatureCount > 0)
1547 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1548 if (OTF_get_table (otf, "GPOS") == 0
1549 && otf->gpos->FeatureList.FeatureCount > 0)
1550 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1551 return gsub_gpos;
1554 #ifdef HAVE_M17N_FLT
1556 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1557 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1558 /* We can use the new feature of libotf and m17n-flt to handle the
1559 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1560 some Agian scripts. */
1561 #define M17N_FLT_USE_NEW_FEATURE
1562 #endif
1564 struct MFLTFontFT
1566 MFLTFont flt_font;
1567 struct font *font;
1568 FT_Face ft_face;
1569 OTF *otf;
1570 FT_Matrix *matrix;
1573 static int
1574 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1575 int from, int to)
1577 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1578 FT_Face ft_face = flt_font_ft->ft_face;
1579 MFLTGlyph *g;
1581 for (g = gstring->glyphs + from; from < to; g++, from++)
1582 if (! g->encoded)
1584 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1586 g->code = code > 0 ? code : FONT_INVALID_CODE;
1587 g->encoded = 1;
1589 return 0;
1592 /* Operators for 26.6 fixed fractional pixel format */
1594 #define FLOOR(x) ((x) & -64)
1595 #define CEIL(x) (((x)+63) & -64)
1596 #define ROUND(x) (((x)+32) & -64)
1598 static int
1599 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1600 int from, int to)
1602 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1603 FT_Face ft_face = flt_font_ft->ft_face;
1604 MFLTGlyph *g;
1606 for (g = gstring->glyphs + from; from < to; g++, from++)
1607 if (! g->measured)
1609 if (g->code != FONT_INVALID_CODE)
1611 FT_Glyph_Metrics *m;
1613 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1614 emacs_abort ();
1615 m = &ft_face->glyph->metrics;
1616 if (flt_font_ft->matrix)
1618 FT_Vector v[4];
1619 int i;
1621 v[0].x = v[1].x = m->horiBearingX;
1622 v[2].x = v[3].x = m->horiBearingX + m->width;
1623 v[0].y = v[2].y = m->horiBearingY;
1624 v[1].y = v[3].y = m->horiBearingY - m->height;
1625 for (i = 0; i < 4; i++)
1626 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1627 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1628 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1629 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1630 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1632 else
1634 g->lbearing = FLOOR (m->horiBearingX);
1635 g->rbearing = CEIL (m->horiBearingX + m->width);
1636 g->ascent = CEIL (m->horiBearingY);
1637 g->descent = - FLOOR (m->horiBearingY - m->height);
1639 g->xadv = ROUND (ft_face->glyph->advance.x);
1641 else
1643 g->lbearing = 0;
1644 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1645 g->ascent = flt_font_ft->font->ascent << 6;
1646 g->descent = flt_font_ft->font->descent << 6;
1648 g->yadv = 0;
1649 g->measured = 1;
1651 return 0;
1654 static int
1655 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1657 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1659 #define FEATURE_ANY(IDX) \
1660 (spec->features[IDX] \
1661 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1663 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1664 OTF *otf = flt_font_ft->otf;
1665 OTF_Tag *tags;
1666 int i, n;
1667 bool negative;
1669 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1670 /* Return true iff any of GSUB or GPOS support the script (and
1671 language). */
1672 return (otf
1673 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1674 NULL, 0) > 0
1675 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1676 NULL, 0) > 0));
1678 for (i = 0; i < 2; i++)
1679 if (! FEATURE_ANY (i))
1681 if (FEATURE_NONE (i))
1683 if (otf
1684 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1685 NULL, 0) > 0)
1686 return 0;
1687 continue;
1689 if (spec->features[i][0] == 0xFFFFFFFF)
1691 if (! otf
1692 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1693 NULL, 0) <= 0)
1694 continue;
1696 else if (! otf)
1697 return 0;
1698 for (n = 1; spec->features[i][n]; n++);
1699 USE_SAFE_ALLOCA;
1700 SAFE_NALLOCA (tags, 1, n);
1701 for (n = 0, negative = 0; spec->features[i][n]; n++)
1703 if (spec->features[i][n] == 0xFFFFFFFF)
1704 negative = 1;
1705 else if (negative)
1706 tags[n - 1] = spec->features[i][n] | 0x80000000;
1707 else
1708 tags[n] = spec->features[i][n];
1710 bool passed = true;
1711 #ifndef M17N_FLT_USE_NEW_FEATURE
1712 passed = n - negative > 0;
1713 #endif
1714 if (passed)
1715 passed = (OTF_check_features (otf, i == 0, spec->script,
1716 spec->langsys, tags, n - negative)
1717 != 1);
1718 SAFE_FREE ();
1719 if (passed)
1720 return 0;
1722 return 1;
1723 #undef FEATURE_NONE
1724 #undef FEATURE_ANY
1727 #define DEVICE_DELTA(table, size) \
1728 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1729 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1730 : 0)
1732 static void
1733 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1734 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1736 if (anchor->AnchorFormat == 2)
1738 FT_Outline *outline;
1739 int ap = anchor->f.f1.AnchorPoint;
1741 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1742 outline = &ft_face->glyph->outline;
1743 if (ap < outline->n_points)
1745 *x = outline->points[ap].x << 6;
1746 *y = outline->points[ap].y << 6;
1749 else if (anchor->AnchorFormat == 3)
1751 if (anchor->f.f2.XDeviceTable.offset
1752 && anchor->f.f2.XDeviceTable.DeltaValue)
1753 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1754 if (anchor->f.f2.YDeviceTable.offset
1755 && anchor->f.f2.YDeviceTable.DeltaValue)
1756 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1760 static OTF_GlyphString otf_gstring;
1762 static void
1763 setup_otf_gstring (int size)
1765 if (otf_gstring.size < size)
1767 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1768 size, sizeof (OTF_Glyph));
1769 otf_gstring.size = size;
1771 otf_gstring.used = size;
1772 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1775 #ifdef M17N_FLT_USE_NEW_FEATURE
1777 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1778 #define PACK_OTF_TAG(TAG) \
1779 ((((TAG) & 0x7F000000) >> 3) \
1780 | (((TAG) & 0x7F0000) >> 2) \
1781 | (((TAG) & 0x7F00) >> 1) \
1782 | ((TAG) & 0x7F))
1784 /* Assuming that FONT is an OpenType font, apply OpenType features
1785 specified in SPEC on glyphs between FROM and TO of IN, and record
1786 the lastly applied feature in each glyph of IN. If OUT is not
1787 NULL, append the resulting glyphs to OUT while storing glyph
1788 position adjustment information in ADJUSTMENT. */
1790 static int
1791 ftfont_drive_otf (MFLTFont *font,
1792 MFLTOtfSpec *spec,
1793 MFLTGlyphString *in,
1794 int from,
1795 int to,
1796 MFLTGlyphString *out,
1797 MFLTGlyphAdjustment *adjustment)
1799 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1800 FT_Face ft_face = flt_font_ft->ft_face;
1801 OTF *otf = flt_font_ft->otf;
1802 int len = to - from;
1803 int i, j, gidx;
1804 OTF_Glyph *otfg;
1805 char script[5], *langsys = NULL;
1806 char *gsub_features = NULL, *gpos_features = NULL;
1807 OTF_Feature *features;
1809 if (len == 0)
1810 return from;
1811 OTF_tag_name (spec->script, script);
1813 char langsysbuf[5];
1814 if (spec->langsys)
1816 langsys = langsysbuf;
1817 OTF_tag_name (spec->langsys, langsys);
1820 USE_SAFE_ALLOCA;
1821 for (i = 0; i < 2; i++)
1823 char *p;
1825 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1827 for (j = 0; spec->features[i][j]; j++);
1828 SAFE_NALLOCA (p, 6, j);
1829 if (i == 0)
1830 gsub_features = p;
1831 else
1832 gpos_features = p;
1833 for (j = 0; spec->features[i][j]; j++)
1835 if (spec->features[i][j] == 0xFFFFFFFF)
1836 *p++ = '*', *p++ = ',';
1837 else
1839 OTF_tag_name (spec->features[i][j], p);
1840 p[4] = ',';
1841 p += 5;
1844 *--p = '\0';
1848 setup_otf_gstring (len);
1849 for (i = 0; i < len; i++)
1851 otf_gstring.glyphs[i].c = in->glyphs[from + i].c & 0x11FFFF;
1852 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1855 OTF_drive_gdef (otf, &otf_gstring);
1856 gidx = out ? out->used : from;
1858 if (gsub_features && out)
1860 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1861 gsub_features) < 0)
1862 goto simple_copy;
1863 if (out->allocated < out->used + otf_gstring.used)
1865 SAFE_FREE ();
1866 return -2;
1868 features = otf->gsub->FeatureList.Feature;
1869 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1871 MFLTGlyph *g;
1872 int min_from, max_to;
1873 int feature_idx = otfg->positioning_type >> 4;
1875 g = out->glyphs + out->used;
1876 *g = in->glyphs[from + otfg->f.index.from];
1877 if (g->code != otfg->glyph_id)
1879 g->c = 0;
1880 g->code = otfg->glyph_id;
1881 g->measured = 0;
1883 out->used++;
1884 min_from = g->from;
1885 max_to = g->to;
1886 if (otfg->f.index.from < otfg->f.index.to)
1888 /* OTFG substitutes multiple glyphs in IN. */
1889 for (j = from + otfg->f.index.from + 1;
1890 j <= from + otfg->f.index.to; j++)
1892 if (min_from > in->glyphs[j].from)
1893 min_from = in->glyphs[j].from;
1894 if (max_to < in->glyphs[j].to)
1895 max_to = in->glyphs[j].to;
1897 g->from = min_from;
1898 g->to = max_to;
1900 if (feature_idx)
1902 unsigned int tag = features[feature_idx - 1].FeatureTag;
1903 tag = PACK_OTF_TAG (tag);
1904 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1906 for (i++, otfg++; (i < otf_gstring.used
1907 && otfg->f.index.from == otfg[-1].f.index.from);
1908 i++, otfg++)
1910 g = out->glyphs + out->used;
1911 *g = in->glyphs[from + otfg->f.index.to];
1912 if (g->code != otfg->glyph_id)
1914 g->c = 0;
1915 g->code = otfg->glyph_id;
1916 g->measured = 0;
1918 feature_idx = otfg->positioning_type >> 4;
1919 if (feature_idx)
1921 unsigned int tag = features[feature_idx - 1].FeatureTag;
1922 tag = PACK_OTF_TAG (tag);
1923 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1925 out->used++;
1929 else if (gsub_features)
1931 /* Just for checking which features will be applied. */
1932 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1933 gsub_features) < 0)
1934 goto simple_copy;
1935 features = otf->gsub->FeatureList.Feature;
1936 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1937 otfg++)
1939 int feature_idx = otfg->positioning_type >> 4;
1941 if (feature_idx)
1943 unsigned int tag = features[feature_idx - 1].FeatureTag;
1944 tag = PACK_OTF_TAG (tag);
1945 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1947 MFLTGlyph *g = in->glyphs + (from + j);
1948 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1953 else if (out)
1955 if (out->allocated < out->used + len)
1957 SAFE_FREE ();
1958 return -2;
1960 for (i = 0; i < len; i++)
1961 out->glyphs[out->used++] = in->glyphs[from + i];
1964 if (gpos_features && out)
1966 MFLTGlyph *base = NULL, *mark = NULL, *g;
1967 int x_ppem, y_ppem, x_scale, y_scale;
1969 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1970 gpos_features) < 0)
1972 SAFE_FREE ();
1973 return to;
1975 features = otf->gpos->FeatureList.Feature;
1976 x_ppem = ft_face->size->metrics.x_ppem;
1977 y_ppem = ft_face->size->metrics.y_ppem;
1978 x_scale = ft_face->size->metrics.x_scale;
1979 y_scale = ft_face->size->metrics.y_scale;
1981 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1982 i < otf_gstring.used; i++, otfg++, g++)
1984 MFLTGlyph *prev;
1985 int feature_idx = otfg->positioning_type >> 4;
1987 if (feature_idx)
1989 unsigned int tag = features[feature_idx - 1].FeatureTag;
1990 tag = PACK_OTF_TAG (tag);
1991 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1994 if (! otfg->glyph_id)
1995 continue;
1996 switch (otfg->positioning_type & 0xF)
1998 case 0:
1999 break;
2000 case 1: /* Single */
2001 case 2: /* Pair */
2003 int format = otfg->f.f1.format;
2005 if (format & OTF_XPlacement)
2006 adjustment[i].xoff
2007 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2008 if (format & OTF_XPlaDevice)
2009 adjustment[i].xoff
2010 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2011 if (format & OTF_YPlacement)
2012 adjustment[i].yoff
2013 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2014 if (format & OTF_YPlaDevice)
2015 adjustment[i].yoff
2016 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2017 if (format & OTF_XAdvance)
2018 adjustment[i].xadv
2019 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2020 if (format & OTF_XAdvDevice)
2021 adjustment[i].xadv
2022 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2023 if (format & OTF_YAdvance)
2024 adjustment[i].yadv
2025 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2026 if (format & OTF_YAdvDevice)
2027 adjustment[i].yadv
2028 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2029 adjustment[i].set = 1;
2031 break;
2032 case 3: /* Cursive */
2033 /* Not yet supported. */
2034 break;
2035 case 4: /* Mark-to-Base */
2036 case 5: /* Mark-to-Ligature */
2037 if (! base)
2038 break;
2039 prev = base;
2040 goto label_adjust_anchor;
2041 default: /* i.e. case 6 Mark-to-Mark */
2042 if (! mark)
2043 break;
2044 prev = mark;
2046 label_adjust_anchor:
2048 int base_x, base_y, mark_x, mark_y;
2049 int this_from, this_to;
2051 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2052 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2053 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2054 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2056 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2057 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2058 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2059 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2060 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2061 x_ppem, y_ppem, &mark_x, &mark_y);
2062 adjustment[i].xoff = (base_x - mark_x);
2063 adjustment[i].yoff = - (base_y - mark_y);
2064 adjustment[i].back = (g - prev);
2065 adjustment[i].xadv = 0;
2066 adjustment[i].advance_is_absolute = 1;
2067 adjustment[i].set = 1;
2068 this_from = g->from;
2069 this_to = g->to;
2070 for (j = 0; prev + j < g; j++)
2072 if (this_from > prev[j].from)
2073 this_from = prev[j].from;
2074 if (this_to < prev[j].to)
2075 this_to = prev[j].to;
2077 for (; prev <= g; prev++)
2079 prev->from = this_from;
2080 prev->to = this_to;
2084 if (otfg->GlyphClass == OTF_GlyphClass0)
2085 base = mark = g;
2086 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2087 mark = g;
2088 else
2089 base = g;
2092 else if (gpos_features)
2094 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2095 gpos_features) < 0)
2097 SAFE_FREE ();
2098 return to;
2100 features = otf->gpos->FeatureList.Feature;
2101 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2102 i++, otfg++)
2103 if (otfg->positioning_type & 0xF)
2105 int feature_idx = otfg->positioning_type >> 4;
2107 if (feature_idx)
2109 unsigned int tag = features[feature_idx - 1].FeatureTag;
2110 tag = PACK_OTF_TAG (tag);
2111 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2113 MFLTGlyph *g = in->glyphs + (from + j);
2114 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2119 SAFE_FREE ();
2120 return to;
2122 simple_copy:
2123 SAFE_FREE ();
2124 if (! out)
2125 return to;
2126 if (out->allocated < out->used + len)
2127 return -2;
2128 font->get_metrics (font, in, from, to);
2129 memcpy (out->glyphs + out->used, in->glyphs + from,
2130 sizeof (MFLTGlyph) * len);
2131 out->used += len;
2132 return to;
2135 static int
2136 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2137 MFLTGlyphString *in, int from, int to)
2139 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2142 #else /* not M17N_FLT_USE_NEW_FEATURE */
2144 static int
2145 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2146 int from, int to,
2147 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2149 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2150 FT_Face ft_face = flt_font_ft->ft_face;
2151 OTF *otf = flt_font_ft->otf;
2152 int len = to - from;
2153 int i, j, gidx;
2154 OTF_Glyph *otfg;
2155 char script[5], *langsys = NULL;
2156 char *gsub_features = NULL, *gpos_features = NULL;
2158 if (len == 0)
2159 return from;
2160 OTF_tag_name (spec->script, script);
2162 char langsysbuf[5];
2163 if (spec->langsys)
2165 langsys = langsysbuf;
2166 OTF_tag_name (spec->langsys, langsys);
2169 USE_SAFE_ALLOCA;
2170 for (i = 0; i < 2; i++)
2172 char *p;
2174 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2176 for (j = 0; spec->features[i][j]; j++);
2177 SAFE_NALLOCA (p, 6, j);
2178 if (i == 0)
2179 gsub_features = p;
2180 else
2181 gpos_features = p;
2182 for (j = 0; spec->features[i][j]; j++)
2184 if (spec->features[i][j] == 0xFFFFFFFF)
2185 *p++ = '*', *p++ = ',';
2186 else
2188 OTF_tag_name (spec->features[i][j], p);
2189 p[4] = ',';
2190 p += 5;
2193 *--p = '\0';
2197 setup_otf_gstring (len);
2198 for (i = 0; i < len; i++)
2200 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2201 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2204 OTF_drive_gdef (otf, &otf_gstring);
2205 gidx = out->used;
2207 if (gsub_features)
2209 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2210 < 0)
2211 goto simple_copy;
2212 if (out->allocated < out->used + otf_gstring.used)
2214 SAFE_FREE ();
2215 return -2;
2217 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2219 MFLTGlyph *g;
2220 int min_from, max_to;
2221 int j;
2223 g = out->glyphs + out->used;
2224 *g = in->glyphs[from + otfg->f.index.from];
2225 if (g->code != otfg->glyph_id)
2227 g->c = 0;
2228 g->code = otfg->glyph_id;
2229 g->measured = 0;
2231 out->used++;
2232 min_from = g->from;
2233 max_to = g->to;
2234 if (otfg->f.index.from < otfg->f.index.to)
2236 /* OTFG substitutes multiple glyphs in IN. */
2237 for (j = from + otfg->f.index.from + 1;
2238 j <= from + otfg->f.index.to; j++)
2240 if (min_from > in->glyphs[j].from)
2241 min_from = in->glyphs[j].from;
2242 if (max_to < in->glyphs[j].to)
2243 max_to = in->glyphs[j].to;
2245 g->from = min_from;
2246 g->to = max_to;
2248 for (i++, otfg++; (i < otf_gstring.used
2249 && otfg->f.index.from == otfg[-1].f.index.from);
2250 i++, otfg++)
2252 g = out->glyphs + out->used;
2253 *g = in->glyphs[from + otfg->f.index.to];
2254 if (g->code != otfg->glyph_id)
2256 g->c = 0;
2257 g->code = otfg->glyph_id;
2258 g->measured = 0;
2260 out->used++;
2264 else
2266 if (out->allocated < out->used + len)
2268 SAFE_FREE ();
2269 return -2;
2271 for (i = 0; i < len; i++)
2272 out->glyphs[out->used++] = in->glyphs[from + i];
2275 if (gpos_features)
2277 MFLTGlyph *base = NULL, *mark = NULL, *g;
2278 int x_ppem, y_ppem, x_scale, y_scale;
2280 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2281 < 0)
2283 SAFE_FREE ();
2284 return to;
2287 x_ppem = ft_face->size->metrics.x_ppem;
2288 y_ppem = ft_face->size->metrics.y_ppem;
2289 x_scale = ft_face->size->metrics.x_scale;
2290 y_scale = ft_face->size->metrics.y_scale;
2292 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2293 i < otf_gstring.used; i++, otfg++, g++)
2295 MFLTGlyph *prev;
2297 if (! otfg->glyph_id)
2298 continue;
2299 switch (otfg->positioning_type)
2301 case 0:
2302 break;
2303 case 1: /* Single */
2304 case 2: /* Pair */
2306 int format = otfg->f.f1.format;
2308 if (format & OTF_XPlacement)
2309 adjustment[i].xoff
2310 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2311 if (format & OTF_XPlaDevice)
2312 adjustment[i].xoff
2313 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2314 if (format & OTF_YPlacement)
2315 adjustment[i].yoff
2316 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2317 if (format & OTF_YPlaDevice)
2318 adjustment[i].yoff
2319 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2320 if (format & OTF_XAdvance)
2321 adjustment[i].xadv
2322 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2323 if (format & OTF_XAdvDevice)
2324 adjustment[i].xadv
2325 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2326 if (format & OTF_YAdvance)
2327 adjustment[i].yadv
2328 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2329 if (format & OTF_YAdvDevice)
2330 adjustment[i].yadv
2331 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2332 adjustment[i].set = 1;
2334 break;
2335 case 3: /* Cursive */
2336 /* Not yet supported. */
2337 break;
2338 case 4: /* Mark-to-Base */
2339 case 5: /* Mark-to-Ligature */
2340 if (! base)
2341 break;
2342 prev = base;
2343 goto label_adjust_anchor;
2344 default: /* i.e. case 6 Mark-to-Mark */
2345 if (! mark)
2346 break;
2347 prev = mark;
2349 label_adjust_anchor:
2351 int base_x, base_y, mark_x, mark_y;
2352 int this_from, this_to;
2354 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2355 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2356 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2357 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2359 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2360 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2361 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2362 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2363 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2364 x_ppem, y_ppem, &mark_x, &mark_y);
2365 adjustment[i].xoff = (base_x - mark_x);
2366 adjustment[i].yoff = - (base_y - mark_y);
2367 adjustment[i].back = (g - prev);
2368 adjustment[i].xadv = 0;
2369 adjustment[i].advance_is_absolute = 1;
2370 adjustment[i].set = 1;
2371 this_from = g->from;
2372 this_to = g->to;
2373 for (j = 0; prev + j < g; j++)
2375 if (this_from > prev[j].from)
2376 this_from = prev[j].from;
2377 if (this_to < prev[j].to)
2378 this_to = prev[j].to;
2380 for (; prev <= g; prev++)
2382 prev->from = this_from;
2383 prev->to = this_to;
2387 if (otfg->GlyphClass == OTF_GlyphClass0)
2388 base = mark = g;
2389 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2390 mark = g;
2391 else
2392 base = g;
2395 SAFE_FREE ();
2396 return to;
2398 simple_copy:
2399 SAFE_FREE ();
2400 if (out->allocated < out->used + len)
2401 return -2;
2402 font->get_metrics (font, in, from, to);
2403 memcpy (out->glyphs + out->used, in->glyphs + from,
2404 sizeof (MFLTGlyph) * len);
2405 out->used += len;
2406 return to;
2409 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2411 static MFLTGlyphString gstring;
2413 static bool m17n_flt_initialized;
2415 static Lisp_Object
2416 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2417 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2419 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2420 ptrdiff_t i;
2421 struct MFLTFontFT flt_font_ft;
2422 MFLT *flt = NULL;
2423 bool with_variation_selector = 0;
2425 if (! m17n_flt_initialized)
2427 M17N_INIT ();
2428 #ifdef M17N_FLT_USE_NEW_FEATURE
2429 mflt_enable_new_feature = 1;
2430 mflt_try_otf = ftfont_try_otf;
2431 #endif /* M17N_FLT_USE_NEW_FEATURE */
2432 m17n_flt_initialized = 1;
2435 for (i = 0; i < len; i++)
2437 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2438 int c;
2440 if (NILP (g))
2441 break;
2442 c = LGLYPH_CHAR (g);
2443 if (CHAR_VARIATION_SELECTOR_P (c))
2444 with_variation_selector = 1;
2447 len = i;
2449 if (with_variation_selector)
2451 setup_otf_gstring (len);
2452 for (i = 0; i < len; i++)
2454 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2456 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2457 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2458 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2460 OTF_drive_cmap (otf, &otf_gstring);
2461 for (i = 0; i < otf_gstring.used; i++)
2463 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2464 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2465 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2467 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2468 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2469 LGSTRING_SET_GLYPH (lgstring, i, g0);
2471 if (len > otf_gstring.used)
2473 len = otf_gstring.used;
2474 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2478 if (INT_MAX / 2 < len)
2479 memory_full (SIZE_MAX);
2481 if (gstring.allocated == 0)
2483 gstring.glyph_size = sizeof (MFLTGlyph);
2484 gstring.glyphs = xnmalloc (len * 2, sizeof *gstring.glyphs);
2485 gstring.allocated = len * 2;
2487 else if (gstring.allocated < len * 2)
2489 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2,
2490 sizeof *gstring.glyphs);
2491 gstring.allocated = len * 2;
2493 memset (gstring.glyphs, 0, len * sizeof *gstring.glyphs);
2494 for (i = 0; i < len; i++)
2496 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2498 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2499 if (with_variation_selector)
2501 gstring.glyphs[i].code = LGLYPH_CODE (g);
2502 gstring.glyphs[i].encoded = 1;
2506 gstring.used = len;
2507 gstring.r2l = 0;
2510 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2512 if (NILP (family))
2513 flt_font_ft.flt_font.family = Mnil;
2514 else
2515 flt_font_ft.flt_font.family
2516 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2518 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2519 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2520 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2521 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2522 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2523 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2524 flt_font_ft.flt_font.internal = NULL;
2525 flt_font_ft.font = font;
2526 flt_font_ft.ft_face = ft_face;
2527 flt_font_ft.otf = otf;
2528 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2529 if (len > 1
2530 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2531 /* A little bit ad hoc. Perhaps, shaper must get script and
2532 language information, and select a proper flt for them
2533 here. */
2534 flt = mflt_get (msymbol ("combining"));
2535 for (i = 0; i < 3; i++)
2537 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2538 if (result != -2)
2539 break;
2540 if (INT_MAX / 2 < gstring.allocated)
2541 memory_full (SIZE_MAX);
2542 gstring.glyphs = xnrealloc (gstring.glyphs,
2543 gstring.allocated, 2 * sizeof (MFLTGlyph));
2544 gstring.allocated *= 2;
2546 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2547 return Qnil;
2548 for (i = 0; i < gstring.used; i++)
2550 MFLTGlyph *g = gstring.glyphs + i;
2552 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2553 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2556 for (i = 0; i < gstring.used; i++)
2558 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2559 MFLTGlyph *g = gstring.glyphs + i;
2561 if (NILP (lglyph))
2563 lglyph = LGLYPH_NEW ();
2564 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2566 LGLYPH_SET_FROM (lglyph, g->from);
2567 LGLYPH_SET_TO (lglyph, g->to);
2568 LGLYPH_SET_CHAR (lglyph, g->c);
2569 LGLYPH_SET_CODE (lglyph, g->code);
2570 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2571 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2572 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2573 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2574 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2575 if (g->adjusted)
2577 Lisp_Object vec = make_uninit_vector (3);
2579 ASET (vec, 0, make_number (g->xoff >> 6));
2580 ASET (vec, 1, make_number (g->yoff >> 6));
2581 ASET (vec, 2, make_number (g->xadv >> 6));
2582 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2585 return make_number (i);
2588 Lisp_Object
2589 ftfont_shape (Lisp_Object lgstring)
2591 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2592 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2593 OTF *otf = ftfont_get_otf (ftfont_info);
2595 if (! otf)
2596 return make_number (0);
2597 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2598 &ftfont_info->matrix);
2601 #endif /* HAVE_M17N_FLT */
2603 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2605 static int
2606 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2608 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2609 OTF *otf = ftfont_get_otf (ftfont_info);
2611 if (! otf)
2612 return 0;
2613 return OTF_get_variation_glyphs (otf, c, variations);
2616 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2617 #endif /* HAVE_LIBOTF */
2619 static const char *const ftfont_booleans [] = {
2620 ":antialias",
2621 ":hinting",
2622 ":verticallayout",
2623 ":autohint",
2624 ":globaladvance",
2625 ":outline",
2626 ":scalable",
2627 ":minspace",
2628 ":embolden",
2629 NULL,
2632 static const char *const ftfont_non_booleans [] = {
2633 ":family",
2634 ":familylang",
2635 ":style",
2636 ":stylelang",
2637 ":fullname",
2638 ":fullnamelang",
2639 ":slant",
2640 ":weight",
2641 ":size",
2642 ":width",
2643 ":aspect",
2644 ":pixelsize",
2645 ":spacing",
2646 ":foundry",
2647 ":hintstyle",
2648 ":file",
2649 ":index",
2650 ":ftface",
2651 ":rasterizer",
2652 ":scale",
2653 ":dpi",
2654 ":rgba",
2655 ":lcdfilter",
2656 ":charset",
2657 ":lang",
2658 ":fontversion",
2659 ":capability",
2660 NULL,
2663 static void
2664 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2666 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2670 void
2671 syms_of_ftfont (void)
2673 /* Symbolic type of this font-driver. */
2674 DEFSYM (Qfreetype, "freetype");
2676 /* Fontconfig's generic families and their aliases. */
2677 DEFSYM (Qmonospace, "monospace");
2678 DEFSYM (Qsans_serif, "sans-serif");
2679 DEFSYM (Qsans, "sans");
2680 DEFSYM (Qsans__serif, "sans serif");
2682 staticpro (&freetype_font_cache);
2683 freetype_font_cache = list1 (Qt);
2685 staticpro (&ftfont_generic_family_list);
2686 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2687 Fcons (Qsans_serif, Qt),
2688 Fcons (Qsans, Qt));
2690 staticpro (&ft_face_cache);
2691 ft_face_cache = Qnil;
2693 ftfont_driver.type = Qfreetype;
2694 register_font_driver (&ftfont_driver, NULL);