* test/automated/sgml-mode-tests.el: New file.
[emacs.git] / src / ftfont.c
blob26740c263ce08128e0335d5207da61c03695a796
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 enum ftfont_cache_for
72 FTFONT_CACHE_FOR_FACE,
73 FTFONT_CACHE_FOR_CHARSET,
74 FTFONT_CACHE_FOR_ENTITY
77 static Lisp_Object ftfont_pattern_entity (FcPattern *, Lisp_Object);
79 static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
80 FcPattern *);
81 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
82 enum ftfont_cache_for);
84 static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
86 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
88 static struct
90 /* registry name */
91 const char *name;
92 /* characters to distinguish the charset from the others */
93 int uniquifier[6];
94 /* additional constraint by language */
95 const char *lang;
96 /* set on demand */
97 FcCharSet *fc_charset;
98 } fc_charset_table[] =
99 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
100 { "iso8859-2", { 0x00A0, 0x010E }},
101 { "iso8859-3", { 0x00A0, 0x0108 }},
102 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
103 { "iso8859-5", { 0x00A0, 0x0401 }},
104 { "iso8859-6", { 0x00A0, 0x060C }},
105 { "iso8859-7", { 0x00A0, 0x0384 }},
106 { "iso8859-8", { 0x00A0, 0x05D0 }},
107 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
108 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
109 { "iso8859-11", { 0x00A0, 0x0E01 }},
110 { "iso8859-13", { 0x00A0, 0x201C }},
111 { "iso8859-14", { 0x00A0, 0x0174 }},
112 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
113 { "iso8859-16", { 0x00A0, 0x0218}},
114 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
115 { "big5-0", { 0xF6B1 }, "zh-tw" },
116 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
117 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
118 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
119 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
120 { "cns11643.1992-3", { 0x201A9 }},
121 { "cns11643.1992-4", { 0x20057 }},
122 { "cns11643.1992-5", { 0x20000 }},
123 { "cns11643.1992-6", { 0x20003 }},
124 { "cns11643.1992-7", { 0x20055 }},
125 { "gbk-0", { 0x4E06 }, "zh-cn"},
126 { "jisx0212.1990-0", { 0x4E44 }},
127 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
128 { "jisx0213.2000-2", { 0xFA49 }},
129 { "jisx0213.2004-1", { 0x20B9F }},
130 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
131 { "tis620.2529-1", { 0x0E01 }, "th"},
132 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
133 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
134 { "mulelao-1", { 0x0E81 }, "lo"},
135 { "unicode-sip", { 0x20000 }},
136 { NULL }
139 static bool
140 matching_prefix (char const *str, ptrdiff_t len, char const *pat)
142 return len == strlen (pat) && c_strncasecmp (str, pat, len) == 0;
145 /* Dirty hack for handing ADSTYLE property.
147 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
148 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
149 "Oblique", "Italic", or any non-normal SWIDTH property names
150 (e.g. SemiCondensed) are appended. In addition, if there's no
151 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
152 "Regular" is used for FC_STYLE (see the function
153 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
155 Unfortunately this behavior is not documented, so the following
156 code may fail if FreeType changes the behavior in the future. */
158 static Lisp_Object
159 get_adstyle_property (FcPattern *p)
161 FcChar8 *fcstr;
162 char *str, *end;
163 Lisp_Object adstyle;
165 #ifdef FC_FONTFORMAT
166 if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
167 && xstrcasecmp ((char *) fcstr, "bdf") != 0
168 && xstrcasecmp ((char *) fcstr, "pcf") != 0)
169 /* Not a BDF nor PCF font. */
170 return Qnil;
171 #endif
172 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
173 return Qnil;
174 str = (char *) fcstr;
175 for (end = str; *end && *end != ' '; end++);
176 if (matching_prefix (str, end - str, "Regular")
177 || matching_prefix (str, end - str, "Bold")
178 || matching_prefix (str, end - str, "Oblique")
179 || matching_prefix (str, end - str, "Italic"))
180 return Qnil;
181 adstyle = font_intern_prop (str, end - str, 1);
182 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
183 return Qnil;
184 return adstyle;
187 static Lisp_Object
188 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
190 Lisp_Object key, cache, entity;
191 FcChar8 *str;
192 char *file;
193 int idx;
194 int numeric;
195 double dbl;
196 FcBool b;
198 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
199 return Qnil;
200 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
201 return Qnil;
203 file = (char *) str;
204 key = Fcons (build_unibyte_string (file), make_number (idx));
205 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
206 entity = XCAR (cache);
207 if (! NILP (entity))
209 Lisp_Object val = font_make_entity ();
210 int i;
212 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
213 ASET (val, i, AREF (entity, i));
215 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
216 font_put_extra (val, QCfont_entity, key);
218 return val;
220 entity = font_make_entity ();
221 XSETCAR (cache, entity);
223 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
224 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
226 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
228 char *s = (char *) str;
229 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
231 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
233 char *s = (char *) str;
234 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
236 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
238 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
239 numeric = FC_WEIGHT_MEDIUM;
240 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
242 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
244 numeric += 100;
245 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
247 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
249 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
251 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
253 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
255 else
256 ASET (entity, FONT_SIZE_INDEX, make_number (0));
257 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
258 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
259 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
261 int dpi = dbl;
262 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
264 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
265 && b == FcTrue)
267 ASET (entity, FONT_SIZE_INDEX, make_number (0));
268 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
270 else
272 /* As this font is not scalable, perhaps this is a BDF or PCF
273 font. */
274 FT_Face ft_face;
276 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
277 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
278 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
280 BDF_PropertyRec rec;
282 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
283 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
284 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
285 FT_Done_Face (ft_face);
289 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
290 font_put_extra (entity, QCfont_entity, key);
291 return entity;
295 static Lisp_Object ftfont_generic_family_list;
297 static Lisp_Object
298 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
300 Lisp_Object slot;
301 FcPattern *match;
302 FcResult result;
303 FcLangSet *langset;
305 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
306 if (EQ (family, Qmono))
307 family = Qmonospace;
308 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
309 family = Qsans_serif;
310 slot = assq_no_quit (family, ftfont_generic_family_list);
311 if (! CONSP (slot))
312 return Qnil;
313 if (! EQ (XCDR (slot), Qt))
314 return XCDR (slot);
315 pattern = FcPatternDuplicate (pattern);
316 if (! pattern)
317 goto err;
318 FcPatternDel (pattern, FC_FOUNDRY);
319 FcPatternDel (pattern, FC_FAMILY);
320 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
321 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
323 /* This is to avoid the effect of locale. */
324 static const FcChar8 lang[] = "en";
325 langset = FcLangSetCreate ();
326 FcLangSetAdd (langset, lang);
327 FcPatternAddLangSet (pattern, FC_LANG, langset);
328 FcLangSetDestroy (langset);
330 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
331 FcDefaultSubstitute (pattern);
332 match = FcFontMatch (NULL, pattern, &result);
333 if (match)
335 FcChar8 *fam;
337 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
338 family = intern ((char *) fam);
340 else
341 family = Qnil;
342 XSETCDR (slot, family);
343 if (match) FcPatternDestroy (match);
344 err:
345 if (pattern) FcPatternDestroy (pattern);
346 return family;
349 struct ftfont_cache_data
351 FT_Face ft_face;
352 FcCharSet *fc_charset;
355 static Lisp_Object
356 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
358 Lisp_Object cache, val, entity;
359 struct ftfont_cache_data *cache_data;
361 if (FONT_ENTITY_P (key))
363 entity = key;
364 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
365 eassert (CONSP (val));
366 key = XCDR (val);
368 else
369 entity = Qnil;
371 if (NILP (ft_face_cache))
372 cache = Qnil;
373 else
374 cache = Fgethash (key, ft_face_cache, Qnil);
375 if (NILP (cache))
377 if (NILP (ft_face_cache))
378 ft_face_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
379 cache_data = xmalloc (sizeof *cache_data);
380 cache_data->ft_face = NULL;
381 cache_data->fc_charset = NULL;
382 val = make_save_ptr_int (cache_data, 0);
383 cache = Fcons (Qnil, val);
384 Fputhash (key, cache, ft_face_cache);
386 else
388 val = XCDR (cache);
389 cache_data = XSAVE_POINTER (val, 0);
392 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
393 return cache;
395 if (cache_for == FTFONT_CACHE_FOR_FACE
396 ? ! cache_data->ft_face : ! cache_data->fc_charset)
398 char *filename = SSDATA (XCAR (key));
399 int idx = XINT (XCDR (key));
401 if (cache_for == FTFONT_CACHE_FOR_FACE)
403 if (! ft_library
404 && FT_Init_FreeType (&ft_library) != 0)
405 return Qnil;
406 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
407 != 0)
408 return Qnil;
410 else
412 FcPattern *pat = NULL;
413 FcFontSet *fontset = NULL;
414 FcObjectSet *objset = NULL;
415 FcCharSet *charset = NULL;
417 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
418 FC_INDEX, FcTypeInteger, idx, NULL);
419 if (! pat)
420 goto finish;
421 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
422 if (! objset)
423 goto finish;
424 fontset = FcFontList (NULL, pat, objset);
425 if (! fontset)
426 goto finish;
427 if (fontset && fontset->nfont > 0
428 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
429 &charset)
430 == FcResultMatch))
431 cache_data->fc_charset = FcCharSetCopy (charset);
432 else
433 cache_data->fc_charset = FcCharSetCreate ();
435 finish:
436 if (fontset)
437 FcFontSetDestroy (fontset);
438 if (objset)
439 FcObjectSetDestroy (objset);
440 if (pat)
441 FcPatternDestroy (pat);
444 return cache;
447 FcCharSet *
448 ftfont_get_fc_charset (Lisp_Object entity)
450 Lisp_Object val, cache;
451 struct ftfont_cache_data *cache_data;
453 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
454 val = XCDR (cache);
455 cache_data = XSAVE_POINTER (val, 0);
456 return cache_data->fc_charset;
459 #ifdef HAVE_LIBOTF
460 static OTF *
461 ftfont_get_otf (struct ftfont_info *ftfont_info)
463 OTF *otf;
465 if (ftfont_info->otf)
466 return ftfont_info->otf;
467 if (! ftfont_info->maybe_otf)
468 return NULL;
469 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
470 if (! otf || OTF_get_table (otf, "head") < 0)
472 if (otf)
473 OTF_close (otf);
474 ftfont_info->maybe_otf = 0;
475 return NULL;
477 ftfont_info->otf = otf;
478 return otf;
480 #endif /* HAVE_LIBOTF */
482 static Lisp_Object ftfont_get_cache (struct frame *);
483 static Lisp_Object ftfont_list (struct frame *, Lisp_Object);
484 static Lisp_Object ftfont_match (struct frame *, Lisp_Object);
485 static Lisp_Object ftfont_list_family (struct frame *);
486 static Lisp_Object ftfont_open (struct frame *, Lisp_Object, int);
487 static void ftfont_close (struct font *);
488 static int ftfont_has_char (Lisp_Object, int);
489 static unsigned ftfont_encode_char (struct font *, int);
490 static void ftfont_text_extents (struct font *, unsigned *, int,
491 struct font_metrics *);
492 static int ftfont_get_bitmap (struct font *, unsigned,
493 struct font_bitmap *, int);
494 static int ftfont_anchor_point (struct font *, unsigned, int,
495 int *, int *);
496 #ifdef HAVE_LIBOTF
497 static Lisp_Object ftfont_otf_capability (struct font *);
498 # ifdef HAVE_M17N_FLT
499 static Lisp_Object ftfont_shape (Lisp_Object);
500 # endif
501 #endif
503 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
504 static int ftfont_variation_glyphs (struct font *, int c,
505 unsigned variations[256]);
506 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
508 struct font_driver ftfont_driver =
510 LISP_INITIALLY_ZERO, /* Qfreetype */
511 0, /* case insensitive */
512 ftfont_get_cache,
513 ftfont_list,
514 ftfont_match,
515 ftfont_list_family,
516 NULL, /* free_entity */
517 ftfont_open,
518 ftfont_close,
519 /* We can't draw a text without device dependent functions. */
520 NULL, /* prepare_face */
521 NULL, /* done_face */
522 ftfont_has_char,
523 ftfont_encode_char,
524 ftfont_text_extents,
525 /* We can't draw a text without device dependent functions. */
526 NULL, /* draw */
527 ftfont_get_bitmap,
528 NULL, /* free_bitmap */
529 ftfont_anchor_point,
530 #ifdef HAVE_LIBOTF
531 ftfont_otf_capability,
532 #else /* not HAVE_LIBOTF */
533 NULL,
534 #endif /* not HAVE_LIBOTF */
535 NULL, /* otf_drive */
536 NULL, /* start_for_frame */
537 NULL, /* end_for_frame */
538 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
539 ftfont_shape,
540 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
541 NULL,
542 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
543 NULL, /* check */
545 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
546 ftfont_variation_glyphs,
547 #else
548 NULL,
549 #endif
551 ftfont_filter_properties, /* filter_properties */
554 static Lisp_Object
555 ftfont_get_cache (struct frame *f)
557 return freetype_font_cache;
560 static int
561 ftfont_get_charset (Lisp_Object registry)
563 char *str = SSDATA (SYMBOL_NAME (registry));
564 USE_SAFE_ALLOCA;
565 char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
566 Lisp_Object regexp;
567 int i, j;
569 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
571 if (str[i] == '.')
572 re[j++] = '\\';
573 else if (str[i] == '*')
574 re[j++] = '.';
575 re[j] = str[i];
576 if (re[j] == '?')
577 re[j] = '.';
579 re[j] = '\0';
580 regexp = make_unibyte_string (re, j);
581 SAFE_FREE ();
582 for (i = 0; fc_charset_table[i].name; i++)
583 if (fast_c_string_match_ignore_case
584 (regexp, fc_charset_table[i].name,
585 strlen (fc_charset_table[i].name)) >= 0)
586 break;
587 if (! fc_charset_table[i].name)
588 return -1;
589 if (! fc_charset_table[i].fc_charset)
591 FcCharSet *charset = FcCharSetCreate ();
592 int *uniquifier = fc_charset_table[i].uniquifier;
594 if (! charset)
595 return -1;
596 for (j = 0; uniquifier[j]; j++)
597 if (! FcCharSetAddChar (charset, uniquifier[j]))
599 FcCharSetDestroy (charset);
600 return -1;
602 fc_charset_table[i].fc_charset = charset;
604 return i;
607 struct OpenTypeSpec
609 Lisp_Object script;
610 unsigned int script_tag, langsys_tag;
611 int nfeatures[2];
612 unsigned int *features[2];
615 #define OTF_SYM_TAG(SYM, TAG) \
616 do { \
617 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
618 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
619 } while (0)
621 #define OTF_TAG_STR(TAG, P) \
622 do { \
623 (P)[0] = (char) (TAG >> 24); \
624 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
625 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
626 (P)[3] = (char) (TAG & 0xFF); \
627 (P)[4] = '\0'; \
628 } while (0)
630 #ifdef HAVE_LIBOTF
631 #define OTF_TAG_SYM(SYM, TAG) \
632 do { \
633 char str[5]; \
635 OTF_TAG_STR (TAG, str); \
636 (SYM) = font_intern_prop (str, 4, 1); \
637 } while (0)
638 #endif
641 static struct OpenTypeSpec *
642 ftfont_get_open_type_spec (Lisp_Object otf_spec)
644 struct OpenTypeSpec *spec = malloc (sizeof *spec);
645 Lisp_Object val;
646 int i, j;
647 bool negative;
649 if (! spec)
650 return NULL;
651 spec->script = XCAR (otf_spec);
652 if (! NILP (spec->script))
654 OTF_SYM_TAG (spec->script, spec->script_tag);
655 val = assq_no_quit (spec->script, Votf_script_alist);
656 if (CONSP (val) && SYMBOLP (XCDR (val)))
657 spec->script = XCDR (val);
658 else
659 spec->script = Qnil;
661 else
662 spec->script_tag = 0x44464C54; /* "DFLT" */
663 otf_spec = XCDR (otf_spec);
664 spec->langsys_tag = 0;
665 if (! NILP (otf_spec))
667 val = XCAR (otf_spec);
668 if (! NILP (val))
669 OTF_SYM_TAG (val, spec->langsys_tag);
670 otf_spec = XCDR (otf_spec);
672 spec->nfeatures[0] = spec->nfeatures[1] = 0;
673 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
675 Lisp_Object len;
677 val = XCAR (otf_spec);
678 if (NILP (val))
679 continue;
680 len = Flength (val);
681 spec->features[i] =
682 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
684 : malloc (XINT (len) * sizeof *spec->features[i]));
685 if (! spec->features[i])
687 if (i > 0 && spec->features[0])
688 free (spec->features[0]);
689 free (spec);
690 return NULL;
692 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
694 if (NILP (XCAR (val)))
695 negative = 1;
696 else
698 unsigned int tag;
700 OTF_SYM_TAG (XCAR (val), tag);
701 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
704 spec->nfeatures[i] = j;
706 return spec;
709 static FcPattern *
710 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
712 Lisp_Object tmp, extra;
713 FcPattern *pattern = NULL;
714 FcCharSet *charset = NULL;
715 FcLangSet *langset = NULL;
716 int n;
717 int dpi = -1;
718 int scalable = -1;
719 Lisp_Object script = Qnil;
720 Lisp_Object registry;
721 int fc_charset_idx;
723 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
724 && n < 100)
725 /* Fontconfig doesn't support reverse-italic/oblique. */
726 return NULL;
728 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
729 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
730 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
731 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
732 scalable = 1;
734 registry = AREF (spec, FONT_REGISTRY_INDEX);
735 if (NILP (registry)
736 || EQ (registry, Qascii_0)
737 || EQ (registry, Qiso10646_1)
738 || EQ (registry, Qunicode_bmp))
739 fc_charset_idx = -1;
740 else
742 FcChar8 *lang;
744 fc_charset_idx = ftfont_get_charset (registry);
745 if (fc_charset_idx < 0)
746 return NULL;
747 charset = fc_charset_table[fc_charset_idx].fc_charset;
748 *langname = fc_charset_table[fc_charset_idx].lang;
749 lang = (FcChar8 *) *langname;
750 if (lang)
752 langset = FcLangSetCreate ();
753 if (! langset)
754 goto err;
755 FcLangSetAdd (langset, lang);
759 otlayout[0] = '\0';
760 for (extra = AREF (spec, FONT_EXTRA_INDEX);
761 CONSP (extra); extra = XCDR (extra))
763 Lisp_Object key, val;
765 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
766 if (EQ (key, QCdpi))
768 if (INTEGERP (val))
769 dpi = XINT (val);
771 else if (EQ (key, QClang))
773 if (! langset)
774 langset = FcLangSetCreate ();
775 if (! langset)
776 goto err;
777 if (SYMBOLP (val))
779 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
780 goto err;
782 else
783 for (; CONSP (val); val = XCDR (val))
784 if (SYMBOLP (XCAR (val))
785 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
786 goto err;
788 else if (EQ (key, QCotf))
790 if (CONSP (val))
792 *otspec = ftfont_get_open_type_spec (val);
793 if (! *otspec)
794 return NULL;
795 strcpy (otlayout, "otlayout:");
796 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
797 script = (*otspec)->script;
800 else if (EQ (key, QCscript))
801 script = val;
802 else if (EQ (key, QCscalable))
803 scalable = ! NILP (val);
806 if (! NILP (script) && ! charset)
808 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
810 if (CONSP (chars) && CONSP (CDR (chars)))
812 charset = FcCharSetCreate ();
813 if (! charset)
814 goto err;
815 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
816 if (CHARACTERP (XCAR (chars))
817 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
818 goto err;
822 pattern = FcPatternCreate ();
823 if (! pattern)
824 goto err;
825 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
826 if (! NILP (tmp)
827 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
828 goto err;
829 tmp = AREF (spec, FONT_FAMILY_INDEX);
830 if (! NILP (tmp)
831 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
832 goto err;
833 if (charset
834 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
835 goto err;
836 if (langset
837 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
838 goto err;
839 if (dpi >= 0
840 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
841 goto err;
842 if (scalable >= 0
843 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
844 goto err;
846 goto finish;
848 err:
849 /* We come here because of unexpected error in fontconfig API call
850 (usually insufficient memory). */
851 if (pattern)
853 FcPatternDestroy (pattern);
854 pattern = NULL;
856 if (*otspec)
858 if ((*otspec)->nfeatures[0] > 0)
859 free ((*otspec)->features[0]);
860 if ((*otspec)->nfeatures[1] > 0)
861 free ((*otspec)->features[1]);
862 free (*otspec);
863 *otspec = NULL;
866 finish:
867 if (langset) FcLangSetDestroy (langset);
868 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
869 return pattern;
872 static Lisp_Object
873 ftfont_list (struct frame *f, Lisp_Object spec)
875 Lisp_Object val = Qnil, family, adstyle;
876 int i;
877 FcPattern *pattern;
878 FcFontSet *fontset = NULL;
879 FcObjectSet *objset = NULL;
880 FcCharSet *charset;
881 Lisp_Object chars = Qnil;
882 char otlayout[15]; /* For "otlayout:XXXX" */
883 struct OpenTypeSpec *otspec = NULL;
884 int spacing = -1;
885 const char *langname = NULL;
887 if (! fc_initialized)
889 FcInit ();
890 fc_initialized = 1;
893 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
894 if (! pattern)
895 return Qnil;
896 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
898 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
899 if (! NILP (val))
901 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
902 if (CONSP (val) && VECTORP (XCDR (val)))
903 chars = XCDR (val);
905 val = Qnil;
907 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
908 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
909 family = AREF (spec, FONT_FAMILY_INDEX);
910 if (! NILP (family))
912 Lisp_Object resolved;
914 resolved = ftfont_resolve_generic_family (family, pattern);
915 if (! NILP (resolved))
917 FcPatternDel (pattern, FC_FAMILY);
918 if (! FcPatternAddString (pattern, FC_FAMILY,
919 SYMBOL_FcChar8 (resolved)))
920 goto err;
923 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
924 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
925 adstyle = Qnil;
926 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
927 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
928 FC_STYLE, FC_FILE, FC_INDEX,
929 #ifdef FC_CAPABILITY
930 FC_CAPABILITY,
931 #endif /* FC_CAPABILITY */
932 #ifdef FC_FONTFORMAT
933 FC_FONTFORMAT,
934 #endif
935 NULL);
936 if (! objset)
937 goto err;
938 if (! NILP (chars))
939 FcObjectSetAdd (objset, FC_CHARSET);
941 fontset = FcFontList (NULL, pattern, objset);
942 if (! fontset || fontset->nfont == 0)
943 goto finish;
944 #if 0
945 /* Need fix because this finds any fonts. */
946 if (fontset->nfont == 0 && ! NILP (family))
948 /* Try matching with configuration. For instance, the
949 configuration may specify "Nimbus Mono L" as an alias of
950 "Courier". */
951 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
952 SYMBOL_FcChar8 (family), NULL);
953 FcChar8 *fam;
955 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
957 for (i = 0;
958 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
959 i++)
961 FcPatternDel (pattern, FC_FAMILY);
962 FcPatternAddString (pattern, FC_FAMILY, fam);
963 FcFontSetDestroy (fontset);
964 fontset = FcFontList (NULL, pattern, objset);
965 if (fontset && fontset->nfont > 0)
966 break;
970 #endif
971 for (i = 0; i < fontset->nfont; i++)
973 Lisp_Object entity;
975 if (spacing >= 0)
977 int this;
979 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
980 == FcResultMatch)
981 && spacing != this)
982 continue;
985 #ifdef FC_CAPABILITY
986 if (otlayout[0])
988 FcChar8 *this;
990 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
991 != FcResultMatch
992 || ! strstr ((char *) this, otlayout))
993 continue;
995 #endif /* FC_CAPABILITY */
996 #ifdef HAVE_LIBOTF
997 if (otspec)
999 FcChar8 *file;
1000 bool passed;
1001 OTF *otf;
1003 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1004 != FcResultMatch)
1005 continue;
1006 otf = OTF_open ((char *) file);
1007 if (! otf)
1008 continue;
1009 passed = (OTF_check_features (otf, 1, otspec->script_tag,
1010 otspec->langsys_tag,
1011 otspec->features[0],
1012 otspec->nfeatures[0]) == 1
1013 && OTF_check_features (otf, 0, otspec->script_tag,
1014 otspec->langsys_tag,
1015 otspec->features[1],
1016 otspec->nfeatures[1]) == 1);
1017 OTF_close (otf);
1018 if (!passed)
1019 continue;
1021 #endif /* HAVE_LIBOTF */
1022 if (VECTORP (chars))
1024 ptrdiff_t j;
1026 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1027 != FcResultMatch)
1028 continue;
1029 for (j = 0; j < ASIZE (chars); j++)
1030 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1031 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1032 break;
1033 if (j == ASIZE (chars))
1034 continue;
1036 if (! NILP (adstyle) || langname)
1038 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1040 if (! NILP (adstyle)
1041 && (NILP (this_adstyle)
1042 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1043 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1044 continue;
1045 if (langname
1046 && ! NILP (this_adstyle)
1047 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1048 continue;
1050 entity = ftfont_pattern_entity (fontset->fonts[i],
1051 AREF (spec, FONT_EXTRA_INDEX));
1052 if (! NILP (entity))
1053 val = Fcons (entity, val);
1055 val = Fnreverse (val);
1056 goto finish;
1058 err:
1059 /* We come here because of unexpected error in fontconfig API call
1060 (usually insufficient memory). */
1061 val = Qnil;
1063 finish:
1064 FONT_ADD_LOG ("ftfont-list", spec, val);
1065 if (objset) FcObjectSetDestroy (objset);
1066 if (fontset) FcFontSetDestroy (fontset);
1067 if (pattern) FcPatternDestroy (pattern);
1068 return val;
1071 static Lisp_Object
1072 ftfont_match (struct frame *f, Lisp_Object spec)
1074 Lisp_Object entity = Qnil;
1075 FcPattern *pattern, *match = NULL;
1076 FcResult result;
1077 char otlayout[15]; /* For "otlayout:XXXX" */
1078 struct OpenTypeSpec *otspec = NULL;
1079 const char *langname = NULL;
1081 if (! fc_initialized)
1083 FcInit ();
1084 fc_initialized = 1;
1087 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1088 if (! pattern)
1089 return Qnil;
1091 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1093 FcValue value;
1095 value.type = FcTypeDouble;
1096 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1097 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1099 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1101 FcDefaultSubstitute (pattern);
1102 match = FcFontMatch (NULL, pattern, &result);
1103 if (match)
1105 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1106 FcPatternDestroy (match);
1107 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1108 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1109 ftfont_generic_family_list))
1110 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1111 AREF (entity, FONT_FAMILY_INDEX))))
1112 entity = Qnil;
1115 FcPatternDestroy (pattern);
1117 FONT_ADD_LOG ("ftfont-match", spec, entity);
1118 return entity;
1121 static Lisp_Object
1122 ftfont_list_family (struct frame *f)
1124 Lisp_Object list = Qnil;
1125 FcPattern *pattern = NULL;
1126 FcFontSet *fontset = NULL;
1127 FcObjectSet *objset = NULL;
1128 int i;
1130 if (! fc_initialized)
1132 FcInit ();
1133 fc_initialized = 1;
1136 pattern = FcPatternCreate ();
1137 if (! pattern)
1138 goto finish;
1139 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1140 if (! objset)
1141 goto finish;
1142 fontset = FcFontList (NULL, pattern, objset);
1143 if (! fontset)
1144 goto finish;
1146 for (i = 0; i < fontset->nfont; i++)
1148 FcPattern *pat = fontset->fonts[i];
1149 FcChar8 *str;
1151 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1152 list = Fcons (intern ((char *) str), list);
1155 finish:
1156 if (objset) FcObjectSetDestroy (objset);
1157 if (fontset) FcFontSetDestroy (fontset);
1158 if (pattern) FcPatternDestroy (pattern);
1160 return list;
1164 static Lisp_Object
1165 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1167 struct ftfont_info *ftfont_info;
1168 struct font *font;
1169 struct ftfont_cache_data *cache_data;
1170 FT_Face ft_face;
1171 FT_Size ft_size;
1172 FT_UInt size;
1173 Lisp_Object val, filename, idx, cache, font_object;
1174 bool scalable;
1175 int spacing;
1176 int i;
1177 int upEM;
1179 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1180 if (! CONSP (val))
1181 return Qnil;
1182 val = XCDR (val);
1183 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1184 if (NILP (cache))
1185 return Qnil;
1186 filename = XCAR (val);
1187 idx = XCDR (val);
1188 val = XCDR (cache);
1189 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1190 ft_face = cache_data->ft_face;
1191 if (XSAVE_INTEGER (val, 1) > 0)
1193 /* FT_Face in this cache is already used by the different size. */
1194 if (FT_New_Size (ft_face, &ft_size) != 0)
1195 return Qnil;
1196 if (FT_Activate_Size (ft_size) != 0)
1198 FT_Done_Size (ft_size);
1199 return Qnil;
1202 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1203 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1204 if (size == 0)
1205 size = pixel_size;
1206 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1208 if (XSAVE_INTEGER (val, 1) == 0)
1209 FT_Done_Face (ft_face);
1210 return Qnil;
1213 font_object = font_build_object (VECSIZE (struct ftfont_info),
1214 Qfreetype, entity, size);
1215 ASET (font_object, FONT_FILE_INDEX, filename);
1216 font = XFONT_OBJECT (font_object);
1217 ftfont_info = (struct ftfont_info *) font;
1218 ftfont_info->ft_size = ft_face->size;
1219 ftfont_info->index = XINT (idx);
1220 #ifdef HAVE_LIBOTF
1221 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1222 ftfont_info->otf = NULL;
1223 #endif /* HAVE_LIBOTF */
1224 /* This means that there's no need of transformation. */
1225 ftfont_info->matrix.xx = 0;
1226 font->pixel_size = size;
1227 font->driver = &ftfont_driver;
1228 font->encoding_charset = font->repertory_charset = -1;
1230 upEM = ft_face->units_per_EM;
1231 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1232 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1233 if (scalable)
1235 font->ascent = ft_face->ascender * size / upEM;
1236 font->descent = - ft_face->descender * size / upEM;
1237 font->height = ft_face->height * size / upEM;
1239 else
1241 font->ascent = ft_face->size->metrics.ascender >> 6;
1242 font->descent = - ft_face->size->metrics.descender >> 6;
1243 font->height = ft_face->size->metrics.height >> 6;
1245 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1246 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1247 else
1248 spacing = FC_PROPORTIONAL;
1249 if (spacing != FC_PROPORTIONAL
1250 #ifdef FC_DUAL
1251 && spacing != FC_DUAL
1252 #endif /* FC_DUAL */
1254 font->min_width = font->average_width = font->space_width
1255 = (scalable ? ft_face->max_advance_width * size / upEM
1256 : ft_face->size->metrics.max_advance >> 6);
1257 else
1259 int n;
1261 font->min_width = font->average_width = font->space_width = 0;
1262 for (i = 32, n = 0; i < 127; i++)
1263 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1265 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1267 if (this_width > 0
1268 && (! font->min_width || font->min_width > this_width))
1269 font->min_width = this_width;
1270 if (i == 32)
1271 font->space_width = this_width;
1272 font->average_width += this_width;
1273 n++;
1275 if (n > 0)
1276 font->average_width /= n;
1279 font->baseline_offset = 0;
1280 font->relative_compose = 0;
1281 font->default_ascent = 0;
1282 font->vertical_centering = 0;
1283 if (scalable)
1285 font->underline_position = -ft_face->underline_position * size / upEM;
1286 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1288 else
1290 font->underline_position = -1;
1291 font->underline_thickness = 0;
1294 return font_object;
1297 static void
1298 ftfont_close (struct font *font)
1300 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1301 Lisp_Object val, cache;
1303 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1304 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1305 eassert (CONSP (cache));
1306 val = XCDR (cache);
1307 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1308 if (XSAVE_INTEGER (val, 1) == 0)
1310 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1312 FT_Done_Face (cache_data->ft_face);
1313 #ifdef HAVE_LIBOTF
1314 if (ftfont_info->otf)
1315 OTF_close (ftfont_info->otf);
1316 #endif
1317 cache_data->ft_face = NULL;
1319 else
1320 FT_Done_Size (ftfont_info->ft_size);
1323 static int
1324 ftfont_has_char (Lisp_Object font, int c)
1326 struct charset *cs = NULL;
1328 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1329 && charset_jisx0208 >= 0)
1330 cs = CHARSET_FROM_ID (charset_jisx0208);
1331 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1332 && charset_ksc5601 >= 0)
1333 cs = CHARSET_FROM_ID (charset_ksc5601);
1334 if (cs)
1335 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1337 if (FONT_ENTITY_P (font))
1339 FcCharSet *charset = ftfont_get_fc_charset (font);
1341 return (FcCharSetHasChar (charset, c) == FcTrue);
1343 else
1345 struct ftfont_info *ftfont_info;
1347 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1348 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1349 != 0);
1353 static unsigned
1354 ftfont_encode_char (struct font *font, int c)
1356 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1357 FT_Face ft_face = ftfont_info->ft_size->face;
1358 FT_ULong charcode = c;
1359 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1361 return (code > 0 ? code : FONT_INVALID_CODE);
1364 static void
1365 ftfont_text_extents (struct font *font, unsigned int *code,
1366 int nglyphs, struct font_metrics *metrics)
1368 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1369 FT_Face ft_face = ftfont_info->ft_size->face;
1370 int i, width = 0;
1371 bool first;
1373 if (ftfont_info->ft_size != ft_face->size)
1374 FT_Activate_Size (ftfont_info->ft_size);
1376 for (i = 0, first = 1; i < nglyphs; i++)
1378 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1380 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1382 if (first)
1384 metrics->lbearing = m->horiBearingX >> 6;
1385 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1386 metrics->ascent = m->horiBearingY >> 6;
1387 metrics->descent = (m->height - m->horiBearingY) >> 6;
1388 first = 0;
1390 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1391 metrics->lbearing = width + (m->horiBearingX >> 6);
1392 if (metrics->rbearing
1393 < width + ((m->horiBearingX + m->width) >> 6))
1394 metrics->rbearing
1395 = width + ((m->horiBearingX + m->width) >> 6);
1396 if (metrics->ascent < (m->horiBearingY >> 6))
1397 metrics->ascent = m->horiBearingY >> 6;
1398 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1399 metrics->descent = (m->height - m->horiBearingY) >> 6;
1400 width += m->horiAdvance >> 6;
1402 else
1403 width += font->space_width;
1405 metrics->width = width;
1408 static int
1409 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1411 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1412 FT_Face ft_face = ftfont_info->ft_size->face;
1413 FT_Int32 load_flags = FT_LOAD_RENDER;
1415 if (ftfont_info->ft_size != ft_face->size)
1416 FT_Activate_Size (ftfont_info->ft_size);
1417 if (bits_per_pixel == 1)
1419 #ifdef FT_LOAD_TARGET_MONO
1420 load_flags |= FT_LOAD_TARGET_MONO;
1421 #else
1422 load_flags |= FT_LOAD_MONOCHROME;
1423 #endif
1425 else if (bits_per_pixel != 8)
1426 /* We don't support such a rendering. */
1427 return -1;
1429 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1430 return -1;
1431 bitmap->bits_per_pixel
1432 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1433 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1434 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1435 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1436 : -1);
1437 if (bitmap->bits_per_pixel < 0)
1438 /* We don't support that kind of pixel mode. */
1439 return -1;
1440 bitmap->rows = ft_face->glyph->bitmap.rows;
1441 bitmap->width = ft_face->glyph->bitmap.width;
1442 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1443 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1444 bitmap->left = ft_face->glyph->bitmap_left;
1445 bitmap->top = ft_face->glyph->bitmap_top;
1446 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1448 return 0;
1451 static int
1452 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1453 int *x, int *y)
1455 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1456 FT_Face ft_face = ftfont_info->ft_size->face;
1458 if (ftfont_info->ft_size != ft_face->size)
1459 FT_Activate_Size (ftfont_info->ft_size);
1460 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1461 return -1;
1462 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1463 return -1;
1464 if (idx >= ft_face->glyph->outline.n_points)
1465 return -1;
1466 *x = ft_face->glyph->outline.points[idx].x;
1467 *y = ft_face->glyph->outline.points[idx].y;
1468 return 0;
1471 #ifdef HAVE_LIBOTF
1473 static Lisp_Object
1474 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1476 Lisp_Object scripts, langsyses, features, sym;
1477 int i, j, k, l;
1479 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1481 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1483 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1485 OTF_LangSys *otf_langsys;
1487 if (j >= 0)
1488 otf_langsys = otf_script->LangSys + j;
1489 else if (otf_script->DefaultLangSysOffset)
1490 otf_langsys = &otf_script->DefaultLangSys;
1491 else
1492 break;
1494 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1496 l = otf_langsys->FeatureIndex[k];
1497 if (l >= gsub_gpos->FeatureList.FeatureCount)
1498 continue;
1499 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1500 features = Fcons (sym, features);
1502 if (j >= 0)
1503 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1504 else
1505 sym = Qnil;
1506 langsyses = Fcons (Fcons (sym, features), langsyses);
1509 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1510 scripts = Fcons (Fcons (sym, langsyses), scripts);
1512 return scripts;
1517 static Lisp_Object
1518 ftfont_otf_capability (struct font *font)
1520 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1521 OTF *otf = ftfont_get_otf (ftfont_info);
1522 Lisp_Object gsub_gpos;
1524 if (! otf)
1525 return Qnil;
1526 gsub_gpos = Fcons (Qnil, Qnil);
1527 if (OTF_get_table (otf, "GSUB") == 0
1528 && otf->gsub->FeatureList.FeatureCount > 0)
1529 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1530 if (OTF_get_table (otf, "GPOS") == 0
1531 && otf->gpos->FeatureList.FeatureCount > 0)
1532 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1533 return gsub_gpos;
1536 #ifdef HAVE_M17N_FLT
1538 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1539 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1540 /* We can use the new feature of libotf and m17n-flt to handle the
1541 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1542 some Agian scripts. */
1543 #define M17N_FLT_USE_NEW_FEATURE
1544 #endif
1546 struct MFLTFontFT
1548 MFLTFont flt_font;
1549 struct font *font;
1550 FT_Face ft_face;
1551 OTF *otf;
1552 FT_Matrix *matrix;
1555 static int
1556 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1557 int from, int to)
1559 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1560 FT_Face ft_face = flt_font_ft->ft_face;
1561 MFLTGlyph *g;
1563 for (g = gstring->glyphs + from; from < to; g++, from++)
1564 if (! g->encoded)
1566 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1568 g->code = code > 0 ? code : FONT_INVALID_CODE;
1569 g->encoded = 1;
1571 return 0;
1574 /* Operators for 26.6 fixed fractional pixel format */
1576 #define FLOOR(x) ((x) & -64)
1577 #define CEIL(x) (((x)+63) & -64)
1578 #define ROUND(x) (((x)+32) & -64)
1580 static int
1581 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1582 int from, int to)
1584 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1585 FT_Face ft_face = flt_font_ft->ft_face;
1586 MFLTGlyph *g;
1588 for (g = gstring->glyphs + from; from < to; g++, from++)
1589 if (! g->measured)
1591 if (g->code != FONT_INVALID_CODE)
1593 FT_Glyph_Metrics *m;
1595 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1596 emacs_abort ();
1597 m = &ft_face->glyph->metrics;
1598 if (flt_font_ft->matrix)
1600 FT_Vector v[4];
1601 int i;
1603 v[0].x = v[1].x = m->horiBearingX;
1604 v[2].x = v[3].x = m->horiBearingX + m->width;
1605 v[0].y = v[2].y = m->horiBearingY;
1606 v[1].y = v[3].y = m->horiBearingY - m->height;
1607 for (i = 0; i < 4; i++)
1608 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1609 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1610 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1611 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1612 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1614 else
1616 g->lbearing = FLOOR (m->horiBearingX);
1617 g->rbearing = CEIL (m->horiBearingX + m->width);
1618 g->ascent = CEIL (m->horiBearingY);
1619 g->descent = - FLOOR (m->horiBearingY - m->height);
1621 g->xadv = ROUND (ft_face->glyph->advance.x);
1623 else
1625 g->lbearing = 0;
1626 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1627 g->ascent = flt_font_ft->font->ascent << 6;
1628 g->descent = flt_font_ft->font->descent << 6;
1630 g->yadv = 0;
1631 g->measured = 1;
1633 return 0;
1636 static int
1637 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1639 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1641 #define FEATURE_ANY(IDX) \
1642 (spec->features[IDX] \
1643 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1645 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1646 OTF *otf = flt_font_ft->otf;
1647 OTF_Tag *tags;
1648 int i, n;
1649 bool negative;
1651 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1652 /* Return true iff any of GSUB or GPOS support the script (and
1653 language). */
1654 return (otf
1655 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1656 NULL, 0) > 0
1657 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1658 NULL, 0) > 0));
1660 for (i = 0; i < 2; i++)
1661 if (! FEATURE_ANY (i))
1663 if (FEATURE_NONE (i))
1665 if (otf
1666 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1667 NULL, 0) > 0)
1668 return 0;
1669 continue;
1671 if (spec->features[i][0] == 0xFFFFFFFF)
1673 if (! otf
1674 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1675 NULL, 0) <= 0)
1676 continue;
1678 else if (! otf)
1679 return 0;
1680 for (n = 1; spec->features[i][n]; n++);
1681 USE_SAFE_ALLOCA;
1682 SAFE_NALLOCA (tags, 1, n);
1683 for (n = 0, negative = 0; spec->features[i][n]; n++)
1685 if (spec->features[i][n] == 0xFFFFFFFF)
1686 negative = 1;
1687 else if (negative)
1688 tags[n - 1] = spec->features[i][n] | 0x80000000;
1689 else
1690 tags[n] = spec->features[i][n];
1692 bool passed = true;
1693 #ifndef M17N_FLT_USE_NEW_FEATURE
1694 passed = n - negative > 0;
1695 #endif
1696 if (passed)
1697 passed = (OTF_check_features (otf, i == 0, spec->script,
1698 spec->langsys, tags, n - negative)
1699 != 1);
1700 SAFE_FREE ();
1701 if (passed)
1702 return 0;
1704 return 1;
1705 #undef FEATURE_NONE
1706 #undef FEATURE_ANY
1709 #define DEVICE_DELTA(table, size) \
1710 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1711 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1712 : 0)
1714 static void
1715 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1716 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1718 if (anchor->AnchorFormat == 2)
1720 FT_Outline *outline;
1721 int ap = anchor->f.f1.AnchorPoint;
1723 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1724 outline = &ft_face->glyph->outline;
1725 if (ap < outline->n_points)
1727 *x = outline->points[ap].x << 6;
1728 *y = outline->points[ap].y << 6;
1731 else if (anchor->AnchorFormat == 3)
1733 if (anchor->f.f2.XDeviceTable.offset
1734 && anchor->f.f2.XDeviceTable.DeltaValue)
1735 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1736 if (anchor->f.f2.YDeviceTable.offset
1737 && anchor->f.f2.YDeviceTable.DeltaValue)
1738 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1742 static OTF_GlyphString otf_gstring;
1744 static void
1745 setup_otf_gstring (int size)
1747 if (otf_gstring.size < size)
1749 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1750 size, sizeof (OTF_Glyph));
1751 otf_gstring.size = size;
1753 otf_gstring.used = size;
1754 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1757 #ifdef M17N_FLT_USE_NEW_FEATURE
1759 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1760 #define PACK_OTF_TAG(TAG) \
1761 ((((TAG) & 0x7F000000) >> 3) \
1762 | (((TAG) & 0x7F0000) >> 2) \
1763 | (((TAG) & 0x7F00) >> 1) \
1764 | ((TAG) & 0x7F))
1766 /* Assuming that FONT is an OpenType font, apply OpenType features
1767 specified in SPEC on glyphs between FROM and TO of IN, and record
1768 the lastly applied feature in each glyph of IN. If OUT is not
1769 NULL, append the resulting glyphs to OUT while storing glyph
1770 position adjustment information in ADJUSTMENT. */
1772 static int
1773 ftfont_drive_otf (MFLTFont *font,
1774 MFLTOtfSpec *spec,
1775 MFLTGlyphString *in,
1776 int from,
1777 int to,
1778 MFLTGlyphString *out,
1779 MFLTGlyphAdjustment *adjustment)
1781 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1782 FT_Face ft_face = flt_font_ft->ft_face;
1783 OTF *otf = flt_font_ft->otf;
1784 int len = to - from;
1785 int i, j, gidx;
1786 OTF_Glyph *otfg;
1787 char script[5], *langsys = NULL;
1788 char *gsub_features = NULL, *gpos_features = NULL;
1789 OTF_Feature *features;
1791 if (len == 0)
1792 return from;
1793 OTF_tag_name (spec->script, script);
1795 char langsysbuf[5];
1796 if (spec->langsys)
1798 langsys = langsysbuf;
1799 OTF_tag_name (spec->langsys, langsys);
1802 USE_SAFE_ALLOCA;
1803 for (i = 0; i < 2; i++)
1805 char *p;
1807 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1809 for (j = 0; spec->features[i][j]; j++);
1810 SAFE_NALLOCA (p, 6, j);
1811 if (i == 0)
1812 gsub_features = p;
1813 else
1814 gpos_features = p;
1815 for (j = 0; spec->features[i][j]; j++)
1817 if (spec->features[i][j] == 0xFFFFFFFF)
1818 *p++ = '*', *p++ = ',';
1819 else
1821 OTF_tag_name (spec->features[i][j], p);
1822 p[4] = ',';
1823 p += 5;
1826 *--p = '\0';
1830 setup_otf_gstring (len);
1831 for (i = 0; i < len; i++)
1833 otf_gstring.glyphs[i].c = in->glyphs[from + i].c & 0x11FFFF;
1834 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1837 OTF_drive_gdef (otf, &otf_gstring);
1838 gidx = out ? out->used : from;
1840 if (gsub_features && out)
1842 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1843 gsub_features) < 0)
1844 goto simple_copy;
1845 if (out->allocated < out->used + otf_gstring.used)
1847 SAFE_FREE ();
1848 return -2;
1850 features = otf->gsub->FeatureList.Feature;
1851 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1853 MFLTGlyph *g;
1854 int min_from, max_to;
1855 int feature_idx = otfg->positioning_type >> 4;
1857 g = out->glyphs + out->used;
1858 *g = in->glyphs[from + otfg->f.index.from];
1859 if (g->code != otfg->glyph_id)
1861 g->c = 0;
1862 g->code = otfg->glyph_id;
1863 g->measured = 0;
1865 out->used++;
1866 min_from = g->from;
1867 max_to = g->to;
1868 if (otfg->f.index.from < otfg->f.index.to)
1870 /* OTFG substitutes multiple glyphs in IN. */
1871 for (j = from + otfg->f.index.from + 1;
1872 j <= from + otfg->f.index.to; j++)
1874 if (min_from > in->glyphs[j].from)
1875 min_from = in->glyphs[j].from;
1876 if (max_to < in->glyphs[j].to)
1877 max_to = in->glyphs[j].to;
1879 g->from = min_from;
1880 g->to = max_to;
1882 if (feature_idx)
1884 unsigned int tag = features[feature_idx - 1].FeatureTag;
1885 tag = PACK_OTF_TAG (tag);
1886 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1888 for (i++, otfg++; (i < otf_gstring.used
1889 && otfg->f.index.from == otfg[-1].f.index.from);
1890 i++, otfg++)
1892 g = out->glyphs + out->used;
1893 *g = in->glyphs[from + otfg->f.index.to];
1894 if (g->code != otfg->glyph_id)
1896 g->c = 0;
1897 g->code = otfg->glyph_id;
1898 g->measured = 0;
1900 feature_idx = otfg->positioning_type >> 4;
1901 if (feature_idx)
1903 unsigned int tag = features[feature_idx - 1].FeatureTag;
1904 tag = PACK_OTF_TAG (tag);
1905 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1907 out->used++;
1911 else if (gsub_features)
1913 /* Just for checking which features will be applied. */
1914 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1915 gsub_features) < 0)
1916 goto simple_copy;
1917 features = otf->gsub->FeatureList.Feature;
1918 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1919 otfg++)
1921 int feature_idx = otfg->positioning_type >> 4;
1923 if (feature_idx)
1925 unsigned int tag = features[feature_idx - 1].FeatureTag;
1926 tag = PACK_OTF_TAG (tag);
1927 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1929 MFLTGlyph *g = in->glyphs + (from + j);
1930 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1935 else if (out)
1937 if (out->allocated < out->used + len)
1939 SAFE_FREE ();
1940 return -2;
1942 for (i = 0; i < len; i++)
1943 out->glyphs[out->used++] = in->glyphs[from + i];
1946 if (gpos_features && out)
1948 MFLTGlyph *base = NULL, *mark = NULL, *g;
1949 int x_ppem, y_ppem, x_scale, y_scale;
1951 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1952 gpos_features) < 0)
1954 SAFE_FREE ();
1955 return to;
1957 features = otf->gpos->FeatureList.Feature;
1958 x_ppem = ft_face->size->metrics.x_ppem;
1959 y_ppem = ft_face->size->metrics.y_ppem;
1960 x_scale = ft_face->size->metrics.x_scale;
1961 y_scale = ft_face->size->metrics.y_scale;
1963 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1964 i < otf_gstring.used; i++, otfg++, g++)
1966 MFLTGlyph *prev;
1967 int feature_idx = otfg->positioning_type >> 4;
1969 if (feature_idx)
1971 unsigned int tag = features[feature_idx - 1].FeatureTag;
1972 tag = PACK_OTF_TAG (tag);
1973 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1976 if (! otfg->glyph_id)
1977 continue;
1978 switch (otfg->positioning_type & 0xF)
1980 case 0:
1981 break;
1982 case 1: /* Single */
1983 case 2: /* Pair */
1985 int format = otfg->f.f1.format;
1987 if (format & OTF_XPlacement)
1988 adjustment[i].xoff
1989 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
1990 if (format & OTF_XPlaDevice)
1991 adjustment[i].xoff
1992 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
1993 if (format & OTF_YPlacement)
1994 adjustment[i].yoff
1995 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
1996 if (format & OTF_YPlaDevice)
1997 adjustment[i].yoff
1998 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
1999 if (format & OTF_XAdvance)
2000 adjustment[i].xadv
2001 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2002 if (format & OTF_XAdvDevice)
2003 adjustment[i].xadv
2004 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2005 if (format & OTF_YAdvance)
2006 adjustment[i].yadv
2007 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2008 if (format & OTF_YAdvDevice)
2009 adjustment[i].yadv
2010 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2011 adjustment[i].set = 1;
2013 break;
2014 case 3: /* Cursive */
2015 /* Not yet supported. */
2016 break;
2017 case 4: /* Mark-to-Base */
2018 case 5: /* Mark-to-Ligature */
2019 if (! base)
2020 break;
2021 prev = base;
2022 goto label_adjust_anchor;
2023 default: /* i.e. case 6 Mark-to-Mark */
2024 if (! mark)
2025 break;
2026 prev = mark;
2028 label_adjust_anchor:
2030 int base_x, base_y, mark_x, mark_y;
2031 int this_from, this_to;
2033 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2034 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2035 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2036 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2038 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2039 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2040 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2041 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2042 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2043 x_ppem, y_ppem, &mark_x, &mark_y);
2044 adjustment[i].xoff = (base_x - mark_x);
2045 adjustment[i].yoff = - (base_y - mark_y);
2046 adjustment[i].back = (g - prev);
2047 adjustment[i].xadv = 0;
2048 adjustment[i].advance_is_absolute = 1;
2049 adjustment[i].set = 1;
2050 this_from = g->from;
2051 this_to = g->to;
2052 for (j = 0; prev + j < g; j++)
2054 if (this_from > prev[j].from)
2055 this_from = prev[j].from;
2056 if (this_to < prev[j].to)
2057 this_to = prev[j].to;
2059 for (; prev <= g; prev++)
2061 prev->from = this_from;
2062 prev->to = this_to;
2066 if (otfg->GlyphClass == OTF_GlyphClass0)
2067 base = mark = g;
2068 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2069 mark = g;
2070 else
2071 base = g;
2074 else if (gpos_features)
2076 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2077 gpos_features) < 0)
2079 SAFE_FREE ();
2080 return to;
2082 features = otf->gpos->FeatureList.Feature;
2083 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2084 i++, otfg++)
2085 if (otfg->positioning_type & 0xF)
2087 int feature_idx = otfg->positioning_type >> 4;
2089 if (feature_idx)
2091 unsigned int tag = features[feature_idx - 1].FeatureTag;
2092 tag = PACK_OTF_TAG (tag);
2093 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2095 MFLTGlyph *g = in->glyphs + (from + j);
2096 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2101 SAFE_FREE ();
2102 return to;
2104 simple_copy:
2105 SAFE_FREE ();
2106 if (! out)
2107 return to;
2108 if (out->allocated < out->used + len)
2109 return -2;
2110 font->get_metrics (font, in, from, to);
2111 memcpy (out->glyphs + out->used, in->glyphs + from,
2112 sizeof (MFLTGlyph) * len);
2113 out->used += len;
2114 return to;
2117 static int
2118 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2119 MFLTGlyphString *in, int from, int to)
2121 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2124 #else /* not M17N_FLT_USE_NEW_FEATURE */
2126 static int
2127 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2128 int from, int to,
2129 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2131 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2132 FT_Face ft_face = flt_font_ft->ft_face;
2133 OTF *otf = flt_font_ft->otf;
2134 int len = to - from;
2135 int i, j, gidx;
2136 OTF_Glyph *otfg;
2137 char script[5], *langsys = NULL;
2138 char *gsub_features = NULL, *gpos_features = NULL;
2140 if (len == 0)
2141 return from;
2142 OTF_tag_name (spec->script, script);
2144 char langsysbuf[5];
2145 if (spec->langsys)
2147 langsys = langsysbuf;
2148 OTF_tag_name (spec->langsys, langsys);
2151 USE_SAFE_ALLOCA;
2152 for (i = 0; i < 2; i++)
2154 char *p;
2156 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2158 for (j = 0; spec->features[i][j]; j++);
2159 SAFE_NALLOCA (p, 6, j);
2160 if (i == 0)
2161 gsub_features = p;
2162 else
2163 gpos_features = p;
2164 for (j = 0; spec->features[i][j]; j++)
2166 if (spec->features[i][j] == 0xFFFFFFFF)
2167 *p++ = '*', *p++ = ',';
2168 else
2170 OTF_tag_name (spec->features[i][j], p);
2171 p[4] = ',';
2172 p += 5;
2175 *--p = '\0';
2179 setup_otf_gstring (len);
2180 for (i = 0; i < len; i++)
2182 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2183 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2186 OTF_drive_gdef (otf, &otf_gstring);
2187 gidx = out->used;
2189 if (gsub_features)
2191 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2192 < 0)
2193 goto simple_copy;
2194 if (out->allocated < out->used + otf_gstring.used)
2196 SAFE_FREE ();
2197 return -2;
2199 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2201 MFLTGlyph *g;
2202 int min_from, max_to;
2203 int j;
2205 g = out->glyphs + out->used;
2206 *g = in->glyphs[from + otfg->f.index.from];
2207 if (g->code != otfg->glyph_id)
2209 g->c = 0;
2210 g->code = otfg->glyph_id;
2211 g->measured = 0;
2213 out->used++;
2214 min_from = g->from;
2215 max_to = g->to;
2216 if (otfg->f.index.from < otfg->f.index.to)
2218 /* OTFG substitutes multiple glyphs in IN. */
2219 for (j = from + otfg->f.index.from + 1;
2220 j <= from + otfg->f.index.to; j++)
2222 if (min_from > in->glyphs[j].from)
2223 min_from = in->glyphs[j].from;
2224 if (max_to < in->glyphs[j].to)
2225 max_to = in->glyphs[j].to;
2227 g->from = min_from;
2228 g->to = max_to;
2230 for (i++, otfg++; (i < otf_gstring.used
2231 && otfg->f.index.from == otfg[-1].f.index.from);
2232 i++, otfg++)
2234 g = out->glyphs + out->used;
2235 *g = in->glyphs[from + otfg->f.index.to];
2236 if (g->code != otfg->glyph_id)
2238 g->c = 0;
2239 g->code = otfg->glyph_id;
2240 g->measured = 0;
2242 out->used++;
2246 else
2248 if (out->allocated < out->used + len)
2250 SAFE_FREE ();
2251 return -2;
2253 for (i = 0; i < len; i++)
2254 out->glyphs[out->used++] = in->glyphs[from + i];
2257 if (gpos_features)
2259 MFLTGlyph *base = NULL, *mark = NULL, *g;
2260 int x_ppem, y_ppem, x_scale, y_scale;
2262 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2263 < 0)
2265 SAFE_FREE ();
2266 return to;
2269 x_ppem = ft_face->size->metrics.x_ppem;
2270 y_ppem = ft_face->size->metrics.y_ppem;
2271 x_scale = ft_face->size->metrics.x_scale;
2272 y_scale = ft_face->size->metrics.y_scale;
2274 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2275 i < otf_gstring.used; i++, otfg++, g++)
2277 MFLTGlyph *prev;
2279 if (! otfg->glyph_id)
2280 continue;
2281 switch (otfg->positioning_type)
2283 case 0:
2284 break;
2285 case 1: /* Single */
2286 case 2: /* Pair */
2288 int format = otfg->f.f1.format;
2290 if (format & OTF_XPlacement)
2291 adjustment[i].xoff
2292 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2293 if (format & OTF_XPlaDevice)
2294 adjustment[i].xoff
2295 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2296 if (format & OTF_YPlacement)
2297 adjustment[i].yoff
2298 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2299 if (format & OTF_YPlaDevice)
2300 adjustment[i].yoff
2301 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2302 if (format & OTF_XAdvance)
2303 adjustment[i].xadv
2304 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2305 if (format & OTF_XAdvDevice)
2306 adjustment[i].xadv
2307 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2308 if (format & OTF_YAdvance)
2309 adjustment[i].yadv
2310 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2311 if (format & OTF_YAdvDevice)
2312 adjustment[i].yadv
2313 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2314 adjustment[i].set = 1;
2316 break;
2317 case 3: /* Cursive */
2318 /* Not yet supported. */
2319 break;
2320 case 4: /* Mark-to-Base */
2321 case 5: /* Mark-to-Ligature */
2322 if (! base)
2323 break;
2324 prev = base;
2325 goto label_adjust_anchor;
2326 default: /* i.e. case 6 Mark-to-Mark */
2327 if (! mark)
2328 break;
2329 prev = mark;
2331 label_adjust_anchor:
2333 int base_x, base_y, mark_x, mark_y;
2334 int this_from, this_to;
2336 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2337 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2338 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2339 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2341 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2342 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2343 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2344 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2345 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2346 x_ppem, y_ppem, &mark_x, &mark_y);
2347 adjustment[i].xoff = (base_x - mark_x);
2348 adjustment[i].yoff = - (base_y - mark_y);
2349 adjustment[i].back = (g - prev);
2350 adjustment[i].xadv = 0;
2351 adjustment[i].advance_is_absolute = 1;
2352 adjustment[i].set = 1;
2353 this_from = g->from;
2354 this_to = g->to;
2355 for (j = 0; prev + j < g; j++)
2357 if (this_from > prev[j].from)
2358 this_from = prev[j].from;
2359 if (this_to < prev[j].to)
2360 this_to = prev[j].to;
2362 for (; prev <= g; prev++)
2364 prev->from = this_from;
2365 prev->to = this_to;
2369 if (otfg->GlyphClass == OTF_GlyphClass0)
2370 base = mark = g;
2371 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2372 mark = g;
2373 else
2374 base = g;
2377 SAFE_FREE ();
2378 return to;
2380 simple_copy:
2381 SAFE_FREE ();
2382 if (out->allocated < out->used + len)
2383 return -2;
2384 font->get_metrics (font, in, from, to);
2385 memcpy (out->glyphs + out->used, in->glyphs + from,
2386 sizeof (MFLTGlyph) * len);
2387 out->used += len;
2388 return to;
2391 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2393 static MFLTGlyphString gstring;
2395 static bool m17n_flt_initialized;
2397 static Lisp_Object
2398 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2399 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2401 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2402 ptrdiff_t i;
2403 struct MFLTFontFT flt_font_ft;
2404 MFLT *flt = NULL;
2405 bool with_variation_selector = 0;
2407 if (! m17n_flt_initialized)
2409 M17N_INIT ();
2410 #ifdef M17N_FLT_USE_NEW_FEATURE
2411 mflt_enable_new_feature = 1;
2412 mflt_try_otf = ftfont_try_otf;
2413 #endif /* M17N_FLT_USE_NEW_FEATURE */
2414 m17n_flt_initialized = 1;
2417 for (i = 0; i < len; i++)
2419 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2420 int c;
2422 if (NILP (g))
2423 break;
2424 c = LGLYPH_CHAR (g);
2425 if (CHAR_VARIATION_SELECTOR_P (c))
2426 with_variation_selector = 1;
2429 len = i;
2431 if (with_variation_selector)
2433 setup_otf_gstring (len);
2434 for (i = 0; i < len; i++)
2436 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2438 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2439 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2440 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2442 OTF_drive_cmap (otf, &otf_gstring);
2443 for (i = 0; i < otf_gstring.used; i++)
2445 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2446 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2447 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2449 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2450 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2451 LGSTRING_SET_GLYPH (lgstring, i, g0);
2453 if (len > otf_gstring.used)
2455 len = otf_gstring.used;
2456 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2460 if (INT_MAX / 2 < len)
2461 memory_full (SIZE_MAX);
2463 if (gstring.allocated == 0)
2465 gstring.glyph_size = sizeof (MFLTGlyph);
2466 gstring.glyphs = xnmalloc (len * 2, sizeof *gstring.glyphs);
2467 gstring.allocated = len * 2;
2469 else if (gstring.allocated < len * 2)
2471 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2,
2472 sizeof *gstring.glyphs);
2473 gstring.allocated = len * 2;
2475 memset (gstring.glyphs, 0, len * sizeof *gstring.glyphs);
2476 for (i = 0; i < len; i++)
2478 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2480 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2481 if (with_variation_selector)
2483 gstring.glyphs[i].code = LGLYPH_CODE (g);
2484 gstring.glyphs[i].encoded = 1;
2488 gstring.used = len;
2489 gstring.r2l = 0;
2492 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2494 if (NILP (family))
2495 flt_font_ft.flt_font.family = Mnil;
2496 else
2497 flt_font_ft.flt_font.family
2498 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2500 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2501 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2502 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2503 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2504 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2505 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2506 flt_font_ft.flt_font.internal = NULL;
2507 flt_font_ft.font = font;
2508 flt_font_ft.ft_face = ft_face;
2509 flt_font_ft.otf = otf;
2510 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2511 if (len > 1
2512 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2513 /* A little bit ad hoc. Perhaps, shaper must get script and
2514 language information, and select a proper flt for them
2515 here. */
2516 flt = mflt_get (msymbol ("combining"));
2517 for (i = 0; i < 3; i++)
2519 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2520 if (result != -2)
2521 break;
2522 if (INT_MAX / 2 < gstring.allocated)
2523 memory_full (SIZE_MAX);
2524 gstring.glyphs = xnrealloc (gstring.glyphs,
2525 gstring.allocated, 2 * sizeof (MFLTGlyph));
2526 gstring.allocated *= 2;
2528 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2529 return Qnil;
2530 for (i = 0; i < gstring.used; i++)
2532 MFLTGlyph *g = gstring.glyphs + i;
2534 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2535 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2538 for (i = 0; i < gstring.used; i++)
2540 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2541 MFLTGlyph *g = gstring.glyphs + i;
2543 if (NILP (lglyph))
2545 lglyph = LGLYPH_NEW ();
2546 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2548 LGLYPH_SET_FROM (lglyph, g->from);
2549 LGLYPH_SET_TO (lglyph, g->to);
2550 LGLYPH_SET_CHAR (lglyph, g->c);
2551 LGLYPH_SET_CODE (lglyph, g->code);
2552 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2553 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2554 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2555 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2556 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2557 if (g->adjusted)
2559 Lisp_Object vec = make_uninit_vector (3);
2561 ASET (vec, 0, make_number (g->xoff >> 6));
2562 ASET (vec, 1, make_number (g->yoff >> 6));
2563 ASET (vec, 2, make_number (g->xadv >> 6));
2564 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2567 return make_number (i);
2570 Lisp_Object
2571 ftfont_shape (Lisp_Object lgstring)
2573 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2574 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2575 OTF *otf = ftfont_get_otf (ftfont_info);
2577 if (! otf)
2578 return make_number (0);
2579 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2580 &ftfont_info->matrix);
2583 #endif /* HAVE_M17N_FLT */
2585 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2587 static int
2588 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2590 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2591 OTF *otf = ftfont_get_otf (ftfont_info);
2593 if (! otf)
2594 return 0;
2595 return OTF_get_variation_glyphs (otf, c, variations);
2598 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2599 #endif /* HAVE_LIBOTF */
2601 static const char *const ftfont_booleans [] = {
2602 ":antialias",
2603 ":hinting",
2604 ":verticallayout",
2605 ":autohint",
2606 ":globaladvance",
2607 ":outline",
2608 ":scalable",
2609 ":minspace",
2610 ":embolden",
2611 NULL,
2614 static const char *const ftfont_non_booleans [] = {
2615 ":family",
2616 ":familylang",
2617 ":style",
2618 ":stylelang",
2619 ":fullname",
2620 ":fullnamelang",
2621 ":slant",
2622 ":weight",
2623 ":size",
2624 ":width",
2625 ":aspect",
2626 ":pixelsize",
2627 ":spacing",
2628 ":foundry",
2629 ":hintstyle",
2630 ":file",
2631 ":index",
2632 ":ftface",
2633 ":rasterizer",
2634 ":scale",
2635 ":dpi",
2636 ":rgba",
2637 ":lcdfilter",
2638 ":charset",
2639 ":lang",
2640 ":fontversion",
2641 ":capability",
2642 NULL,
2645 static void
2646 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2648 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2652 void
2653 syms_of_ftfont (void)
2655 /* Symbolic type of this font-driver. */
2656 DEFSYM (Qfreetype, "freetype");
2658 /* Fontconfig's generic families and their aliases. */
2659 DEFSYM (Qmonospace, "monospace");
2660 DEFSYM (Qsans_serif, "sans-serif");
2661 DEFSYM (Qserif, "serif");
2662 DEFSYM (Qsans, "sans");
2663 DEFSYM (Qsans__serif, "sans serif");
2665 staticpro (&freetype_font_cache);
2666 freetype_font_cache = list1 (Qt);
2668 staticpro (&ftfont_generic_family_list);
2669 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2670 Fcons (Qsans_serif, Qt),
2671 Fcons (Qsans, Qt));
2673 staticpro (&ft_face_cache);
2674 ft_face_cache = Qnil;
2676 ftfont_driver.type = Qfreetype;
2677 register_font_driver (&ftfont_driver, NULL);