Update copyright year to 2015
[emacs.git] / src / ftfont.c
blob8169806630647753c5b7e528ba5e71e8d9b72d38
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 /* Symbolic type of this font-driver. */
42 static Lisp_Object Qfreetype;
44 /* Fontconfig's generic families and their aliases. */
45 static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
47 /* Flag to tell if FcInit is already called or not. */
48 static bool fc_initialized;
50 /* Handle to a FreeType library instance. */
51 static FT_Library ft_library;
53 /* Cache for FreeType fonts. */
54 static Lisp_Object freetype_font_cache;
56 /* Cache for FT_Face and FcCharSet. */
57 static Lisp_Object ft_face_cache;
59 /* The actual structure for FreeType font that can be cast to struct
60 font. */
62 struct ftfont_info
64 struct font font;
65 #ifdef HAVE_LIBOTF
66 /* The following four members must be here in this order to be
67 compatible with struct xftfont_info (in xftfont.c). */
68 bool maybe_otf; /* Flag to tell if this may be OTF or not. */
69 OTF *otf;
70 #endif /* HAVE_LIBOTF */
71 FT_Size ft_size;
72 int index;
73 FT_Matrix matrix;
76 enum ftfont_cache_for
78 FTFONT_CACHE_FOR_FACE,
79 FTFONT_CACHE_FOR_CHARSET,
80 FTFONT_CACHE_FOR_ENTITY
83 static Lisp_Object ftfont_pattern_entity (FcPattern *, Lisp_Object);
85 static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
86 FcPattern *);
87 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
88 enum ftfont_cache_for);
90 static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
92 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
94 static struct
96 /* registry name */
97 const char *name;
98 /* characters to distinguish the charset from the others */
99 int uniquifier[6];
100 /* additional constraint by language */
101 const char *lang;
102 /* set on demand */
103 FcCharSet *fc_charset;
104 } fc_charset_table[] =
105 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
106 { "iso8859-2", { 0x00A0, 0x010E }},
107 { "iso8859-3", { 0x00A0, 0x0108 }},
108 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
109 { "iso8859-5", { 0x00A0, 0x0401 }},
110 { "iso8859-6", { 0x00A0, 0x060C }},
111 { "iso8859-7", { 0x00A0, 0x0384 }},
112 { "iso8859-8", { 0x00A0, 0x05D0 }},
113 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
114 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
115 { "iso8859-11", { 0x00A0, 0x0E01 }},
116 { "iso8859-13", { 0x00A0, 0x201C }},
117 { "iso8859-14", { 0x00A0, 0x0174 }},
118 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
119 { "iso8859-16", { 0x00A0, 0x0218}},
120 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
121 { "big5-0", { 0xF6B1 }, "zh-tw" },
122 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
123 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
124 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
125 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
126 { "cns11643.1992-3", { 0x201A9 }},
127 { "cns11643.1992-4", { 0x20057 }},
128 { "cns11643.1992-5", { 0x20000 }},
129 { "cns11643.1992-6", { 0x20003 }},
130 { "cns11643.1992-7", { 0x20055 }},
131 { "gbk-0", { 0x4E06 }, "zh-cn"},
132 { "jisx0212.1990-0", { 0x4E44 }},
133 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
134 { "jisx0213.2000-2", { 0xFA49 }},
135 { "jisx0213.2004-1", { 0x20B9F }},
136 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
137 { "tis620.2529-1", { 0x0E01 }, "th"},
138 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
139 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
140 { "mulelao-1", { 0x0E81 }, "lo"},
141 { "unicode-sip", { 0x20000 }},
142 { NULL }
145 static bool
146 matching_prefix (char const *str, ptrdiff_t len, char const *pat)
148 return len == strlen (pat) && c_strncasecmp (str, pat, len) == 0;
151 /* Dirty hack for handing ADSTYLE property.
153 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
154 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
155 "Oblique", "Italic", or any non-normal SWIDTH property names
156 (e.g. SemiCondensed) are appended. In addition, if there's no
157 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
158 "Regular" is used for FC_STYLE (see the function
159 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
161 Unfortunately this behavior is not documented, so the following
162 code may fail if FreeType changes the behavior in the future. */
164 static Lisp_Object
165 get_adstyle_property (FcPattern *p)
167 FcChar8 *fcstr;
168 char *str, *end;
169 Lisp_Object adstyle;
171 #ifdef FC_FONTFORMAT
172 if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
173 && xstrcasecmp ((char *) fcstr, "bdf") != 0
174 && xstrcasecmp ((char *) fcstr, "pcf") != 0)
175 /* Not a BDF nor PCF font. */
176 return Qnil;
177 #endif
178 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
179 return Qnil;
180 str = (char *) fcstr;
181 for (end = str; *end && *end != ' '; end++);
182 if (matching_prefix (str, end - str, "Regular")
183 || matching_prefix (str, end - str, "Bold")
184 || matching_prefix (str, end - str, "Oblique")
185 || matching_prefix (str, end - str, "Italic"))
186 return Qnil;
187 adstyle = font_intern_prop (str, end - str, 1);
188 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
189 return Qnil;
190 return adstyle;
193 static Lisp_Object
194 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
196 Lisp_Object key, cache, entity;
197 FcChar8 *str;
198 char *file;
199 int idx;
200 int numeric;
201 double dbl;
202 FcBool b;
204 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
205 return Qnil;
206 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
207 return Qnil;
209 file = (char *) str;
210 key = Fcons (build_unibyte_string (file), make_number (idx));
211 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
212 entity = XCAR (cache);
213 if (! NILP (entity))
215 Lisp_Object val = font_make_entity ();
216 int i;
218 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
219 ASET (val, i, AREF (entity, i));
221 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
222 font_put_extra (val, QCfont_entity, key);
224 return val;
226 entity = font_make_entity ();
227 XSETCAR (cache, entity);
229 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
230 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
232 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
234 char *s = (char *) str;
235 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
237 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
239 char *s = (char *) str;
240 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
242 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
244 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
245 numeric = FC_WEIGHT_MEDIUM;
246 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
248 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
250 numeric += 100;
251 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
253 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
255 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
257 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
259 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
261 else
262 ASET (entity, FONT_SIZE_INDEX, make_number (0));
263 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
264 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
265 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
267 int dpi = dbl;
268 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
270 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
271 && b == FcTrue)
273 ASET (entity, FONT_SIZE_INDEX, make_number (0));
274 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
276 else
278 /* As this font is not scalable, perhaps this is a BDF or PCF
279 font. */
280 FT_Face ft_face;
282 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
283 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
284 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
286 BDF_PropertyRec rec;
288 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
289 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
290 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
291 FT_Done_Face (ft_face);
295 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
296 font_put_extra (entity, QCfont_entity, key);
297 return entity;
301 static Lisp_Object ftfont_generic_family_list;
303 static Lisp_Object
304 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
306 Lisp_Object slot;
307 FcPattern *match;
308 FcResult result;
309 FcLangSet *langset;
311 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
312 if (EQ (family, Qmono))
313 family = Qmonospace;
314 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
315 family = Qsans_serif;
316 slot = assq_no_quit (family, ftfont_generic_family_list);
317 if (! CONSP (slot))
318 return Qnil;
319 if (! EQ (XCDR (slot), Qt))
320 return XCDR (slot);
321 pattern = FcPatternDuplicate (pattern);
322 if (! pattern)
323 goto err;
324 FcPatternDel (pattern, FC_FOUNDRY);
325 FcPatternDel (pattern, FC_FAMILY);
326 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
327 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
329 /* This is to avoid the effect of locale. */
330 static const FcChar8 lang[] = "en";
331 langset = FcLangSetCreate ();
332 FcLangSetAdd (langset, lang);
333 FcPatternAddLangSet (pattern, FC_LANG, langset);
334 FcLangSetDestroy (langset);
336 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
337 FcDefaultSubstitute (pattern);
338 match = FcFontMatch (NULL, pattern, &result);
339 if (match)
341 FcChar8 *fam;
343 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
344 family = intern ((char *) fam);
346 else
347 family = Qnil;
348 XSETCDR (slot, family);
349 if (match) FcPatternDestroy (match);
350 err:
351 if (pattern) FcPatternDestroy (pattern);
352 return family;
355 struct ftfont_cache_data
357 FT_Face ft_face;
358 FcCharSet *fc_charset;
361 static Lisp_Object
362 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
364 Lisp_Object cache, val, entity;
365 struct ftfont_cache_data *cache_data;
367 if (FONT_ENTITY_P (key))
369 entity = key;
370 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
371 eassert (CONSP (val));
372 key = XCDR (val);
374 else
375 entity = Qnil;
377 if (NILP (ft_face_cache))
378 cache = Qnil;
379 else
380 cache = Fgethash (key, ft_face_cache, Qnil);
381 if (NILP (cache))
383 if (NILP (ft_face_cache))
385 Lisp_Object args[2];
387 args[0] = QCtest;
388 args[1] = Qequal;
389 ft_face_cache = Fmake_hash_table (2, args);
391 cache_data = xmalloc (sizeof *cache_data);
392 cache_data->ft_face = NULL;
393 cache_data->fc_charset = NULL;
394 val = make_save_ptr_int (cache_data, 0);
395 cache = Fcons (Qnil, val);
396 Fputhash (key, cache, ft_face_cache);
398 else
400 val = XCDR (cache);
401 cache_data = XSAVE_POINTER (val, 0);
404 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
405 return cache;
407 if (cache_for == FTFONT_CACHE_FOR_FACE
408 ? ! cache_data->ft_face : ! cache_data->fc_charset)
410 char *filename = SSDATA (XCAR (key));
411 int idx = XINT (XCDR (key));
413 if (cache_for == FTFONT_CACHE_FOR_FACE)
415 if (! ft_library
416 && FT_Init_FreeType (&ft_library) != 0)
417 return Qnil;
418 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
419 != 0)
420 return Qnil;
422 else
424 FcPattern *pat = NULL;
425 FcFontSet *fontset = NULL;
426 FcObjectSet *objset = NULL;
427 FcCharSet *charset = NULL;
429 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
430 FC_INDEX, FcTypeInteger, idx, NULL);
431 if (! pat)
432 goto finish;
433 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
434 if (! objset)
435 goto finish;
436 fontset = FcFontList (NULL, pat, objset);
437 if (! fontset)
438 goto finish;
439 if (fontset && fontset->nfont > 0
440 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
441 &charset)
442 == FcResultMatch))
443 cache_data->fc_charset = FcCharSetCopy (charset);
444 else
445 cache_data->fc_charset = FcCharSetCreate ();
447 finish:
448 if (fontset)
449 FcFontSetDestroy (fontset);
450 if (objset)
451 FcObjectSetDestroy (objset);
452 if (pat)
453 FcPatternDestroy (pat);
456 return cache;
459 FcCharSet *
460 ftfont_get_fc_charset (Lisp_Object entity)
462 Lisp_Object val, cache;
463 struct ftfont_cache_data *cache_data;
465 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
466 val = XCDR (cache);
467 cache_data = XSAVE_POINTER (val, 0);
468 return cache_data->fc_charset;
471 #ifdef HAVE_LIBOTF
472 static OTF *
473 ftfont_get_otf (struct ftfont_info *ftfont_info)
475 OTF *otf;
477 if (ftfont_info->otf)
478 return ftfont_info->otf;
479 if (! ftfont_info->maybe_otf)
480 return NULL;
481 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
482 if (! otf || OTF_get_table (otf, "head") < 0)
484 if (otf)
485 OTF_close (otf);
486 ftfont_info->maybe_otf = 0;
487 return NULL;
489 ftfont_info->otf = otf;
490 return otf;
492 #endif /* HAVE_LIBOTF */
494 static Lisp_Object ftfont_get_cache (struct frame *);
495 static Lisp_Object ftfont_list (struct frame *, Lisp_Object);
496 static Lisp_Object ftfont_match (struct frame *, Lisp_Object);
497 static Lisp_Object ftfont_list_family (struct frame *);
498 static Lisp_Object ftfont_open (struct frame *, Lisp_Object, int);
499 static void ftfont_close (struct font *);
500 static int ftfont_has_char (Lisp_Object, int);
501 static unsigned ftfont_encode_char (struct font *, int);
502 static void ftfont_text_extents (struct font *, unsigned *, int,
503 struct font_metrics *);
504 static int ftfont_get_bitmap (struct font *, unsigned,
505 struct font_bitmap *, int);
506 static int ftfont_anchor_point (struct font *, unsigned, int,
507 int *, int *);
508 #ifdef HAVE_LIBOTF
509 static Lisp_Object ftfont_otf_capability (struct font *);
510 # ifdef HAVE_M17N_FLT
511 static Lisp_Object ftfont_shape (Lisp_Object);
512 # endif
513 #endif
515 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
516 static int ftfont_variation_glyphs (struct font *, int c,
517 unsigned variations[256]);
518 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
520 struct font_driver ftfont_driver =
522 LISP_INITIALLY_ZERO, /* Qfreetype */
523 0, /* case insensitive */
524 ftfont_get_cache,
525 ftfont_list,
526 ftfont_match,
527 ftfont_list_family,
528 NULL, /* free_entity */
529 ftfont_open,
530 ftfont_close,
531 /* We can't draw a text without device dependent functions. */
532 NULL, /* prepare_face */
533 NULL, /* done_face */
534 ftfont_has_char,
535 ftfont_encode_char,
536 ftfont_text_extents,
537 /* We can't draw a text without device dependent functions. */
538 NULL, /* draw */
539 ftfont_get_bitmap,
540 NULL, /* free_bitmap */
541 ftfont_anchor_point,
542 #ifdef HAVE_LIBOTF
543 ftfont_otf_capability,
544 #else /* not HAVE_LIBOTF */
545 NULL,
546 #endif /* not HAVE_LIBOTF */
547 NULL, /* otf_drive */
548 NULL, /* start_for_frame */
549 NULL, /* end_for_frame */
550 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
551 ftfont_shape,
552 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
553 NULL,
554 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
555 NULL, /* check */
557 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
558 ftfont_variation_glyphs,
559 #else
560 NULL,
561 #endif
563 ftfont_filter_properties, /* filter_properties */
566 static Lisp_Object
567 ftfont_get_cache (struct frame *f)
569 return freetype_font_cache;
572 static int
573 ftfont_get_charset (Lisp_Object registry)
575 char *str = SSDATA (SYMBOL_NAME (registry));
576 USE_SAFE_ALLOCA;
577 char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
578 Lisp_Object regexp;
579 int i, j;
581 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
583 if (str[i] == '.')
584 re[j++] = '\\';
585 else if (str[i] == '*')
586 re[j++] = '.';
587 re[j] = str[i];
588 if (re[j] == '?')
589 re[j] = '.';
591 re[j] = '\0';
592 regexp = make_unibyte_string (re, j);
593 SAFE_FREE ();
594 for (i = 0; fc_charset_table[i].name; i++)
595 if (fast_c_string_match_ignore_case
596 (regexp, fc_charset_table[i].name,
597 strlen (fc_charset_table[i].name)) >= 0)
598 break;
599 if (! fc_charset_table[i].name)
600 return -1;
601 if (! fc_charset_table[i].fc_charset)
603 FcCharSet *charset = FcCharSetCreate ();
604 int *uniquifier = fc_charset_table[i].uniquifier;
606 if (! charset)
607 return -1;
608 for (j = 0; uniquifier[j]; j++)
609 if (! FcCharSetAddChar (charset, uniquifier[j]))
611 FcCharSetDestroy (charset);
612 return -1;
614 fc_charset_table[i].fc_charset = charset;
616 return i;
619 struct OpenTypeSpec
621 Lisp_Object script;
622 unsigned int script_tag, langsys_tag;
623 int nfeatures[2];
624 unsigned int *features[2];
627 #define OTF_SYM_TAG(SYM, TAG) \
628 do { \
629 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
630 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
631 } while (0)
633 #define OTF_TAG_STR(TAG, P) \
634 do { \
635 (P)[0] = (char) (TAG >> 24); \
636 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
637 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
638 (P)[3] = (char) (TAG & 0xFF); \
639 (P)[4] = '\0'; \
640 } while (0)
642 #ifdef HAVE_LIBOTF
643 #define OTF_TAG_SYM(SYM, TAG) \
644 do { \
645 char str[5]; \
647 OTF_TAG_STR (TAG, str); \
648 (SYM) = font_intern_prop (str, 4, 1); \
649 } while (0)
650 #endif
653 static struct OpenTypeSpec *
654 ftfont_get_open_type_spec (Lisp_Object otf_spec)
656 struct OpenTypeSpec *spec = malloc (sizeof *spec);
657 Lisp_Object val;
658 int i, j;
659 bool negative;
661 if (! spec)
662 return NULL;
663 spec->script = XCAR (otf_spec);
664 if (! NILP (spec->script))
666 OTF_SYM_TAG (spec->script, spec->script_tag);
667 val = assq_no_quit (spec->script, Votf_script_alist);
668 if (CONSP (val) && SYMBOLP (XCDR (val)))
669 spec->script = XCDR (val);
670 else
671 spec->script = Qnil;
673 else
674 spec->script_tag = 0x44464C54; /* "DFLT" */
675 otf_spec = XCDR (otf_spec);
676 spec->langsys_tag = 0;
677 if (! NILP (otf_spec))
679 val = XCAR (otf_spec);
680 if (! NILP (val))
681 OTF_SYM_TAG (val, spec->langsys_tag);
682 otf_spec = XCDR (otf_spec);
684 spec->nfeatures[0] = spec->nfeatures[1] = 0;
685 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
687 Lisp_Object len;
689 val = XCAR (otf_spec);
690 if (NILP (val))
691 continue;
692 len = Flength (val);
693 spec->features[i] =
694 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
696 : malloc (XINT (len) * sizeof *spec->features[i]));
697 if (! spec->features[i])
699 if (i > 0 && spec->features[0])
700 free (spec->features[0]);
701 free (spec);
702 return NULL;
704 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
706 if (NILP (XCAR (val)))
707 negative = 1;
708 else
710 unsigned int tag;
712 OTF_SYM_TAG (XCAR (val), tag);
713 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
716 spec->nfeatures[i] = j;
718 return spec;
721 static FcPattern *
722 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
724 Lisp_Object tmp, extra;
725 FcPattern *pattern = NULL;
726 FcCharSet *charset = NULL;
727 FcLangSet *langset = NULL;
728 int n;
729 int dpi = -1;
730 int scalable = -1;
731 Lisp_Object script = Qnil;
732 Lisp_Object registry;
733 int fc_charset_idx;
735 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
736 && n < 100)
737 /* Fontconfig doesn't support reverse-italic/oblique. */
738 return NULL;
740 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
741 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
742 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
743 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
744 scalable = 1;
746 registry = AREF (spec, FONT_REGISTRY_INDEX);
747 if (NILP (registry)
748 || EQ (registry, Qascii_0)
749 || EQ (registry, Qiso10646_1)
750 || EQ (registry, Qunicode_bmp))
751 fc_charset_idx = -1;
752 else
754 FcChar8 *lang;
756 fc_charset_idx = ftfont_get_charset (registry);
757 if (fc_charset_idx < 0)
758 return NULL;
759 charset = fc_charset_table[fc_charset_idx].fc_charset;
760 *langname = fc_charset_table[fc_charset_idx].lang;
761 lang = (FcChar8 *) *langname;
762 if (lang)
764 langset = FcLangSetCreate ();
765 if (! langset)
766 goto err;
767 FcLangSetAdd (langset, lang);
771 otlayout[0] = '\0';
772 for (extra = AREF (spec, FONT_EXTRA_INDEX);
773 CONSP (extra); extra = XCDR (extra))
775 Lisp_Object key, val;
777 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
778 if (EQ (key, QCdpi))
780 if (INTEGERP (val))
781 dpi = XINT (val);
783 else if (EQ (key, QClang))
785 if (! langset)
786 langset = FcLangSetCreate ();
787 if (! langset)
788 goto err;
789 if (SYMBOLP (val))
791 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
792 goto err;
794 else
795 for (; CONSP (val); val = XCDR (val))
796 if (SYMBOLP (XCAR (val))
797 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
798 goto err;
800 else if (EQ (key, QCotf))
802 if (CONSP (val))
804 *otspec = ftfont_get_open_type_spec (val);
805 if (! *otspec)
806 return NULL;
807 strcpy (otlayout, "otlayout:");
808 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
809 script = (*otspec)->script;
812 else if (EQ (key, QCscript))
813 script = val;
814 else if (EQ (key, QCscalable))
815 scalable = ! NILP (val);
818 if (! NILP (script) && ! charset)
820 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
822 if (CONSP (chars) && CONSP (CDR (chars)))
824 charset = FcCharSetCreate ();
825 if (! charset)
826 goto err;
827 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
828 if (CHARACTERP (XCAR (chars))
829 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
830 goto err;
834 pattern = FcPatternCreate ();
835 if (! pattern)
836 goto err;
837 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
838 if (! NILP (tmp)
839 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
840 goto err;
841 tmp = AREF (spec, FONT_FAMILY_INDEX);
842 if (! NILP (tmp)
843 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
844 goto err;
845 if (charset
846 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
847 goto err;
848 if (langset
849 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
850 goto err;
851 if (dpi >= 0
852 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
853 goto err;
854 if (scalable >= 0
855 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
856 goto err;
858 goto finish;
860 err:
861 /* We come here because of unexpected error in fontconfig API call
862 (usually insufficient memory). */
863 if (pattern)
865 FcPatternDestroy (pattern);
866 pattern = NULL;
868 if (*otspec)
870 if ((*otspec)->nfeatures[0] > 0)
871 free ((*otspec)->features[0]);
872 if ((*otspec)->nfeatures[1] > 0)
873 free ((*otspec)->features[1]);
874 free (*otspec);
875 *otspec = NULL;
878 finish:
879 if (langset) FcLangSetDestroy (langset);
880 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
881 return pattern;
884 static Lisp_Object
885 ftfont_list (struct frame *f, Lisp_Object spec)
887 Lisp_Object val = Qnil, family, adstyle;
888 int i;
889 FcPattern *pattern;
890 FcFontSet *fontset = NULL;
891 FcObjectSet *objset = NULL;
892 FcCharSet *charset;
893 Lisp_Object chars = Qnil;
894 char otlayout[15]; /* For "otlayout:XXXX" */
895 struct OpenTypeSpec *otspec = NULL;
896 int spacing = -1;
897 const char *langname = NULL;
899 if (! fc_initialized)
901 FcInit ();
902 fc_initialized = 1;
905 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
906 if (! pattern)
907 return Qnil;
908 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
910 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
911 if (! NILP (val))
913 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
914 if (CONSP (val) && VECTORP (XCDR (val)))
915 chars = XCDR (val);
917 val = Qnil;
919 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
920 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
921 family = AREF (spec, FONT_FAMILY_INDEX);
922 if (! NILP (family))
924 Lisp_Object resolved;
926 resolved = ftfont_resolve_generic_family (family, pattern);
927 if (! NILP (resolved))
929 FcPatternDel (pattern, FC_FAMILY);
930 if (! FcPatternAddString (pattern, FC_FAMILY,
931 SYMBOL_FcChar8 (resolved)))
932 goto err;
935 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
936 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
937 adstyle = Qnil;
938 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
939 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
940 FC_STYLE, FC_FILE, FC_INDEX,
941 #ifdef FC_CAPABILITY
942 FC_CAPABILITY,
943 #endif /* FC_CAPABILITY */
944 #ifdef FC_FONTFORMAT
945 FC_FONTFORMAT,
946 #endif
947 NULL);
948 if (! objset)
949 goto err;
950 if (! NILP (chars))
951 FcObjectSetAdd (objset, FC_CHARSET);
953 fontset = FcFontList (NULL, pattern, objset);
954 if (! fontset || fontset->nfont == 0)
955 goto finish;
956 #if 0
957 /* Need fix because this finds any fonts. */
958 if (fontset->nfont == 0 && ! NILP (family))
960 /* Try matching with configuration. For instance, the
961 configuration may specify "Nimbus Mono L" as an alias of
962 "Courier". */
963 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
964 SYMBOL_FcChar8 (family), NULL);
965 FcChar8 *fam;
967 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
969 for (i = 0;
970 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
971 i++)
973 FcPatternDel (pattern, FC_FAMILY);
974 FcPatternAddString (pattern, FC_FAMILY, fam);
975 FcFontSetDestroy (fontset);
976 fontset = FcFontList (NULL, pattern, objset);
977 if (fontset && fontset->nfont > 0)
978 break;
982 #endif
983 for (i = 0; i < fontset->nfont; i++)
985 Lisp_Object entity;
987 if (spacing >= 0)
989 int this;
991 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
992 == FcResultMatch)
993 && spacing != this)
994 continue;
997 #ifdef FC_CAPABILITY
998 if (otlayout[0])
1000 FcChar8 *this;
1002 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
1003 != FcResultMatch
1004 || ! strstr ((char *) this, otlayout))
1005 continue;
1007 #endif /* FC_CAPABILITY */
1008 #ifdef HAVE_LIBOTF
1009 if (otspec)
1011 FcChar8 *file;
1012 bool passed;
1013 OTF *otf;
1015 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1016 != FcResultMatch)
1017 continue;
1018 otf = OTF_open ((char *) file);
1019 if (! otf)
1020 continue;
1021 passed = (OTF_check_features (otf, 1, otspec->script_tag,
1022 otspec->langsys_tag,
1023 otspec->features[0],
1024 otspec->nfeatures[0]) == 1
1025 && OTF_check_features (otf, 0, otspec->script_tag,
1026 otspec->langsys_tag,
1027 otspec->features[1],
1028 otspec->nfeatures[1]) == 1);
1029 OTF_close (otf);
1030 if (!passed)
1031 continue;
1033 #endif /* HAVE_LIBOTF */
1034 if (VECTORP (chars))
1036 ptrdiff_t j;
1038 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1039 != FcResultMatch)
1040 continue;
1041 for (j = 0; j < ASIZE (chars); j++)
1042 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1043 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1044 break;
1045 if (j == ASIZE (chars))
1046 continue;
1048 if (! NILP (adstyle) || langname)
1050 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1052 if (! NILP (adstyle)
1053 && (NILP (this_adstyle)
1054 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1055 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1056 continue;
1057 if (langname
1058 && ! NILP (this_adstyle)
1059 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1060 continue;
1062 entity = ftfont_pattern_entity (fontset->fonts[i],
1063 AREF (spec, FONT_EXTRA_INDEX));
1064 if (! NILP (entity))
1065 val = Fcons (entity, val);
1067 val = Fnreverse (val);
1068 goto finish;
1070 err:
1071 /* We come here because of unexpected error in fontconfig API call
1072 (usually insufficient memory). */
1073 val = Qnil;
1075 finish:
1076 FONT_ADD_LOG ("ftfont-list", spec, val);
1077 if (objset) FcObjectSetDestroy (objset);
1078 if (fontset) FcFontSetDestroy (fontset);
1079 if (pattern) FcPatternDestroy (pattern);
1080 return val;
1083 static Lisp_Object
1084 ftfont_match (struct frame *f, Lisp_Object spec)
1086 Lisp_Object entity = Qnil;
1087 FcPattern *pattern, *match = NULL;
1088 FcResult result;
1089 char otlayout[15]; /* For "otlayout:XXXX" */
1090 struct OpenTypeSpec *otspec = NULL;
1091 const char *langname = NULL;
1093 if (! fc_initialized)
1095 FcInit ();
1096 fc_initialized = 1;
1099 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1100 if (! pattern)
1101 return Qnil;
1103 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1105 FcValue value;
1107 value.type = FcTypeDouble;
1108 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1109 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1111 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1113 FcDefaultSubstitute (pattern);
1114 match = FcFontMatch (NULL, pattern, &result);
1115 if (match)
1117 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1118 FcPatternDestroy (match);
1119 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1120 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1121 ftfont_generic_family_list))
1122 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1123 AREF (entity, FONT_FAMILY_INDEX))))
1124 entity = Qnil;
1127 FcPatternDestroy (pattern);
1129 FONT_ADD_LOG ("ftfont-match", spec, entity);
1130 return entity;
1133 static Lisp_Object
1134 ftfont_list_family (struct frame *f)
1136 Lisp_Object list = Qnil;
1137 FcPattern *pattern = NULL;
1138 FcFontSet *fontset = NULL;
1139 FcObjectSet *objset = NULL;
1140 int i;
1142 if (! fc_initialized)
1144 FcInit ();
1145 fc_initialized = 1;
1148 pattern = FcPatternCreate ();
1149 if (! pattern)
1150 goto finish;
1151 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1152 if (! objset)
1153 goto finish;
1154 fontset = FcFontList (NULL, pattern, objset);
1155 if (! fontset)
1156 goto finish;
1158 for (i = 0; i < fontset->nfont; i++)
1160 FcPattern *pat = fontset->fonts[i];
1161 FcChar8 *str;
1163 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1164 list = Fcons (intern ((char *) str), list);
1167 finish:
1168 if (objset) FcObjectSetDestroy (objset);
1169 if (fontset) FcFontSetDestroy (fontset);
1170 if (pattern) FcPatternDestroy (pattern);
1172 return list;
1176 static Lisp_Object
1177 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1179 struct ftfont_info *ftfont_info;
1180 struct font *font;
1181 struct ftfont_cache_data *cache_data;
1182 FT_Face ft_face;
1183 FT_Size ft_size;
1184 FT_UInt size;
1185 Lisp_Object val, filename, idx, cache, font_object;
1186 bool scalable;
1187 int spacing;
1188 int i;
1189 int upEM;
1191 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1192 if (! CONSP (val))
1193 return Qnil;
1194 val = XCDR (val);
1195 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1196 if (NILP (cache))
1197 return Qnil;
1198 filename = XCAR (val);
1199 idx = XCDR (val);
1200 val = XCDR (cache);
1201 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1202 ft_face = cache_data->ft_face;
1203 if (XSAVE_INTEGER (val, 1) > 0)
1205 /* FT_Face in this cache is already used by the different size. */
1206 if (FT_New_Size (ft_face, &ft_size) != 0)
1207 return Qnil;
1208 if (FT_Activate_Size (ft_size) != 0)
1210 FT_Done_Size (ft_size);
1211 return Qnil;
1214 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1215 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1216 if (size == 0)
1217 size = pixel_size;
1218 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1220 if (XSAVE_INTEGER (val, 1) == 0)
1221 FT_Done_Face (ft_face);
1222 return Qnil;
1225 font_object = font_build_object (VECSIZE (struct ftfont_info),
1226 Qfreetype, entity, size);
1227 ASET (font_object, FONT_FILE_INDEX, filename);
1228 font = XFONT_OBJECT (font_object);
1229 ftfont_info = (struct ftfont_info *) font;
1230 ftfont_info->ft_size = ft_face->size;
1231 ftfont_info->index = XINT (idx);
1232 #ifdef HAVE_LIBOTF
1233 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1234 ftfont_info->otf = NULL;
1235 #endif /* HAVE_LIBOTF */
1236 /* This means that there's no need of transformation. */
1237 ftfont_info->matrix.xx = 0;
1238 font->pixel_size = size;
1239 font->driver = &ftfont_driver;
1240 font->encoding_charset = font->repertory_charset = -1;
1242 upEM = ft_face->units_per_EM;
1243 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1244 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1245 if (scalable)
1247 font->ascent = ft_face->ascender * size / upEM;
1248 font->descent = - ft_face->descender * size / upEM;
1249 font->height = ft_face->height * size / upEM;
1251 else
1253 font->ascent = ft_face->size->metrics.ascender >> 6;
1254 font->descent = - ft_face->size->metrics.descender >> 6;
1255 font->height = ft_face->size->metrics.height >> 6;
1257 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1258 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1259 else
1260 spacing = FC_PROPORTIONAL;
1261 if (spacing != FC_PROPORTIONAL
1262 #ifdef FC_DUAL
1263 && spacing != FC_DUAL
1264 #endif /* FC_DUAL */
1266 font->min_width = font->average_width = font->space_width
1267 = (scalable ? ft_face->max_advance_width * size / upEM
1268 : ft_face->size->metrics.max_advance >> 6);
1269 else
1271 int n;
1273 font->min_width = font->average_width = font->space_width = 0;
1274 for (i = 32, n = 0; i < 127; i++)
1275 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1277 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1279 if (this_width > 0
1280 && (! font->min_width || font->min_width > this_width))
1281 font->min_width = this_width;
1282 if (i == 32)
1283 font->space_width = this_width;
1284 font->average_width += this_width;
1285 n++;
1287 if (n > 0)
1288 font->average_width /= n;
1291 font->baseline_offset = 0;
1292 font->relative_compose = 0;
1293 font->default_ascent = 0;
1294 font->vertical_centering = 0;
1295 if (scalable)
1297 font->underline_position = -ft_face->underline_position * size / upEM;
1298 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1300 else
1302 font->underline_position = -1;
1303 font->underline_thickness = 0;
1306 return font_object;
1309 static void
1310 ftfont_close (struct font *font)
1312 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1313 Lisp_Object val, cache;
1315 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1316 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1317 eassert (CONSP (cache));
1318 val = XCDR (cache);
1319 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1320 if (XSAVE_INTEGER (val, 1) == 0)
1322 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1324 FT_Done_Face (cache_data->ft_face);
1325 #ifdef HAVE_LIBOTF
1326 if (ftfont_info->otf)
1327 OTF_close (ftfont_info->otf);
1328 #endif
1329 cache_data->ft_face = NULL;
1331 else
1332 FT_Done_Size (ftfont_info->ft_size);
1335 static int
1336 ftfont_has_char (Lisp_Object font, int c)
1338 struct charset *cs = NULL;
1340 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1341 && charset_jisx0208 >= 0)
1342 cs = CHARSET_FROM_ID (charset_jisx0208);
1343 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1344 && charset_ksc5601 >= 0)
1345 cs = CHARSET_FROM_ID (charset_ksc5601);
1346 if (cs)
1347 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1349 if (FONT_ENTITY_P (font))
1351 FcCharSet *charset = ftfont_get_fc_charset (font);
1353 return (FcCharSetHasChar (charset, c) == FcTrue);
1355 else
1357 struct ftfont_info *ftfont_info;
1359 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1360 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1361 != 0);
1365 static unsigned
1366 ftfont_encode_char (struct font *font, int c)
1368 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1369 FT_Face ft_face = ftfont_info->ft_size->face;
1370 FT_ULong charcode = c;
1371 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1373 return (code > 0 ? code : FONT_INVALID_CODE);
1376 static void
1377 ftfont_text_extents (struct font *font, unsigned int *code,
1378 int nglyphs, struct font_metrics *metrics)
1380 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1381 FT_Face ft_face = ftfont_info->ft_size->face;
1382 int i, width = 0;
1383 bool first;
1385 if (ftfont_info->ft_size != ft_face->size)
1386 FT_Activate_Size (ftfont_info->ft_size);
1388 for (i = 0, first = 1; i < nglyphs; i++)
1390 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1392 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1394 if (first)
1396 metrics->lbearing = m->horiBearingX >> 6;
1397 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1398 metrics->ascent = m->horiBearingY >> 6;
1399 metrics->descent = (m->height - m->horiBearingY) >> 6;
1400 first = 0;
1402 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1403 metrics->lbearing = width + (m->horiBearingX >> 6);
1404 if (metrics->rbearing
1405 < width + ((m->horiBearingX + m->width) >> 6))
1406 metrics->rbearing
1407 = width + ((m->horiBearingX + m->width) >> 6);
1408 if (metrics->ascent < (m->horiBearingY >> 6))
1409 metrics->ascent = m->horiBearingY >> 6;
1410 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1411 metrics->descent = (m->height - m->horiBearingY) >> 6;
1412 width += m->horiAdvance >> 6;
1414 else
1415 width += font->space_width;
1417 metrics->width = width;
1420 static int
1421 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1423 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1424 FT_Face ft_face = ftfont_info->ft_size->face;
1425 FT_Int32 load_flags = FT_LOAD_RENDER;
1427 if (ftfont_info->ft_size != ft_face->size)
1428 FT_Activate_Size (ftfont_info->ft_size);
1429 if (bits_per_pixel == 1)
1431 #ifdef FT_LOAD_TARGET_MONO
1432 load_flags |= FT_LOAD_TARGET_MONO;
1433 #else
1434 load_flags |= FT_LOAD_MONOCHROME;
1435 #endif
1437 else if (bits_per_pixel != 8)
1438 /* We don't support such a rendering. */
1439 return -1;
1441 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1442 return -1;
1443 bitmap->bits_per_pixel
1444 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1445 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1446 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1447 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1448 : -1);
1449 if (bitmap->bits_per_pixel < 0)
1450 /* We don't support that kind of pixel mode. */
1451 return -1;
1452 bitmap->rows = ft_face->glyph->bitmap.rows;
1453 bitmap->width = ft_face->glyph->bitmap.width;
1454 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1455 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1456 bitmap->left = ft_face->glyph->bitmap_left;
1457 bitmap->top = ft_face->glyph->bitmap_top;
1458 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1460 return 0;
1463 static int
1464 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1465 int *x, int *y)
1467 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1468 FT_Face ft_face = ftfont_info->ft_size->face;
1470 if (ftfont_info->ft_size != ft_face->size)
1471 FT_Activate_Size (ftfont_info->ft_size);
1472 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1473 return -1;
1474 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1475 return -1;
1476 if (idx >= ft_face->glyph->outline.n_points)
1477 return -1;
1478 *x = ft_face->glyph->outline.points[idx].x;
1479 *y = ft_face->glyph->outline.points[idx].y;
1480 return 0;
1483 #ifdef HAVE_LIBOTF
1485 static Lisp_Object
1486 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1488 Lisp_Object scripts, langsyses, features, sym;
1489 int i, j, k, l;
1491 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1493 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1495 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1497 OTF_LangSys *otf_langsys;
1499 if (j >= 0)
1500 otf_langsys = otf_script->LangSys + j;
1501 else if (otf_script->DefaultLangSysOffset)
1502 otf_langsys = &otf_script->DefaultLangSys;
1503 else
1504 break;
1506 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1508 l = otf_langsys->FeatureIndex[k];
1509 if (l >= gsub_gpos->FeatureList.FeatureCount)
1510 continue;
1511 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1512 features = Fcons (sym, features);
1514 if (j >= 0)
1515 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1516 else
1517 sym = Qnil;
1518 langsyses = Fcons (Fcons (sym, features), langsyses);
1521 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1522 scripts = Fcons (Fcons (sym, langsyses), scripts);
1524 return scripts;
1529 static Lisp_Object
1530 ftfont_otf_capability (struct font *font)
1532 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1533 OTF *otf = ftfont_get_otf (ftfont_info);
1534 Lisp_Object gsub_gpos;
1536 if (! otf)
1537 return Qnil;
1538 gsub_gpos = Fcons (Qnil, Qnil);
1539 if (OTF_get_table (otf, "GSUB") == 0
1540 && otf->gsub->FeatureList.FeatureCount > 0)
1541 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1542 if (OTF_get_table (otf, "GPOS") == 0
1543 && otf->gpos->FeatureList.FeatureCount > 0)
1544 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1545 return gsub_gpos;
1548 #ifdef HAVE_M17N_FLT
1550 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1551 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1552 /* We can use the new feature of libotf and m17n-flt to handle the
1553 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1554 some Agian scripts. */
1555 #define M17N_FLT_USE_NEW_FEATURE
1556 #endif
1558 struct MFLTFontFT
1560 MFLTFont flt_font;
1561 struct font *font;
1562 FT_Face ft_face;
1563 OTF *otf;
1564 FT_Matrix *matrix;
1567 static int
1568 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1569 int from, int to)
1571 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1572 FT_Face ft_face = flt_font_ft->ft_face;
1573 MFLTGlyph *g;
1575 for (g = gstring->glyphs + from; from < to; g++, from++)
1576 if (! g->encoded)
1578 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1580 g->code = code > 0 ? code : FONT_INVALID_CODE;
1581 g->encoded = 1;
1583 return 0;
1586 /* Operators for 26.6 fixed fractional pixel format */
1588 #define FLOOR(x) ((x) & -64)
1589 #define CEIL(x) (((x)+63) & -64)
1590 #define ROUND(x) (((x)+32) & -64)
1592 static int
1593 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1594 int from, int to)
1596 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1597 FT_Face ft_face = flt_font_ft->ft_face;
1598 MFLTGlyph *g;
1600 for (g = gstring->glyphs + from; from < to; g++, from++)
1601 if (! g->measured)
1603 if (g->code != FONT_INVALID_CODE)
1605 FT_Glyph_Metrics *m;
1607 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1608 emacs_abort ();
1609 m = &ft_face->glyph->metrics;
1610 if (flt_font_ft->matrix)
1612 FT_Vector v[4];
1613 int i;
1615 v[0].x = v[1].x = m->horiBearingX;
1616 v[2].x = v[3].x = m->horiBearingX + m->width;
1617 v[0].y = v[2].y = m->horiBearingY;
1618 v[1].y = v[3].y = m->horiBearingY - m->height;
1619 for (i = 0; i < 4; i++)
1620 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1621 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1622 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1623 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1624 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1626 else
1628 g->lbearing = FLOOR (m->horiBearingX);
1629 g->rbearing = CEIL (m->horiBearingX + m->width);
1630 g->ascent = CEIL (m->horiBearingY);
1631 g->descent = - FLOOR (m->horiBearingY - m->height);
1633 g->xadv = ROUND (ft_face->glyph->advance.x);
1635 else
1637 g->lbearing = 0;
1638 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1639 g->ascent = flt_font_ft->font->ascent << 6;
1640 g->descent = flt_font_ft->font->descent << 6;
1642 g->yadv = 0;
1643 g->measured = 1;
1645 return 0;
1648 static int
1649 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1651 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1653 #define FEATURE_ANY(IDX) \
1654 (spec->features[IDX] \
1655 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1657 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1658 OTF *otf = flt_font_ft->otf;
1659 OTF_Tag *tags;
1660 int i, n;
1661 bool negative;
1663 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1664 /* Return true iff any of GSUB or GPOS support the script (and
1665 language). */
1666 return (otf
1667 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1668 NULL, 0) > 0
1669 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1670 NULL, 0) > 0));
1672 for (i = 0; i < 2; i++)
1673 if (! FEATURE_ANY (i))
1675 if (FEATURE_NONE (i))
1677 if (otf
1678 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1679 NULL, 0) > 0)
1680 return 0;
1681 continue;
1683 if (spec->features[i][0] == 0xFFFFFFFF)
1685 if (! otf
1686 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1687 NULL, 0) <= 0)
1688 continue;
1690 else if (! otf)
1691 return 0;
1692 for (n = 1; spec->features[i][n]; n++);
1693 USE_SAFE_ALLOCA;
1694 SAFE_NALLOCA (tags, 1, n);
1695 for (n = 0, negative = 0; spec->features[i][n]; n++)
1697 if (spec->features[i][n] == 0xFFFFFFFF)
1698 negative = 1;
1699 else if (negative)
1700 tags[n - 1] = spec->features[i][n] | 0x80000000;
1701 else
1702 tags[n] = spec->features[i][n];
1704 bool passed = true;
1705 #ifndef M17N_FLT_USE_NEW_FEATURE
1706 passed = n - negative > 0;
1707 #endif
1708 if (passed)
1709 passed = (OTF_check_features (otf, i == 0, spec->script,
1710 spec->langsys, tags, n - negative)
1711 != 1);
1712 SAFE_FREE ();
1713 if (passed)
1714 return 0;
1716 return 1;
1717 #undef FEATURE_NONE
1718 #undef FEATURE_ANY
1721 #define DEVICE_DELTA(table, size) \
1722 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1723 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1724 : 0)
1726 static void
1727 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1728 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1730 if (anchor->AnchorFormat == 2)
1732 FT_Outline *outline;
1733 int ap = anchor->f.f1.AnchorPoint;
1735 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1736 outline = &ft_face->glyph->outline;
1737 if (ap < outline->n_points)
1739 *x = outline->points[ap].x << 6;
1740 *y = outline->points[ap].y << 6;
1743 else if (anchor->AnchorFormat == 3)
1745 if (anchor->f.f2.XDeviceTable.offset
1746 && anchor->f.f2.XDeviceTable.DeltaValue)
1747 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1748 if (anchor->f.f2.YDeviceTable.offset
1749 && anchor->f.f2.YDeviceTable.DeltaValue)
1750 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1754 static OTF_GlyphString otf_gstring;
1756 static void
1757 setup_otf_gstring (int size)
1759 if (otf_gstring.size < size)
1761 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1762 size, sizeof (OTF_Glyph));
1763 otf_gstring.size = size;
1765 otf_gstring.used = size;
1766 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1769 #ifdef M17N_FLT_USE_NEW_FEATURE
1771 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1772 #define PACK_OTF_TAG(TAG) \
1773 ((((TAG) & 0x7F000000) >> 3) \
1774 | (((TAG) & 0x7F0000) >> 2) \
1775 | (((TAG) & 0x7F00) >> 1) \
1776 | ((TAG) & 0x7F))
1778 /* Assuming that FONT is an OpenType font, apply OpenType features
1779 specified in SPEC on glyphs between FROM and TO of IN, and record
1780 the lastly applied feature in each glyph of IN. If OUT is not
1781 NULL, append the resulting glyphs to OUT while storing glyph
1782 position adjustment information in ADJUSTMENT. */
1784 static int
1785 ftfont_drive_otf (MFLTFont *font,
1786 MFLTOtfSpec *spec,
1787 MFLTGlyphString *in,
1788 int from,
1789 int to,
1790 MFLTGlyphString *out,
1791 MFLTGlyphAdjustment *adjustment)
1793 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1794 FT_Face ft_face = flt_font_ft->ft_face;
1795 OTF *otf = flt_font_ft->otf;
1796 int len = to - from;
1797 int i, j, gidx;
1798 OTF_Glyph *otfg;
1799 char script[5], *langsys = NULL;
1800 char *gsub_features = NULL, *gpos_features = NULL;
1801 OTF_Feature *features;
1803 if (len == 0)
1804 return from;
1805 OTF_tag_name (spec->script, script);
1807 char langsysbuf[5];
1808 if (spec->langsys)
1810 langsys = langsysbuf;
1811 OTF_tag_name (spec->langsys, langsys);
1814 USE_SAFE_ALLOCA;
1815 for (i = 0; i < 2; i++)
1817 char *p;
1819 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1821 for (j = 0; spec->features[i][j]; j++);
1822 SAFE_NALLOCA (p, 6, j);
1823 if (i == 0)
1824 gsub_features = p;
1825 else
1826 gpos_features = p;
1827 for (j = 0; spec->features[i][j]; j++)
1829 if (spec->features[i][j] == 0xFFFFFFFF)
1830 *p++ = '*', *p++ = ',';
1831 else
1833 OTF_tag_name (spec->features[i][j], p);
1834 p[4] = ',';
1835 p += 5;
1838 *--p = '\0';
1842 setup_otf_gstring (len);
1843 for (i = 0; i < len; i++)
1845 otf_gstring.glyphs[i].c = in->glyphs[from + i].c & 0x11FFFF;
1846 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1849 OTF_drive_gdef (otf, &otf_gstring);
1850 gidx = out ? out->used : from;
1852 if (gsub_features && out)
1854 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1855 gsub_features) < 0)
1856 goto simple_copy;
1857 if (out->allocated < out->used + otf_gstring.used)
1859 SAFE_FREE ();
1860 return -2;
1862 features = otf->gsub->FeatureList.Feature;
1863 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1865 MFLTGlyph *g;
1866 int min_from, max_to;
1867 int feature_idx = otfg->positioning_type >> 4;
1869 g = out->glyphs + out->used;
1870 *g = in->glyphs[from + otfg->f.index.from];
1871 if (g->code != otfg->glyph_id)
1873 g->c = 0;
1874 g->code = otfg->glyph_id;
1875 g->measured = 0;
1877 out->used++;
1878 min_from = g->from;
1879 max_to = g->to;
1880 if (otfg->f.index.from < otfg->f.index.to)
1882 /* OTFG substitutes multiple glyphs in IN. */
1883 for (j = from + otfg->f.index.from + 1;
1884 j <= from + otfg->f.index.to; j++)
1886 if (min_from > in->glyphs[j].from)
1887 min_from = in->glyphs[j].from;
1888 if (max_to < in->glyphs[j].to)
1889 max_to = in->glyphs[j].to;
1891 g->from = min_from;
1892 g->to = max_to;
1894 if (feature_idx)
1896 unsigned int tag = features[feature_idx - 1].FeatureTag;
1897 tag = PACK_OTF_TAG (tag);
1898 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1900 for (i++, otfg++; (i < otf_gstring.used
1901 && otfg->f.index.from == otfg[-1].f.index.from);
1902 i++, otfg++)
1904 g = out->glyphs + out->used;
1905 *g = in->glyphs[from + otfg->f.index.to];
1906 if (g->code != otfg->glyph_id)
1908 g->c = 0;
1909 g->code = otfg->glyph_id;
1910 g->measured = 0;
1912 feature_idx = otfg->positioning_type >> 4;
1913 if (feature_idx)
1915 unsigned int tag = features[feature_idx - 1].FeatureTag;
1916 tag = PACK_OTF_TAG (tag);
1917 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1919 out->used++;
1923 else if (gsub_features)
1925 /* Just for checking which features will be applied. */
1926 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1927 gsub_features) < 0)
1928 goto simple_copy;
1929 features = otf->gsub->FeatureList.Feature;
1930 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1931 otfg++)
1933 int feature_idx = otfg->positioning_type >> 4;
1935 if (feature_idx)
1937 unsigned int tag = features[feature_idx - 1].FeatureTag;
1938 tag = PACK_OTF_TAG (tag);
1939 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1941 MFLTGlyph *g = in->glyphs + (from + j);
1942 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1947 else if (out)
1949 if (out->allocated < out->used + len)
1951 SAFE_FREE ();
1952 return -2;
1954 for (i = 0; i < len; i++)
1955 out->glyphs[out->used++] = in->glyphs[from + i];
1958 if (gpos_features && out)
1960 MFLTGlyph *base = NULL, *mark = NULL, *g;
1961 int x_ppem, y_ppem, x_scale, y_scale;
1963 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1964 gpos_features) < 0)
1966 SAFE_FREE ();
1967 return to;
1969 features = otf->gpos->FeatureList.Feature;
1970 x_ppem = ft_face->size->metrics.x_ppem;
1971 y_ppem = ft_face->size->metrics.y_ppem;
1972 x_scale = ft_face->size->metrics.x_scale;
1973 y_scale = ft_face->size->metrics.y_scale;
1975 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1976 i < otf_gstring.used; i++, otfg++, g++)
1978 MFLTGlyph *prev;
1979 int feature_idx = otfg->positioning_type >> 4;
1981 if (feature_idx)
1983 unsigned int tag = features[feature_idx - 1].FeatureTag;
1984 tag = PACK_OTF_TAG (tag);
1985 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1988 if (! otfg->glyph_id)
1989 continue;
1990 switch (otfg->positioning_type & 0xF)
1992 case 0:
1993 break;
1994 case 1: /* Single */
1995 case 2: /* Pair */
1997 int format = otfg->f.f1.format;
1999 if (format & OTF_XPlacement)
2000 adjustment[i].xoff
2001 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2002 if (format & OTF_XPlaDevice)
2003 adjustment[i].xoff
2004 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2005 if (format & OTF_YPlacement)
2006 adjustment[i].yoff
2007 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2008 if (format & OTF_YPlaDevice)
2009 adjustment[i].yoff
2010 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2011 if (format & OTF_XAdvance)
2012 adjustment[i].xadv
2013 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2014 if (format & OTF_XAdvDevice)
2015 adjustment[i].xadv
2016 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2017 if (format & OTF_YAdvance)
2018 adjustment[i].yadv
2019 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2020 if (format & OTF_YAdvDevice)
2021 adjustment[i].yadv
2022 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2023 adjustment[i].set = 1;
2025 break;
2026 case 3: /* Cursive */
2027 /* Not yet supported. */
2028 break;
2029 case 4: /* Mark-to-Base */
2030 case 5: /* Mark-to-Ligature */
2031 if (! base)
2032 break;
2033 prev = base;
2034 goto label_adjust_anchor;
2035 default: /* i.e. case 6 Mark-to-Mark */
2036 if (! mark)
2037 break;
2038 prev = mark;
2040 label_adjust_anchor:
2042 int base_x, base_y, mark_x, mark_y;
2043 int this_from, this_to;
2045 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2046 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2047 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2048 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2050 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2051 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2052 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2053 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2054 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2055 x_ppem, y_ppem, &mark_x, &mark_y);
2056 adjustment[i].xoff = (base_x - mark_x);
2057 adjustment[i].yoff = - (base_y - mark_y);
2058 adjustment[i].back = (g - prev);
2059 adjustment[i].xadv = 0;
2060 adjustment[i].advance_is_absolute = 1;
2061 adjustment[i].set = 1;
2062 this_from = g->from;
2063 this_to = g->to;
2064 for (j = 0; prev + j < g; j++)
2066 if (this_from > prev[j].from)
2067 this_from = prev[j].from;
2068 if (this_to < prev[j].to)
2069 this_to = prev[j].to;
2071 for (; prev <= g; prev++)
2073 prev->from = this_from;
2074 prev->to = this_to;
2078 if (otfg->GlyphClass == OTF_GlyphClass0)
2079 base = mark = g;
2080 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2081 mark = g;
2082 else
2083 base = g;
2086 else if (gpos_features)
2088 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2089 gpos_features) < 0)
2091 SAFE_FREE ();
2092 return to;
2094 features = otf->gpos->FeatureList.Feature;
2095 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2096 i++, otfg++)
2097 if (otfg->positioning_type & 0xF)
2099 int feature_idx = otfg->positioning_type >> 4;
2101 if (feature_idx)
2103 unsigned int tag = features[feature_idx - 1].FeatureTag;
2104 tag = PACK_OTF_TAG (tag);
2105 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2107 MFLTGlyph *g = in->glyphs + (from + j);
2108 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2113 SAFE_FREE ();
2114 return to;
2116 simple_copy:
2117 SAFE_FREE ();
2118 if (! out)
2119 return to;
2120 if (out->allocated < out->used + len)
2121 return -2;
2122 font->get_metrics (font, in, from, to);
2123 memcpy (out->glyphs + out->used, in->glyphs + from,
2124 sizeof (MFLTGlyph) * len);
2125 out->used += len;
2126 return to;
2129 static int
2130 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2131 MFLTGlyphString *in, int from, int to)
2133 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2136 #else /* not M17N_FLT_USE_NEW_FEATURE */
2138 static int
2139 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2140 int from, int to,
2141 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2143 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2144 FT_Face ft_face = flt_font_ft->ft_face;
2145 OTF *otf = flt_font_ft->otf;
2146 int len = to - from;
2147 int i, j, gidx;
2148 OTF_Glyph *otfg;
2149 char script[5], *langsys = NULL;
2150 char *gsub_features = NULL, *gpos_features = NULL;
2152 if (len == 0)
2153 return from;
2154 OTF_tag_name (spec->script, script);
2156 char langsysbuf[5];
2157 if (spec->langsys)
2159 langsys = langsysbuf;
2160 OTF_tag_name (spec->langsys, langsys);
2163 USE_SAFE_ALLOCA;
2164 for (i = 0; i < 2; i++)
2166 char *p;
2168 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2170 for (j = 0; spec->features[i][j]; j++);
2171 SAFE_NALLOCA (p, 6, j);
2172 if (i == 0)
2173 gsub_features = p;
2174 else
2175 gpos_features = p;
2176 for (j = 0; spec->features[i][j]; j++)
2178 if (spec->features[i][j] == 0xFFFFFFFF)
2179 *p++ = '*', *p++ = ',';
2180 else
2182 OTF_tag_name (spec->features[i][j], p);
2183 p[4] = ',';
2184 p += 5;
2187 *--p = '\0';
2191 setup_otf_gstring (len);
2192 for (i = 0; i < len; i++)
2194 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2195 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2198 OTF_drive_gdef (otf, &otf_gstring);
2199 gidx = out->used;
2201 if (gsub_features)
2203 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2204 < 0)
2205 goto simple_copy;
2206 if (out->allocated < out->used + otf_gstring.used)
2208 SAFE_FREE ();
2209 return -2;
2211 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2213 MFLTGlyph *g;
2214 int min_from, max_to;
2215 int j;
2217 g = out->glyphs + out->used;
2218 *g = in->glyphs[from + otfg->f.index.from];
2219 if (g->code != otfg->glyph_id)
2221 g->c = 0;
2222 g->code = otfg->glyph_id;
2223 g->measured = 0;
2225 out->used++;
2226 min_from = g->from;
2227 max_to = g->to;
2228 if (otfg->f.index.from < otfg->f.index.to)
2230 /* OTFG substitutes multiple glyphs in IN. */
2231 for (j = from + otfg->f.index.from + 1;
2232 j <= from + otfg->f.index.to; j++)
2234 if (min_from > in->glyphs[j].from)
2235 min_from = in->glyphs[j].from;
2236 if (max_to < in->glyphs[j].to)
2237 max_to = in->glyphs[j].to;
2239 g->from = min_from;
2240 g->to = max_to;
2242 for (i++, otfg++; (i < otf_gstring.used
2243 && otfg->f.index.from == otfg[-1].f.index.from);
2244 i++, otfg++)
2246 g = out->glyphs + out->used;
2247 *g = in->glyphs[from + otfg->f.index.to];
2248 if (g->code != otfg->glyph_id)
2250 g->c = 0;
2251 g->code = otfg->glyph_id;
2252 g->measured = 0;
2254 out->used++;
2258 else
2260 if (out->allocated < out->used + len)
2262 SAFE_FREE ();
2263 return -2;
2265 for (i = 0; i < len; i++)
2266 out->glyphs[out->used++] = in->glyphs[from + i];
2269 if (gpos_features)
2271 MFLTGlyph *base = NULL, *mark = NULL, *g;
2272 int x_ppem, y_ppem, x_scale, y_scale;
2274 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2275 < 0)
2277 SAFE_FREE ();
2278 return to;
2281 x_ppem = ft_face->size->metrics.x_ppem;
2282 y_ppem = ft_face->size->metrics.y_ppem;
2283 x_scale = ft_face->size->metrics.x_scale;
2284 y_scale = ft_face->size->metrics.y_scale;
2286 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2287 i < otf_gstring.used; i++, otfg++, g++)
2289 MFLTGlyph *prev;
2291 if (! otfg->glyph_id)
2292 continue;
2293 switch (otfg->positioning_type)
2295 case 0:
2296 break;
2297 case 1: /* Single */
2298 case 2: /* Pair */
2300 int format = otfg->f.f1.format;
2302 if (format & OTF_XPlacement)
2303 adjustment[i].xoff
2304 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2305 if (format & OTF_XPlaDevice)
2306 adjustment[i].xoff
2307 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2308 if (format & OTF_YPlacement)
2309 adjustment[i].yoff
2310 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2311 if (format & OTF_YPlaDevice)
2312 adjustment[i].yoff
2313 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2314 if (format & OTF_XAdvance)
2315 adjustment[i].xadv
2316 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2317 if (format & OTF_XAdvDevice)
2318 adjustment[i].xadv
2319 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2320 if (format & OTF_YAdvance)
2321 adjustment[i].yadv
2322 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2323 if (format & OTF_YAdvDevice)
2324 adjustment[i].yadv
2325 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2326 adjustment[i].set = 1;
2328 break;
2329 case 3: /* Cursive */
2330 /* Not yet supported. */
2331 break;
2332 case 4: /* Mark-to-Base */
2333 case 5: /* Mark-to-Ligature */
2334 if (! base)
2335 break;
2336 prev = base;
2337 goto label_adjust_anchor;
2338 default: /* i.e. case 6 Mark-to-Mark */
2339 if (! mark)
2340 break;
2341 prev = mark;
2343 label_adjust_anchor:
2345 int base_x, base_y, mark_x, mark_y;
2346 int this_from, this_to;
2348 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2349 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2350 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2351 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2353 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2354 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2355 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2356 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2357 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2358 x_ppem, y_ppem, &mark_x, &mark_y);
2359 adjustment[i].xoff = (base_x - mark_x);
2360 adjustment[i].yoff = - (base_y - mark_y);
2361 adjustment[i].back = (g - prev);
2362 adjustment[i].xadv = 0;
2363 adjustment[i].advance_is_absolute = 1;
2364 adjustment[i].set = 1;
2365 this_from = g->from;
2366 this_to = g->to;
2367 for (j = 0; prev + j < g; j++)
2369 if (this_from > prev[j].from)
2370 this_from = prev[j].from;
2371 if (this_to < prev[j].to)
2372 this_to = prev[j].to;
2374 for (; prev <= g; prev++)
2376 prev->from = this_from;
2377 prev->to = this_to;
2381 if (otfg->GlyphClass == OTF_GlyphClass0)
2382 base = mark = g;
2383 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2384 mark = g;
2385 else
2386 base = g;
2389 SAFE_FREE ();
2390 return to;
2392 simple_copy:
2393 SAFE_FREE ();
2394 if (out->allocated < out->used + len)
2395 return -2;
2396 font->get_metrics (font, in, from, to);
2397 memcpy (out->glyphs + out->used, in->glyphs + from,
2398 sizeof (MFLTGlyph) * len);
2399 out->used += len;
2400 return to;
2403 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2405 static MFLTGlyphString gstring;
2407 static bool m17n_flt_initialized;
2409 static Lisp_Object
2410 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2411 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2413 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2414 ptrdiff_t i;
2415 struct MFLTFontFT flt_font_ft;
2416 MFLT *flt = NULL;
2417 bool with_variation_selector = 0;
2419 if (! m17n_flt_initialized)
2421 M17N_INIT ();
2422 #ifdef M17N_FLT_USE_NEW_FEATURE
2423 mflt_enable_new_feature = 1;
2424 mflt_try_otf = ftfont_try_otf;
2425 #endif /* M17N_FLT_USE_NEW_FEATURE */
2426 m17n_flt_initialized = 1;
2429 for (i = 0; i < len; i++)
2431 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2432 int c;
2434 if (NILP (g))
2435 break;
2436 c = LGLYPH_CHAR (g);
2437 if (CHAR_VARIATION_SELECTOR_P (c))
2438 with_variation_selector = 1;
2441 len = i;
2443 if (with_variation_selector)
2445 setup_otf_gstring (len);
2446 for (i = 0; i < len; i++)
2448 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2450 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2451 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2452 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2454 OTF_drive_cmap (otf, &otf_gstring);
2455 for (i = 0; i < otf_gstring.used; i++)
2457 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2458 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2459 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2461 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2462 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2463 LGSTRING_SET_GLYPH (lgstring, i, g0);
2465 if (len > otf_gstring.used)
2467 len = otf_gstring.used;
2468 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2472 if (INT_MAX / 2 < len)
2473 memory_full (SIZE_MAX);
2475 if (gstring.allocated == 0)
2477 gstring.glyph_size = sizeof (MFLTGlyph);
2478 gstring.glyphs = xnmalloc (len * 2, sizeof *gstring.glyphs);
2479 gstring.allocated = len * 2;
2481 else if (gstring.allocated < len * 2)
2483 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2,
2484 sizeof *gstring.glyphs);
2485 gstring.allocated = len * 2;
2487 memset (gstring.glyphs, 0, len * sizeof *gstring.glyphs);
2488 for (i = 0; i < len; i++)
2490 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2492 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2493 if (with_variation_selector)
2495 gstring.glyphs[i].code = LGLYPH_CODE (g);
2496 gstring.glyphs[i].encoded = 1;
2500 gstring.used = len;
2501 gstring.r2l = 0;
2504 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2506 if (NILP (family))
2507 flt_font_ft.flt_font.family = Mnil;
2508 else
2509 flt_font_ft.flt_font.family
2510 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2512 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2513 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2514 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2515 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2516 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2517 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2518 flt_font_ft.flt_font.internal = NULL;
2519 flt_font_ft.font = font;
2520 flt_font_ft.ft_face = ft_face;
2521 flt_font_ft.otf = otf;
2522 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2523 if (len > 1
2524 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2525 /* A little bit ad hoc. Perhaps, shaper must get script and
2526 language information, and select a proper flt for them
2527 here. */
2528 flt = mflt_get (msymbol ("combining"));
2529 for (i = 0; i < 3; i++)
2531 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2532 if (result != -2)
2533 break;
2534 if (INT_MAX / 2 < gstring.allocated)
2535 memory_full (SIZE_MAX);
2536 gstring.glyphs = xnrealloc (gstring.glyphs,
2537 gstring.allocated, 2 * sizeof (MFLTGlyph));
2538 gstring.allocated *= 2;
2540 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2541 return Qnil;
2542 for (i = 0; i < gstring.used; i++)
2544 MFLTGlyph *g = gstring.glyphs + i;
2546 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2547 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2550 for (i = 0; i < gstring.used; i++)
2552 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2553 MFLTGlyph *g = gstring.glyphs + i;
2555 if (NILP (lglyph))
2557 lglyph = LGLYPH_NEW ();
2558 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2560 LGLYPH_SET_FROM (lglyph, g->from);
2561 LGLYPH_SET_TO (lglyph, g->to);
2562 LGLYPH_SET_CHAR (lglyph, g->c);
2563 LGLYPH_SET_CODE (lglyph, g->code);
2564 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2565 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2566 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2567 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2568 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2569 if (g->adjusted)
2571 Lisp_Object vec = make_uninit_vector (3);
2573 ASET (vec, 0, make_number (g->xoff >> 6));
2574 ASET (vec, 1, make_number (g->yoff >> 6));
2575 ASET (vec, 2, make_number (g->xadv >> 6));
2576 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2579 return make_number (i);
2582 Lisp_Object
2583 ftfont_shape (Lisp_Object lgstring)
2585 struct font *font;
2586 struct ftfont_info *ftfont_info;
2587 OTF *otf;
2589 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2590 ftfont_info = (struct ftfont_info *) font;
2591 otf = ftfont_get_otf (ftfont_info);
2592 if (! otf)
2593 return make_number (0);
2594 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2595 &ftfont_info->matrix);
2598 #endif /* HAVE_M17N_FLT */
2600 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2602 static int
2603 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2605 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2606 OTF *otf = ftfont_get_otf (ftfont_info);
2608 if (! otf)
2609 return 0;
2610 return OTF_get_variation_glyphs (otf, c, variations);
2613 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2614 #endif /* HAVE_LIBOTF */
2616 static const char *const ftfont_booleans [] = {
2617 ":antialias",
2618 ":hinting",
2619 ":verticallayout",
2620 ":autohint",
2621 ":globaladvance",
2622 ":outline",
2623 ":scalable",
2624 ":minspace",
2625 ":embolden",
2626 NULL,
2629 static const char *const ftfont_non_booleans [] = {
2630 ":family",
2631 ":familylang",
2632 ":style",
2633 ":stylelang",
2634 ":fullname",
2635 ":fullnamelang",
2636 ":slant",
2637 ":weight",
2638 ":size",
2639 ":width",
2640 ":aspect",
2641 ":pixelsize",
2642 ":spacing",
2643 ":foundry",
2644 ":hintstyle",
2645 ":file",
2646 ":index",
2647 ":ftface",
2648 ":rasterizer",
2649 ":scale",
2650 ":dpi",
2651 ":rgba",
2652 ":lcdfilter",
2653 ":charset",
2654 ":lang",
2655 ":fontversion",
2656 ":capability",
2657 NULL,
2660 static void
2661 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2663 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2667 void
2668 syms_of_ftfont (void)
2670 DEFSYM (Qfreetype, "freetype");
2671 DEFSYM (Qmonospace, "monospace");
2672 DEFSYM (Qsans_serif, "sans-serif");
2673 DEFSYM (Qserif, "serif");
2674 DEFSYM (Qmono, "mono");
2675 DEFSYM (Qsans, "sans");
2676 DEFSYM (Qsans__serif, "sans serif");
2678 staticpro (&freetype_font_cache);
2679 freetype_font_cache = list1 (Qt);
2681 staticpro (&ftfont_generic_family_list);
2682 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2683 Fcons (Qsans_serif, Qt),
2684 Fcons (Qsans, Qt));
2686 staticpro (&ft_face_cache);
2687 ft_face_cache = Qnil;
2689 ftfont_driver.type = Qfreetype;
2690 register_font_driver (&ftfont_driver, NULL);