Undo port to hypothetical nonzero Qnil case
[emacs.git] / src / ftfont.c
blob053b95fc69f9375b6cdca5ef9092f5f6f23fad06
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))
379 Lisp_Object args[2];
381 args[0] = QCtest;
382 args[1] = Qequal;
383 ft_face_cache = Fmake_hash_table (2, args);
385 cache_data = xmalloc (sizeof *cache_data);
386 cache_data->ft_face = NULL;
387 cache_data->fc_charset = NULL;
388 val = make_save_ptr_int (cache_data, 0);
389 cache = Fcons (Qnil, val);
390 Fputhash (key, cache, ft_face_cache);
392 else
394 val = XCDR (cache);
395 cache_data = XSAVE_POINTER (val, 0);
398 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
399 return cache;
401 if (cache_for == FTFONT_CACHE_FOR_FACE
402 ? ! cache_data->ft_face : ! cache_data->fc_charset)
404 char *filename = SSDATA (XCAR (key));
405 int idx = XINT (XCDR (key));
407 if (cache_for == FTFONT_CACHE_FOR_FACE)
409 if (! ft_library
410 && FT_Init_FreeType (&ft_library) != 0)
411 return Qnil;
412 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
413 != 0)
414 return Qnil;
416 else
418 FcPattern *pat = NULL;
419 FcFontSet *fontset = NULL;
420 FcObjectSet *objset = NULL;
421 FcCharSet *charset = NULL;
423 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
424 FC_INDEX, FcTypeInteger, idx, NULL);
425 if (! pat)
426 goto finish;
427 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
428 if (! objset)
429 goto finish;
430 fontset = FcFontList (NULL, pat, objset);
431 if (! fontset)
432 goto finish;
433 if (fontset && fontset->nfont > 0
434 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
435 &charset)
436 == FcResultMatch))
437 cache_data->fc_charset = FcCharSetCopy (charset);
438 else
439 cache_data->fc_charset = FcCharSetCreate ();
441 finish:
442 if (fontset)
443 FcFontSetDestroy (fontset);
444 if (objset)
445 FcObjectSetDestroy (objset);
446 if (pat)
447 FcPatternDestroy (pat);
450 return cache;
453 FcCharSet *
454 ftfont_get_fc_charset (Lisp_Object entity)
456 Lisp_Object val, cache;
457 struct ftfont_cache_data *cache_data;
459 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
460 val = XCDR (cache);
461 cache_data = XSAVE_POINTER (val, 0);
462 return cache_data->fc_charset;
465 #ifdef HAVE_LIBOTF
466 static OTF *
467 ftfont_get_otf (struct ftfont_info *ftfont_info)
469 OTF *otf;
471 if (ftfont_info->otf)
472 return ftfont_info->otf;
473 if (! ftfont_info->maybe_otf)
474 return NULL;
475 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
476 if (! otf || OTF_get_table (otf, "head") < 0)
478 if (otf)
479 OTF_close (otf);
480 ftfont_info->maybe_otf = 0;
481 return NULL;
483 ftfont_info->otf = otf;
484 return otf;
486 #endif /* HAVE_LIBOTF */
488 static Lisp_Object ftfont_get_cache (struct frame *);
489 static Lisp_Object ftfont_list (struct frame *, Lisp_Object);
490 static Lisp_Object ftfont_match (struct frame *, Lisp_Object);
491 static Lisp_Object ftfont_list_family (struct frame *);
492 static Lisp_Object ftfont_open (struct frame *, Lisp_Object, int);
493 static void ftfont_close (struct font *);
494 static int ftfont_has_char (Lisp_Object, int);
495 static unsigned ftfont_encode_char (struct font *, int);
496 static void ftfont_text_extents (struct font *, unsigned *, int,
497 struct font_metrics *);
498 static int ftfont_get_bitmap (struct font *, unsigned,
499 struct font_bitmap *, int);
500 static int ftfont_anchor_point (struct font *, unsigned, int,
501 int *, int *);
502 #ifdef HAVE_LIBOTF
503 static Lisp_Object ftfont_otf_capability (struct font *);
504 # ifdef HAVE_M17N_FLT
505 static Lisp_Object ftfont_shape (Lisp_Object);
506 # endif
507 #endif
509 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
510 static int ftfont_variation_glyphs (struct font *, int c,
511 unsigned variations[256]);
512 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
514 struct font_driver ftfont_driver =
516 LISP_INITIALLY_ZERO, /* Qfreetype */
517 0, /* case insensitive */
518 ftfont_get_cache,
519 ftfont_list,
520 ftfont_match,
521 ftfont_list_family,
522 NULL, /* free_entity */
523 ftfont_open,
524 ftfont_close,
525 /* We can't draw a text without device dependent functions. */
526 NULL, /* prepare_face */
527 NULL, /* done_face */
528 ftfont_has_char,
529 ftfont_encode_char,
530 ftfont_text_extents,
531 /* We can't draw a text without device dependent functions. */
532 NULL, /* draw */
533 ftfont_get_bitmap,
534 NULL, /* free_bitmap */
535 ftfont_anchor_point,
536 #ifdef HAVE_LIBOTF
537 ftfont_otf_capability,
538 #else /* not HAVE_LIBOTF */
539 NULL,
540 #endif /* not HAVE_LIBOTF */
541 NULL, /* otf_drive */
542 NULL, /* start_for_frame */
543 NULL, /* end_for_frame */
544 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
545 ftfont_shape,
546 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
547 NULL,
548 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
549 NULL, /* check */
551 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
552 ftfont_variation_glyphs,
553 #else
554 NULL,
555 #endif
557 ftfont_filter_properties, /* filter_properties */
560 static Lisp_Object
561 ftfont_get_cache (struct frame *f)
563 return freetype_font_cache;
566 static int
567 ftfont_get_charset (Lisp_Object registry)
569 char *str = SSDATA (SYMBOL_NAME (registry));
570 USE_SAFE_ALLOCA;
571 char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
572 Lisp_Object regexp;
573 int i, j;
575 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
577 if (str[i] == '.')
578 re[j++] = '\\';
579 else if (str[i] == '*')
580 re[j++] = '.';
581 re[j] = str[i];
582 if (re[j] == '?')
583 re[j] = '.';
585 re[j] = '\0';
586 regexp = make_unibyte_string (re, j);
587 SAFE_FREE ();
588 for (i = 0; fc_charset_table[i].name; i++)
589 if (fast_c_string_match_ignore_case
590 (regexp, fc_charset_table[i].name,
591 strlen (fc_charset_table[i].name)) >= 0)
592 break;
593 if (! fc_charset_table[i].name)
594 return -1;
595 if (! fc_charset_table[i].fc_charset)
597 FcCharSet *charset = FcCharSetCreate ();
598 int *uniquifier = fc_charset_table[i].uniquifier;
600 if (! charset)
601 return -1;
602 for (j = 0; uniquifier[j]; j++)
603 if (! FcCharSetAddChar (charset, uniquifier[j]))
605 FcCharSetDestroy (charset);
606 return -1;
608 fc_charset_table[i].fc_charset = charset;
610 return i;
613 struct OpenTypeSpec
615 Lisp_Object script;
616 unsigned int script_tag, langsys_tag;
617 int nfeatures[2];
618 unsigned int *features[2];
621 #define OTF_SYM_TAG(SYM, TAG) \
622 do { \
623 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
624 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
625 } while (0)
627 #define OTF_TAG_STR(TAG, P) \
628 do { \
629 (P)[0] = (char) (TAG >> 24); \
630 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
631 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
632 (P)[3] = (char) (TAG & 0xFF); \
633 (P)[4] = '\0'; \
634 } while (0)
636 #ifdef HAVE_LIBOTF
637 #define OTF_TAG_SYM(SYM, TAG) \
638 do { \
639 char str[5]; \
641 OTF_TAG_STR (TAG, str); \
642 (SYM) = font_intern_prop (str, 4, 1); \
643 } while (0)
644 #endif
647 static struct OpenTypeSpec *
648 ftfont_get_open_type_spec (Lisp_Object otf_spec)
650 struct OpenTypeSpec *spec = malloc (sizeof *spec);
651 Lisp_Object val;
652 int i, j;
653 bool negative;
655 if (! spec)
656 return NULL;
657 spec->script = XCAR (otf_spec);
658 if (! NILP (spec->script))
660 OTF_SYM_TAG (spec->script, spec->script_tag);
661 val = assq_no_quit (spec->script, Votf_script_alist);
662 if (CONSP (val) && SYMBOLP (XCDR (val)))
663 spec->script = XCDR (val);
664 else
665 spec->script = Qnil;
667 else
668 spec->script_tag = 0x44464C54; /* "DFLT" */
669 otf_spec = XCDR (otf_spec);
670 spec->langsys_tag = 0;
671 if (! NILP (otf_spec))
673 val = XCAR (otf_spec);
674 if (! NILP (val))
675 OTF_SYM_TAG (val, spec->langsys_tag);
676 otf_spec = XCDR (otf_spec);
678 spec->nfeatures[0] = spec->nfeatures[1] = 0;
679 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
681 Lisp_Object len;
683 val = XCAR (otf_spec);
684 if (NILP (val))
685 continue;
686 len = Flength (val);
687 spec->features[i] =
688 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
690 : malloc (XINT (len) * sizeof *spec->features[i]));
691 if (! spec->features[i])
693 if (i > 0 && spec->features[0])
694 free (spec->features[0]);
695 free (spec);
696 return NULL;
698 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
700 if (NILP (XCAR (val)))
701 negative = 1;
702 else
704 unsigned int tag;
706 OTF_SYM_TAG (XCAR (val), tag);
707 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
710 spec->nfeatures[i] = j;
712 return spec;
715 static FcPattern *
716 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
718 Lisp_Object tmp, extra;
719 FcPattern *pattern = NULL;
720 FcCharSet *charset = NULL;
721 FcLangSet *langset = NULL;
722 int n;
723 int dpi = -1;
724 int scalable = -1;
725 Lisp_Object script = Qnil;
726 Lisp_Object registry;
727 int fc_charset_idx;
729 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
730 && n < 100)
731 /* Fontconfig doesn't support reverse-italic/oblique. */
732 return NULL;
734 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
735 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
736 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
737 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
738 scalable = 1;
740 registry = AREF (spec, FONT_REGISTRY_INDEX);
741 if (NILP (registry)
742 || EQ (registry, Qascii_0)
743 || EQ (registry, Qiso10646_1)
744 || EQ (registry, Qunicode_bmp))
745 fc_charset_idx = -1;
746 else
748 FcChar8 *lang;
750 fc_charset_idx = ftfont_get_charset (registry);
751 if (fc_charset_idx < 0)
752 return NULL;
753 charset = fc_charset_table[fc_charset_idx].fc_charset;
754 *langname = fc_charset_table[fc_charset_idx].lang;
755 lang = (FcChar8 *) *langname;
756 if (lang)
758 langset = FcLangSetCreate ();
759 if (! langset)
760 goto err;
761 FcLangSetAdd (langset, lang);
765 otlayout[0] = '\0';
766 for (extra = AREF (spec, FONT_EXTRA_INDEX);
767 CONSP (extra); extra = XCDR (extra))
769 Lisp_Object key, val;
771 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
772 if (EQ (key, QCdpi))
774 if (INTEGERP (val))
775 dpi = XINT (val);
777 else if (EQ (key, QClang))
779 if (! langset)
780 langset = FcLangSetCreate ();
781 if (! langset)
782 goto err;
783 if (SYMBOLP (val))
785 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
786 goto err;
788 else
789 for (; CONSP (val); val = XCDR (val))
790 if (SYMBOLP (XCAR (val))
791 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
792 goto err;
794 else if (EQ (key, QCotf))
796 if (CONSP (val))
798 *otspec = ftfont_get_open_type_spec (val);
799 if (! *otspec)
800 return NULL;
801 strcpy (otlayout, "otlayout:");
802 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
803 script = (*otspec)->script;
806 else if (EQ (key, QCscript))
807 script = val;
808 else if (EQ (key, QCscalable))
809 scalable = ! NILP (val);
812 if (! NILP (script) && ! charset)
814 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
816 if (CONSP (chars) && CONSP (CDR (chars)))
818 charset = FcCharSetCreate ();
819 if (! charset)
820 goto err;
821 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
822 if (CHARACTERP (XCAR (chars))
823 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
824 goto err;
828 pattern = FcPatternCreate ();
829 if (! pattern)
830 goto err;
831 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
832 if (! NILP (tmp)
833 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
834 goto err;
835 tmp = AREF (spec, FONT_FAMILY_INDEX);
836 if (! NILP (tmp)
837 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
838 goto err;
839 if (charset
840 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
841 goto err;
842 if (langset
843 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
844 goto err;
845 if (dpi >= 0
846 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
847 goto err;
848 if (scalable >= 0
849 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
850 goto err;
852 goto finish;
854 err:
855 /* We come here because of unexpected error in fontconfig API call
856 (usually insufficient memory). */
857 if (pattern)
859 FcPatternDestroy (pattern);
860 pattern = NULL;
862 if (*otspec)
864 if ((*otspec)->nfeatures[0] > 0)
865 free ((*otspec)->features[0]);
866 if ((*otspec)->nfeatures[1] > 0)
867 free ((*otspec)->features[1]);
868 free (*otspec);
869 *otspec = NULL;
872 finish:
873 if (langset) FcLangSetDestroy (langset);
874 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
875 return pattern;
878 static Lisp_Object
879 ftfont_list (struct frame *f, Lisp_Object spec)
881 Lisp_Object val = Qnil, family, adstyle;
882 int i;
883 FcPattern *pattern;
884 FcFontSet *fontset = NULL;
885 FcObjectSet *objset = NULL;
886 FcCharSet *charset;
887 Lisp_Object chars = Qnil;
888 char otlayout[15]; /* For "otlayout:XXXX" */
889 struct OpenTypeSpec *otspec = NULL;
890 int spacing = -1;
891 const char *langname = NULL;
893 if (! fc_initialized)
895 FcInit ();
896 fc_initialized = 1;
899 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
900 if (! pattern)
901 return Qnil;
902 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
904 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
905 if (! NILP (val))
907 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
908 if (CONSP (val) && VECTORP (XCDR (val)))
909 chars = XCDR (val);
911 val = Qnil;
913 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
914 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
915 family = AREF (spec, FONT_FAMILY_INDEX);
916 if (! NILP (family))
918 Lisp_Object resolved;
920 resolved = ftfont_resolve_generic_family (family, pattern);
921 if (! NILP (resolved))
923 FcPatternDel (pattern, FC_FAMILY);
924 if (! FcPatternAddString (pattern, FC_FAMILY,
925 SYMBOL_FcChar8 (resolved)))
926 goto err;
929 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
930 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
931 adstyle = Qnil;
932 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
933 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
934 FC_STYLE, FC_FILE, FC_INDEX,
935 #ifdef FC_CAPABILITY
936 FC_CAPABILITY,
937 #endif /* FC_CAPABILITY */
938 #ifdef FC_FONTFORMAT
939 FC_FONTFORMAT,
940 #endif
941 NULL);
942 if (! objset)
943 goto err;
944 if (! NILP (chars))
945 FcObjectSetAdd (objset, FC_CHARSET);
947 fontset = FcFontList (NULL, pattern, objset);
948 if (! fontset || fontset->nfont == 0)
949 goto finish;
950 #if 0
951 /* Need fix because this finds any fonts. */
952 if (fontset->nfont == 0 && ! NILP (family))
954 /* Try matching with configuration. For instance, the
955 configuration may specify "Nimbus Mono L" as an alias of
956 "Courier". */
957 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
958 SYMBOL_FcChar8 (family), NULL);
959 FcChar8 *fam;
961 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
963 for (i = 0;
964 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
965 i++)
967 FcPatternDel (pattern, FC_FAMILY);
968 FcPatternAddString (pattern, FC_FAMILY, fam);
969 FcFontSetDestroy (fontset);
970 fontset = FcFontList (NULL, pattern, objset);
971 if (fontset && fontset->nfont > 0)
972 break;
976 #endif
977 for (i = 0; i < fontset->nfont; i++)
979 Lisp_Object entity;
981 if (spacing >= 0)
983 int this;
985 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
986 == FcResultMatch)
987 && spacing != this)
988 continue;
991 #ifdef FC_CAPABILITY
992 if (otlayout[0])
994 FcChar8 *this;
996 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
997 != FcResultMatch
998 || ! strstr ((char *) this, otlayout))
999 continue;
1001 #endif /* FC_CAPABILITY */
1002 #ifdef HAVE_LIBOTF
1003 if (otspec)
1005 FcChar8 *file;
1006 bool passed;
1007 OTF *otf;
1009 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1010 != FcResultMatch)
1011 continue;
1012 otf = OTF_open ((char *) file);
1013 if (! otf)
1014 continue;
1015 passed = (OTF_check_features (otf, 1, otspec->script_tag,
1016 otspec->langsys_tag,
1017 otspec->features[0],
1018 otspec->nfeatures[0]) == 1
1019 && OTF_check_features (otf, 0, otspec->script_tag,
1020 otspec->langsys_tag,
1021 otspec->features[1],
1022 otspec->nfeatures[1]) == 1);
1023 OTF_close (otf);
1024 if (!passed)
1025 continue;
1027 #endif /* HAVE_LIBOTF */
1028 if (VECTORP (chars))
1030 ptrdiff_t j;
1032 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1033 != FcResultMatch)
1034 continue;
1035 for (j = 0; j < ASIZE (chars); j++)
1036 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1037 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1038 break;
1039 if (j == ASIZE (chars))
1040 continue;
1042 if (! NILP (adstyle) || langname)
1044 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1046 if (! NILP (adstyle)
1047 && (NILP (this_adstyle)
1048 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1049 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1050 continue;
1051 if (langname
1052 && ! NILP (this_adstyle)
1053 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1054 continue;
1056 entity = ftfont_pattern_entity (fontset->fonts[i],
1057 AREF (spec, FONT_EXTRA_INDEX));
1058 if (! NILP (entity))
1059 val = Fcons (entity, val);
1061 val = Fnreverse (val);
1062 goto finish;
1064 err:
1065 /* We come here because of unexpected error in fontconfig API call
1066 (usually insufficient memory). */
1067 val = Qnil;
1069 finish:
1070 FONT_ADD_LOG ("ftfont-list", spec, val);
1071 if (objset) FcObjectSetDestroy (objset);
1072 if (fontset) FcFontSetDestroy (fontset);
1073 if (pattern) FcPatternDestroy (pattern);
1074 return val;
1077 static Lisp_Object
1078 ftfont_match (struct frame *f, Lisp_Object spec)
1080 Lisp_Object entity = Qnil;
1081 FcPattern *pattern, *match = NULL;
1082 FcResult result;
1083 char otlayout[15]; /* For "otlayout:XXXX" */
1084 struct OpenTypeSpec *otspec = NULL;
1085 const char *langname = NULL;
1087 if (! fc_initialized)
1089 FcInit ();
1090 fc_initialized = 1;
1093 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1094 if (! pattern)
1095 return Qnil;
1097 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1099 FcValue value;
1101 value.type = FcTypeDouble;
1102 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1103 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1105 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1107 FcDefaultSubstitute (pattern);
1108 match = FcFontMatch (NULL, pattern, &result);
1109 if (match)
1111 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1112 FcPatternDestroy (match);
1113 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1114 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1115 ftfont_generic_family_list))
1116 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1117 AREF (entity, FONT_FAMILY_INDEX))))
1118 entity = Qnil;
1121 FcPatternDestroy (pattern);
1123 FONT_ADD_LOG ("ftfont-match", spec, entity);
1124 return entity;
1127 static Lisp_Object
1128 ftfont_list_family (struct frame *f)
1130 Lisp_Object list = Qnil;
1131 FcPattern *pattern = NULL;
1132 FcFontSet *fontset = NULL;
1133 FcObjectSet *objset = NULL;
1134 int i;
1136 if (! fc_initialized)
1138 FcInit ();
1139 fc_initialized = 1;
1142 pattern = FcPatternCreate ();
1143 if (! pattern)
1144 goto finish;
1145 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1146 if (! objset)
1147 goto finish;
1148 fontset = FcFontList (NULL, pattern, objset);
1149 if (! fontset)
1150 goto finish;
1152 for (i = 0; i < fontset->nfont; i++)
1154 FcPattern *pat = fontset->fonts[i];
1155 FcChar8 *str;
1157 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1158 list = Fcons (intern ((char *) str), list);
1161 finish:
1162 if (objset) FcObjectSetDestroy (objset);
1163 if (fontset) FcFontSetDestroy (fontset);
1164 if (pattern) FcPatternDestroy (pattern);
1166 return list;
1170 static Lisp_Object
1171 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1173 struct ftfont_info *ftfont_info;
1174 struct font *font;
1175 struct ftfont_cache_data *cache_data;
1176 FT_Face ft_face;
1177 FT_Size ft_size;
1178 FT_UInt size;
1179 Lisp_Object val, filename, idx, cache, font_object;
1180 bool scalable;
1181 int spacing;
1182 int i;
1183 int upEM;
1185 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1186 if (! CONSP (val))
1187 return Qnil;
1188 val = XCDR (val);
1189 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1190 if (NILP (cache))
1191 return Qnil;
1192 filename = XCAR (val);
1193 idx = XCDR (val);
1194 val = XCDR (cache);
1195 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1196 ft_face = cache_data->ft_face;
1197 if (XSAVE_INTEGER (val, 1) > 0)
1199 /* FT_Face in this cache is already used by the different size. */
1200 if (FT_New_Size (ft_face, &ft_size) != 0)
1201 return Qnil;
1202 if (FT_Activate_Size (ft_size) != 0)
1204 FT_Done_Size (ft_size);
1205 return Qnil;
1208 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1209 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1210 if (size == 0)
1211 size = pixel_size;
1212 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1214 if (XSAVE_INTEGER (val, 1) == 0)
1215 FT_Done_Face (ft_face);
1216 return Qnil;
1219 font_object = font_build_object (VECSIZE (struct ftfont_info),
1220 Qfreetype, entity, size);
1221 ASET (font_object, FONT_FILE_INDEX, filename);
1222 font = XFONT_OBJECT (font_object);
1223 ftfont_info = (struct ftfont_info *) font;
1224 ftfont_info->ft_size = ft_face->size;
1225 ftfont_info->index = XINT (idx);
1226 #ifdef HAVE_LIBOTF
1227 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1228 ftfont_info->otf = NULL;
1229 #endif /* HAVE_LIBOTF */
1230 /* This means that there's no need of transformation. */
1231 ftfont_info->matrix.xx = 0;
1232 font->pixel_size = size;
1233 font->driver = &ftfont_driver;
1234 font->encoding_charset = font->repertory_charset = -1;
1236 upEM = ft_face->units_per_EM;
1237 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1238 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1239 if (scalable)
1241 font->ascent = ft_face->ascender * size / upEM;
1242 font->descent = - ft_face->descender * size / upEM;
1243 font->height = ft_face->height * size / upEM;
1245 else
1247 font->ascent = ft_face->size->metrics.ascender >> 6;
1248 font->descent = - ft_face->size->metrics.descender >> 6;
1249 font->height = ft_face->size->metrics.height >> 6;
1251 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1252 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1253 else
1254 spacing = FC_PROPORTIONAL;
1255 if (spacing != FC_PROPORTIONAL
1256 #ifdef FC_DUAL
1257 && spacing != FC_DUAL
1258 #endif /* FC_DUAL */
1260 font->min_width = font->average_width = font->space_width
1261 = (scalable ? ft_face->max_advance_width * size / upEM
1262 : ft_face->size->metrics.max_advance >> 6);
1263 else
1265 int n;
1267 font->min_width = font->average_width = font->space_width = 0;
1268 for (i = 32, n = 0; i < 127; i++)
1269 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1271 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1273 if (this_width > 0
1274 && (! font->min_width || font->min_width > this_width))
1275 font->min_width = this_width;
1276 if (i == 32)
1277 font->space_width = this_width;
1278 font->average_width += this_width;
1279 n++;
1281 if (n > 0)
1282 font->average_width /= n;
1285 font->baseline_offset = 0;
1286 font->relative_compose = 0;
1287 font->default_ascent = 0;
1288 font->vertical_centering = 0;
1289 if (scalable)
1291 font->underline_position = -ft_face->underline_position * size / upEM;
1292 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1294 else
1296 font->underline_position = -1;
1297 font->underline_thickness = 0;
1300 return font_object;
1303 static void
1304 ftfont_close (struct font *font)
1306 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1307 Lisp_Object val, cache;
1309 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1310 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1311 eassert (CONSP (cache));
1312 val = XCDR (cache);
1313 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1314 if (XSAVE_INTEGER (val, 1) == 0)
1316 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1318 FT_Done_Face (cache_data->ft_face);
1319 #ifdef HAVE_LIBOTF
1320 if (ftfont_info->otf)
1321 OTF_close (ftfont_info->otf);
1322 #endif
1323 cache_data->ft_face = NULL;
1325 else
1326 FT_Done_Size (ftfont_info->ft_size);
1329 static int
1330 ftfont_has_char (Lisp_Object font, int c)
1332 struct charset *cs = NULL;
1334 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1335 && charset_jisx0208 >= 0)
1336 cs = CHARSET_FROM_ID (charset_jisx0208);
1337 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1338 && charset_ksc5601 >= 0)
1339 cs = CHARSET_FROM_ID (charset_ksc5601);
1340 if (cs)
1341 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1343 if (FONT_ENTITY_P (font))
1345 FcCharSet *charset = ftfont_get_fc_charset (font);
1347 return (FcCharSetHasChar (charset, c) == FcTrue);
1349 else
1351 struct ftfont_info *ftfont_info;
1353 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1354 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1355 != 0);
1359 static unsigned
1360 ftfont_encode_char (struct font *font, int c)
1362 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1363 FT_Face ft_face = ftfont_info->ft_size->face;
1364 FT_ULong charcode = c;
1365 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1367 return (code > 0 ? code : FONT_INVALID_CODE);
1370 static void
1371 ftfont_text_extents (struct font *font, unsigned int *code,
1372 int nglyphs, struct font_metrics *metrics)
1374 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1375 FT_Face ft_face = ftfont_info->ft_size->face;
1376 int i, width = 0;
1377 bool first;
1379 if (ftfont_info->ft_size != ft_face->size)
1380 FT_Activate_Size (ftfont_info->ft_size);
1382 for (i = 0, first = 1; i < nglyphs; i++)
1384 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1386 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1388 if (first)
1390 metrics->lbearing = m->horiBearingX >> 6;
1391 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1392 metrics->ascent = m->horiBearingY >> 6;
1393 metrics->descent = (m->height - m->horiBearingY) >> 6;
1394 first = 0;
1396 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1397 metrics->lbearing = width + (m->horiBearingX >> 6);
1398 if (metrics->rbearing
1399 < width + ((m->horiBearingX + m->width) >> 6))
1400 metrics->rbearing
1401 = width + ((m->horiBearingX + m->width) >> 6);
1402 if (metrics->ascent < (m->horiBearingY >> 6))
1403 metrics->ascent = m->horiBearingY >> 6;
1404 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1405 metrics->descent = (m->height - m->horiBearingY) >> 6;
1406 width += m->horiAdvance >> 6;
1408 else
1409 width += font->space_width;
1411 metrics->width = width;
1414 static int
1415 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1417 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1418 FT_Face ft_face = ftfont_info->ft_size->face;
1419 FT_Int32 load_flags = FT_LOAD_RENDER;
1421 if (ftfont_info->ft_size != ft_face->size)
1422 FT_Activate_Size (ftfont_info->ft_size);
1423 if (bits_per_pixel == 1)
1425 #ifdef FT_LOAD_TARGET_MONO
1426 load_flags |= FT_LOAD_TARGET_MONO;
1427 #else
1428 load_flags |= FT_LOAD_MONOCHROME;
1429 #endif
1431 else if (bits_per_pixel != 8)
1432 /* We don't support such a rendering. */
1433 return -1;
1435 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1436 return -1;
1437 bitmap->bits_per_pixel
1438 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1439 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1440 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1441 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1442 : -1);
1443 if (bitmap->bits_per_pixel < 0)
1444 /* We don't support that kind of pixel mode. */
1445 return -1;
1446 bitmap->rows = ft_face->glyph->bitmap.rows;
1447 bitmap->width = ft_face->glyph->bitmap.width;
1448 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1449 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1450 bitmap->left = ft_face->glyph->bitmap_left;
1451 bitmap->top = ft_face->glyph->bitmap_top;
1452 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1454 return 0;
1457 static int
1458 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1459 int *x, int *y)
1461 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1462 FT_Face ft_face = ftfont_info->ft_size->face;
1464 if (ftfont_info->ft_size != ft_face->size)
1465 FT_Activate_Size (ftfont_info->ft_size);
1466 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1467 return -1;
1468 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1469 return -1;
1470 if (idx >= ft_face->glyph->outline.n_points)
1471 return -1;
1472 *x = ft_face->glyph->outline.points[idx].x;
1473 *y = ft_face->glyph->outline.points[idx].y;
1474 return 0;
1477 #ifdef HAVE_LIBOTF
1479 static Lisp_Object
1480 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1482 Lisp_Object scripts, langsyses, features, sym;
1483 int i, j, k, l;
1485 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1487 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1489 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1491 OTF_LangSys *otf_langsys;
1493 if (j >= 0)
1494 otf_langsys = otf_script->LangSys + j;
1495 else if (otf_script->DefaultLangSysOffset)
1496 otf_langsys = &otf_script->DefaultLangSys;
1497 else
1498 break;
1500 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1502 l = otf_langsys->FeatureIndex[k];
1503 if (l >= gsub_gpos->FeatureList.FeatureCount)
1504 continue;
1505 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1506 features = Fcons (sym, features);
1508 if (j >= 0)
1509 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1510 else
1511 sym = Qnil;
1512 langsyses = Fcons (Fcons (sym, features), langsyses);
1515 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1516 scripts = Fcons (Fcons (sym, langsyses), scripts);
1518 return scripts;
1523 static Lisp_Object
1524 ftfont_otf_capability (struct font *font)
1526 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1527 OTF *otf = ftfont_get_otf (ftfont_info);
1528 Lisp_Object gsub_gpos;
1530 if (! otf)
1531 return Qnil;
1532 gsub_gpos = Fcons (Qnil, Qnil);
1533 if (OTF_get_table (otf, "GSUB") == 0
1534 && otf->gsub->FeatureList.FeatureCount > 0)
1535 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1536 if (OTF_get_table (otf, "GPOS") == 0
1537 && otf->gpos->FeatureList.FeatureCount > 0)
1538 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1539 return gsub_gpos;
1542 #ifdef HAVE_M17N_FLT
1544 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1545 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1546 /* We can use the new feature of libotf and m17n-flt to handle the
1547 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1548 some Agian scripts. */
1549 #define M17N_FLT_USE_NEW_FEATURE
1550 #endif
1552 struct MFLTFontFT
1554 MFLTFont flt_font;
1555 struct font *font;
1556 FT_Face ft_face;
1557 OTF *otf;
1558 FT_Matrix *matrix;
1561 static int
1562 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1563 int from, int to)
1565 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1566 FT_Face ft_face = flt_font_ft->ft_face;
1567 MFLTGlyph *g;
1569 for (g = gstring->glyphs + from; from < to; g++, from++)
1570 if (! g->encoded)
1572 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1574 g->code = code > 0 ? code : FONT_INVALID_CODE;
1575 g->encoded = 1;
1577 return 0;
1580 /* Operators for 26.6 fixed fractional pixel format */
1582 #define FLOOR(x) ((x) & -64)
1583 #define CEIL(x) (((x)+63) & -64)
1584 #define ROUND(x) (((x)+32) & -64)
1586 static int
1587 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1588 int from, int to)
1590 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1591 FT_Face ft_face = flt_font_ft->ft_face;
1592 MFLTGlyph *g;
1594 for (g = gstring->glyphs + from; from < to; g++, from++)
1595 if (! g->measured)
1597 if (g->code != FONT_INVALID_CODE)
1599 FT_Glyph_Metrics *m;
1601 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1602 emacs_abort ();
1603 m = &ft_face->glyph->metrics;
1604 if (flt_font_ft->matrix)
1606 FT_Vector v[4];
1607 int i;
1609 v[0].x = v[1].x = m->horiBearingX;
1610 v[2].x = v[3].x = m->horiBearingX + m->width;
1611 v[0].y = v[2].y = m->horiBearingY;
1612 v[1].y = v[3].y = m->horiBearingY - m->height;
1613 for (i = 0; i < 4; i++)
1614 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1615 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1616 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1617 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1618 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1620 else
1622 g->lbearing = FLOOR (m->horiBearingX);
1623 g->rbearing = CEIL (m->horiBearingX + m->width);
1624 g->ascent = CEIL (m->horiBearingY);
1625 g->descent = - FLOOR (m->horiBearingY - m->height);
1627 g->xadv = ROUND (ft_face->glyph->advance.x);
1629 else
1631 g->lbearing = 0;
1632 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1633 g->ascent = flt_font_ft->font->ascent << 6;
1634 g->descent = flt_font_ft->font->descent << 6;
1636 g->yadv = 0;
1637 g->measured = 1;
1639 return 0;
1642 static int
1643 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1645 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1647 #define FEATURE_ANY(IDX) \
1648 (spec->features[IDX] \
1649 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1651 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1652 OTF *otf = flt_font_ft->otf;
1653 OTF_Tag *tags;
1654 int i, n;
1655 bool negative;
1657 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1658 /* Return true iff any of GSUB or GPOS support the script (and
1659 language). */
1660 return (otf
1661 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1662 NULL, 0) > 0
1663 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1664 NULL, 0) > 0));
1666 for (i = 0; i < 2; i++)
1667 if (! FEATURE_ANY (i))
1669 if (FEATURE_NONE (i))
1671 if (otf
1672 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1673 NULL, 0) > 0)
1674 return 0;
1675 continue;
1677 if (spec->features[i][0] == 0xFFFFFFFF)
1679 if (! otf
1680 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1681 NULL, 0) <= 0)
1682 continue;
1684 else if (! otf)
1685 return 0;
1686 for (n = 1; spec->features[i][n]; n++);
1687 USE_SAFE_ALLOCA;
1688 SAFE_NALLOCA (tags, 1, n);
1689 for (n = 0, negative = 0; spec->features[i][n]; n++)
1691 if (spec->features[i][n] == 0xFFFFFFFF)
1692 negative = 1;
1693 else if (negative)
1694 tags[n - 1] = spec->features[i][n] | 0x80000000;
1695 else
1696 tags[n] = spec->features[i][n];
1698 bool passed = true;
1699 #ifndef M17N_FLT_USE_NEW_FEATURE
1700 passed = n - negative > 0;
1701 #endif
1702 if (passed)
1703 passed = (OTF_check_features (otf, i == 0, spec->script,
1704 spec->langsys, tags, n - negative)
1705 != 1);
1706 SAFE_FREE ();
1707 if (passed)
1708 return 0;
1710 return 1;
1711 #undef FEATURE_NONE
1712 #undef FEATURE_ANY
1715 #define DEVICE_DELTA(table, size) \
1716 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1717 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1718 : 0)
1720 static void
1721 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1722 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1724 if (anchor->AnchorFormat == 2)
1726 FT_Outline *outline;
1727 int ap = anchor->f.f1.AnchorPoint;
1729 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1730 outline = &ft_face->glyph->outline;
1731 if (ap < outline->n_points)
1733 *x = outline->points[ap].x << 6;
1734 *y = outline->points[ap].y << 6;
1737 else if (anchor->AnchorFormat == 3)
1739 if (anchor->f.f2.XDeviceTable.offset
1740 && anchor->f.f2.XDeviceTable.DeltaValue)
1741 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1742 if (anchor->f.f2.YDeviceTable.offset
1743 && anchor->f.f2.YDeviceTable.DeltaValue)
1744 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1748 static OTF_GlyphString otf_gstring;
1750 static void
1751 setup_otf_gstring (int size)
1753 if (otf_gstring.size < size)
1755 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1756 size, sizeof (OTF_Glyph));
1757 otf_gstring.size = size;
1759 otf_gstring.used = size;
1760 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1763 #ifdef M17N_FLT_USE_NEW_FEATURE
1765 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1766 #define PACK_OTF_TAG(TAG) \
1767 ((((TAG) & 0x7F000000) >> 3) \
1768 | (((TAG) & 0x7F0000) >> 2) \
1769 | (((TAG) & 0x7F00) >> 1) \
1770 | ((TAG) & 0x7F))
1772 /* Assuming that FONT is an OpenType font, apply OpenType features
1773 specified in SPEC on glyphs between FROM and TO of IN, and record
1774 the lastly applied feature in each glyph of IN. If OUT is not
1775 NULL, append the resulting glyphs to OUT while storing glyph
1776 position adjustment information in ADJUSTMENT. */
1778 static int
1779 ftfont_drive_otf (MFLTFont *font,
1780 MFLTOtfSpec *spec,
1781 MFLTGlyphString *in,
1782 int from,
1783 int to,
1784 MFLTGlyphString *out,
1785 MFLTGlyphAdjustment *adjustment)
1787 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1788 FT_Face ft_face = flt_font_ft->ft_face;
1789 OTF *otf = flt_font_ft->otf;
1790 int len = to - from;
1791 int i, j, gidx;
1792 OTF_Glyph *otfg;
1793 char script[5], *langsys = NULL;
1794 char *gsub_features = NULL, *gpos_features = NULL;
1795 OTF_Feature *features;
1797 if (len == 0)
1798 return from;
1799 OTF_tag_name (spec->script, script);
1801 char langsysbuf[5];
1802 if (spec->langsys)
1804 langsys = langsysbuf;
1805 OTF_tag_name (spec->langsys, langsys);
1808 USE_SAFE_ALLOCA;
1809 for (i = 0; i < 2; i++)
1811 char *p;
1813 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1815 for (j = 0; spec->features[i][j]; j++);
1816 SAFE_NALLOCA (p, 6, j);
1817 if (i == 0)
1818 gsub_features = p;
1819 else
1820 gpos_features = p;
1821 for (j = 0; spec->features[i][j]; j++)
1823 if (spec->features[i][j] == 0xFFFFFFFF)
1824 *p++ = '*', *p++ = ',';
1825 else
1827 OTF_tag_name (spec->features[i][j], p);
1828 p[4] = ',';
1829 p += 5;
1832 *--p = '\0';
1836 setup_otf_gstring (len);
1837 for (i = 0; i < len; i++)
1839 otf_gstring.glyphs[i].c = in->glyphs[from + i].c & 0x11FFFF;
1840 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1843 OTF_drive_gdef (otf, &otf_gstring);
1844 gidx = out ? out->used : from;
1846 if (gsub_features && out)
1848 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1849 gsub_features) < 0)
1850 goto simple_copy;
1851 if (out->allocated < out->used + otf_gstring.used)
1853 SAFE_FREE ();
1854 return -2;
1856 features = otf->gsub->FeatureList.Feature;
1857 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1859 MFLTGlyph *g;
1860 int min_from, max_to;
1861 int feature_idx = otfg->positioning_type >> 4;
1863 g = out->glyphs + out->used;
1864 *g = in->glyphs[from + otfg->f.index.from];
1865 if (g->code != otfg->glyph_id)
1867 g->c = 0;
1868 g->code = otfg->glyph_id;
1869 g->measured = 0;
1871 out->used++;
1872 min_from = g->from;
1873 max_to = g->to;
1874 if (otfg->f.index.from < otfg->f.index.to)
1876 /* OTFG substitutes multiple glyphs in IN. */
1877 for (j = from + otfg->f.index.from + 1;
1878 j <= from + otfg->f.index.to; j++)
1880 if (min_from > in->glyphs[j].from)
1881 min_from = in->glyphs[j].from;
1882 if (max_to < in->glyphs[j].to)
1883 max_to = in->glyphs[j].to;
1885 g->from = min_from;
1886 g->to = max_to;
1888 if (feature_idx)
1890 unsigned int tag = features[feature_idx - 1].FeatureTag;
1891 tag = PACK_OTF_TAG (tag);
1892 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1894 for (i++, otfg++; (i < otf_gstring.used
1895 && otfg->f.index.from == otfg[-1].f.index.from);
1896 i++, otfg++)
1898 g = out->glyphs + out->used;
1899 *g = in->glyphs[from + otfg->f.index.to];
1900 if (g->code != otfg->glyph_id)
1902 g->c = 0;
1903 g->code = otfg->glyph_id;
1904 g->measured = 0;
1906 feature_idx = otfg->positioning_type >> 4;
1907 if (feature_idx)
1909 unsigned int tag = features[feature_idx - 1].FeatureTag;
1910 tag = PACK_OTF_TAG (tag);
1911 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1913 out->used++;
1917 else if (gsub_features)
1919 /* Just for checking which features will be applied. */
1920 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1921 gsub_features) < 0)
1922 goto simple_copy;
1923 features = otf->gsub->FeatureList.Feature;
1924 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1925 otfg++)
1927 int feature_idx = otfg->positioning_type >> 4;
1929 if (feature_idx)
1931 unsigned int tag = features[feature_idx - 1].FeatureTag;
1932 tag = PACK_OTF_TAG (tag);
1933 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1935 MFLTGlyph *g = in->glyphs + (from + j);
1936 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1941 else if (out)
1943 if (out->allocated < out->used + len)
1945 SAFE_FREE ();
1946 return -2;
1948 for (i = 0; i < len; i++)
1949 out->glyphs[out->used++] = in->glyphs[from + i];
1952 if (gpos_features && out)
1954 MFLTGlyph *base = NULL, *mark = NULL, *g;
1955 int x_ppem, y_ppem, x_scale, y_scale;
1957 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1958 gpos_features) < 0)
1960 SAFE_FREE ();
1961 return to;
1963 features = otf->gpos->FeatureList.Feature;
1964 x_ppem = ft_face->size->metrics.x_ppem;
1965 y_ppem = ft_face->size->metrics.y_ppem;
1966 x_scale = ft_face->size->metrics.x_scale;
1967 y_scale = ft_face->size->metrics.y_scale;
1969 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1970 i < otf_gstring.used; i++, otfg++, g++)
1972 MFLTGlyph *prev;
1973 int feature_idx = otfg->positioning_type >> 4;
1975 if (feature_idx)
1977 unsigned int tag = features[feature_idx - 1].FeatureTag;
1978 tag = PACK_OTF_TAG (tag);
1979 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1982 if (! otfg->glyph_id)
1983 continue;
1984 switch (otfg->positioning_type & 0xF)
1986 case 0:
1987 break;
1988 case 1: /* Single */
1989 case 2: /* Pair */
1991 int format = otfg->f.f1.format;
1993 if (format & OTF_XPlacement)
1994 adjustment[i].xoff
1995 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
1996 if (format & OTF_XPlaDevice)
1997 adjustment[i].xoff
1998 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
1999 if (format & OTF_YPlacement)
2000 adjustment[i].yoff
2001 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2002 if (format & OTF_YPlaDevice)
2003 adjustment[i].yoff
2004 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2005 if (format & OTF_XAdvance)
2006 adjustment[i].xadv
2007 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2008 if (format & OTF_XAdvDevice)
2009 adjustment[i].xadv
2010 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2011 if (format & OTF_YAdvance)
2012 adjustment[i].yadv
2013 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2014 if (format & OTF_YAdvDevice)
2015 adjustment[i].yadv
2016 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2017 adjustment[i].set = 1;
2019 break;
2020 case 3: /* Cursive */
2021 /* Not yet supported. */
2022 break;
2023 case 4: /* Mark-to-Base */
2024 case 5: /* Mark-to-Ligature */
2025 if (! base)
2026 break;
2027 prev = base;
2028 goto label_adjust_anchor;
2029 default: /* i.e. case 6 Mark-to-Mark */
2030 if (! mark)
2031 break;
2032 prev = mark;
2034 label_adjust_anchor:
2036 int base_x, base_y, mark_x, mark_y;
2037 int this_from, this_to;
2039 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2040 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2041 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2042 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2044 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2045 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2046 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2047 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2048 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2049 x_ppem, y_ppem, &mark_x, &mark_y);
2050 adjustment[i].xoff = (base_x - mark_x);
2051 adjustment[i].yoff = - (base_y - mark_y);
2052 adjustment[i].back = (g - prev);
2053 adjustment[i].xadv = 0;
2054 adjustment[i].advance_is_absolute = 1;
2055 adjustment[i].set = 1;
2056 this_from = g->from;
2057 this_to = g->to;
2058 for (j = 0; prev + j < g; j++)
2060 if (this_from > prev[j].from)
2061 this_from = prev[j].from;
2062 if (this_to < prev[j].to)
2063 this_to = prev[j].to;
2065 for (; prev <= g; prev++)
2067 prev->from = this_from;
2068 prev->to = this_to;
2072 if (otfg->GlyphClass == OTF_GlyphClass0)
2073 base = mark = g;
2074 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2075 mark = g;
2076 else
2077 base = g;
2080 else if (gpos_features)
2082 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2083 gpos_features) < 0)
2085 SAFE_FREE ();
2086 return to;
2088 features = otf->gpos->FeatureList.Feature;
2089 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2090 i++, otfg++)
2091 if (otfg->positioning_type & 0xF)
2093 int feature_idx = otfg->positioning_type >> 4;
2095 if (feature_idx)
2097 unsigned int tag = features[feature_idx - 1].FeatureTag;
2098 tag = PACK_OTF_TAG (tag);
2099 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2101 MFLTGlyph *g = in->glyphs + (from + j);
2102 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2107 SAFE_FREE ();
2108 return to;
2110 simple_copy:
2111 SAFE_FREE ();
2112 if (! out)
2113 return to;
2114 if (out->allocated < out->used + len)
2115 return -2;
2116 font->get_metrics (font, in, from, to);
2117 memcpy (out->glyphs + out->used, in->glyphs + from,
2118 sizeof (MFLTGlyph) * len);
2119 out->used += len;
2120 return to;
2123 static int
2124 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2125 MFLTGlyphString *in, int from, int to)
2127 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2130 #else /* not M17N_FLT_USE_NEW_FEATURE */
2132 static int
2133 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2134 int from, int to,
2135 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2137 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2138 FT_Face ft_face = flt_font_ft->ft_face;
2139 OTF *otf = flt_font_ft->otf;
2140 int len = to - from;
2141 int i, j, gidx;
2142 OTF_Glyph *otfg;
2143 char script[5], *langsys = NULL;
2144 char *gsub_features = NULL, *gpos_features = NULL;
2146 if (len == 0)
2147 return from;
2148 OTF_tag_name (spec->script, script);
2150 char langsysbuf[5];
2151 if (spec->langsys)
2153 langsys = langsysbuf;
2154 OTF_tag_name (spec->langsys, langsys);
2157 USE_SAFE_ALLOCA;
2158 for (i = 0; i < 2; i++)
2160 char *p;
2162 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2164 for (j = 0; spec->features[i][j]; j++);
2165 SAFE_NALLOCA (p, 6, j);
2166 if (i == 0)
2167 gsub_features = p;
2168 else
2169 gpos_features = p;
2170 for (j = 0; spec->features[i][j]; j++)
2172 if (spec->features[i][j] == 0xFFFFFFFF)
2173 *p++ = '*', *p++ = ',';
2174 else
2176 OTF_tag_name (spec->features[i][j], p);
2177 p[4] = ',';
2178 p += 5;
2181 *--p = '\0';
2185 setup_otf_gstring (len);
2186 for (i = 0; i < len; i++)
2188 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2189 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2192 OTF_drive_gdef (otf, &otf_gstring);
2193 gidx = out->used;
2195 if (gsub_features)
2197 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2198 < 0)
2199 goto simple_copy;
2200 if (out->allocated < out->used + otf_gstring.used)
2202 SAFE_FREE ();
2203 return -2;
2205 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2207 MFLTGlyph *g;
2208 int min_from, max_to;
2209 int j;
2211 g = out->glyphs + out->used;
2212 *g = in->glyphs[from + otfg->f.index.from];
2213 if (g->code != otfg->glyph_id)
2215 g->c = 0;
2216 g->code = otfg->glyph_id;
2217 g->measured = 0;
2219 out->used++;
2220 min_from = g->from;
2221 max_to = g->to;
2222 if (otfg->f.index.from < otfg->f.index.to)
2224 /* OTFG substitutes multiple glyphs in IN. */
2225 for (j = from + otfg->f.index.from + 1;
2226 j <= from + otfg->f.index.to; j++)
2228 if (min_from > in->glyphs[j].from)
2229 min_from = in->glyphs[j].from;
2230 if (max_to < in->glyphs[j].to)
2231 max_to = in->glyphs[j].to;
2233 g->from = min_from;
2234 g->to = max_to;
2236 for (i++, otfg++; (i < otf_gstring.used
2237 && otfg->f.index.from == otfg[-1].f.index.from);
2238 i++, otfg++)
2240 g = out->glyphs + out->used;
2241 *g = in->glyphs[from + otfg->f.index.to];
2242 if (g->code != otfg->glyph_id)
2244 g->c = 0;
2245 g->code = otfg->glyph_id;
2246 g->measured = 0;
2248 out->used++;
2252 else
2254 if (out->allocated < out->used + len)
2256 SAFE_FREE ();
2257 return -2;
2259 for (i = 0; i < len; i++)
2260 out->glyphs[out->used++] = in->glyphs[from + i];
2263 if (gpos_features)
2265 MFLTGlyph *base = NULL, *mark = NULL, *g;
2266 int x_ppem, y_ppem, x_scale, y_scale;
2268 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2269 < 0)
2271 SAFE_FREE ();
2272 return to;
2275 x_ppem = ft_face->size->metrics.x_ppem;
2276 y_ppem = ft_face->size->metrics.y_ppem;
2277 x_scale = ft_face->size->metrics.x_scale;
2278 y_scale = ft_face->size->metrics.y_scale;
2280 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2281 i < otf_gstring.used; i++, otfg++, g++)
2283 MFLTGlyph *prev;
2285 if (! otfg->glyph_id)
2286 continue;
2287 switch (otfg->positioning_type)
2289 case 0:
2290 break;
2291 case 1: /* Single */
2292 case 2: /* Pair */
2294 int format = otfg->f.f1.format;
2296 if (format & OTF_XPlacement)
2297 adjustment[i].xoff
2298 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2299 if (format & OTF_XPlaDevice)
2300 adjustment[i].xoff
2301 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2302 if (format & OTF_YPlacement)
2303 adjustment[i].yoff
2304 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2305 if (format & OTF_YPlaDevice)
2306 adjustment[i].yoff
2307 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2308 if (format & OTF_XAdvance)
2309 adjustment[i].xadv
2310 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2311 if (format & OTF_XAdvDevice)
2312 adjustment[i].xadv
2313 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2314 if (format & OTF_YAdvance)
2315 adjustment[i].yadv
2316 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2317 if (format & OTF_YAdvDevice)
2318 adjustment[i].yadv
2319 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2320 adjustment[i].set = 1;
2322 break;
2323 case 3: /* Cursive */
2324 /* Not yet supported. */
2325 break;
2326 case 4: /* Mark-to-Base */
2327 case 5: /* Mark-to-Ligature */
2328 if (! base)
2329 break;
2330 prev = base;
2331 goto label_adjust_anchor;
2332 default: /* i.e. case 6 Mark-to-Mark */
2333 if (! mark)
2334 break;
2335 prev = mark;
2337 label_adjust_anchor:
2339 int base_x, base_y, mark_x, mark_y;
2340 int this_from, this_to;
2342 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2343 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2344 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2345 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2347 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2348 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2349 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2350 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2351 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2352 x_ppem, y_ppem, &mark_x, &mark_y);
2353 adjustment[i].xoff = (base_x - mark_x);
2354 adjustment[i].yoff = - (base_y - mark_y);
2355 adjustment[i].back = (g - prev);
2356 adjustment[i].xadv = 0;
2357 adjustment[i].advance_is_absolute = 1;
2358 adjustment[i].set = 1;
2359 this_from = g->from;
2360 this_to = g->to;
2361 for (j = 0; prev + j < g; j++)
2363 if (this_from > prev[j].from)
2364 this_from = prev[j].from;
2365 if (this_to < prev[j].to)
2366 this_to = prev[j].to;
2368 for (; prev <= g; prev++)
2370 prev->from = this_from;
2371 prev->to = this_to;
2375 if (otfg->GlyphClass == OTF_GlyphClass0)
2376 base = mark = g;
2377 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2378 mark = g;
2379 else
2380 base = g;
2383 SAFE_FREE ();
2384 return to;
2386 simple_copy:
2387 SAFE_FREE ();
2388 if (out->allocated < out->used + len)
2389 return -2;
2390 font->get_metrics (font, in, from, to);
2391 memcpy (out->glyphs + out->used, in->glyphs + from,
2392 sizeof (MFLTGlyph) * len);
2393 out->used += len;
2394 return to;
2397 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2399 static MFLTGlyphString gstring;
2401 static bool m17n_flt_initialized;
2403 static Lisp_Object
2404 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2405 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2407 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2408 ptrdiff_t i;
2409 struct MFLTFontFT flt_font_ft;
2410 MFLT *flt = NULL;
2411 bool with_variation_selector = 0;
2413 if (! m17n_flt_initialized)
2415 M17N_INIT ();
2416 #ifdef M17N_FLT_USE_NEW_FEATURE
2417 mflt_enable_new_feature = 1;
2418 mflt_try_otf = ftfont_try_otf;
2419 #endif /* M17N_FLT_USE_NEW_FEATURE */
2420 m17n_flt_initialized = 1;
2423 for (i = 0; i < len; i++)
2425 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2426 int c;
2428 if (NILP (g))
2429 break;
2430 c = LGLYPH_CHAR (g);
2431 if (CHAR_VARIATION_SELECTOR_P (c))
2432 with_variation_selector = 1;
2435 len = i;
2437 if (with_variation_selector)
2439 setup_otf_gstring (len);
2440 for (i = 0; i < len; i++)
2442 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2444 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2445 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2446 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2448 OTF_drive_cmap (otf, &otf_gstring);
2449 for (i = 0; i < otf_gstring.used; i++)
2451 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2452 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2453 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2455 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2456 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2457 LGSTRING_SET_GLYPH (lgstring, i, g0);
2459 if (len > otf_gstring.used)
2461 len = otf_gstring.used;
2462 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2466 if (INT_MAX / 2 < len)
2467 memory_full (SIZE_MAX);
2469 if (gstring.allocated == 0)
2471 gstring.glyph_size = sizeof (MFLTGlyph);
2472 gstring.glyphs = xnmalloc (len * 2, sizeof *gstring.glyphs);
2473 gstring.allocated = len * 2;
2475 else if (gstring.allocated < len * 2)
2477 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2,
2478 sizeof *gstring.glyphs);
2479 gstring.allocated = len * 2;
2481 memset (gstring.glyphs, 0, len * sizeof *gstring.glyphs);
2482 for (i = 0; i < len; i++)
2484 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2486 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2487 if (with_variation_selector)
2489 gstring.glyphs[i].code = LGLYPH_CODE (g);
2490 gstring.glyphs[i].encoded = 1;
2494 gstring.used = len;
2495 gstring.r2l = 0;
2498 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2500 if (NILP (family))
2501 flt_font_ft.flt_font.family = Mnil;
2502 else
2503 flt_font_ft.flt_font.family
2504 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2506 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2507 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2508 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2509 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2510 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2511 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2512 flt_font_ft.flt_font.internal = NULL;
2513 flt_font_ft.font = font;
2514 flt_font_ft.ft_face = ft_face;
2515 flt_font_ft.otf = otf;
2516 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2517 if (len > 1
2518 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2519 /* A little bit ad hoc. Perhaps, shaper must get script and
2520 language information, and select a proper flt for them
2521 here. */
2522 flt = mflt_get (msymbol ("combining"));
2523 for (i = 0; i < 3; i++)
2525 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2526 if (result != -2)
2527 break;
2528 if (INT_MAX / 2 < gstring.allocated)
2529 memory_full (SIZE_MAX);
2530 gstring.glyphs = xnrealloc (gstring.glyphs,
2531 gstring.allocated, 2 * sizeof (MFLTGlyph));
2532 gstring.allocated *= 2;
2534 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2535 return Qnil;
2536 for (i = 0; i < gstring.used; i++)
2538 MFLTGlyph *g = gstring.glyphs + i;
2540 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2541 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2544 for (i = 0; i < gstring.used; i++)
2546 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2547 MFLTGlyph *g = gstring.glyphs + i;
2549 if (NILP (lglyph))
2551 lglyph = LGLYPH_NEW ();
2552 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2554 LGLYPH_SET_FROM (lglyph, g->from);
2555 LGLYPH_SET_TO (lglyph, g->to);
2556 LGLYPH_SET_CHAR (lglyph, g->c);
2557 LGLYPH_SET_CODE (lglyph, g->code);
2558 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2559 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2560 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2561 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2562 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2563 if (g->adjusted)
2565 Lisp_Object vec = make_uninit_vector (3);
2567 ASET (vec, 0, make_number (g->xoff >> 6));
2568 ASET (vec, 1, make_number (g->yoff >> 6));
2569 ASET (vec, 2, make_number (g->xadv >> 6));
2570 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2573 return make_number (i);
2576 Lisp_Object
2577 ftfont_shape (Lisp_Object lgstring)
2579 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2580 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2581 OTF *otf = ftfont_get_otf (ftfont_info);
2583 if (! otf)
2584 return make_number (0);
2585 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2586 &ftfont_info->matrix);
2589 #endif /* HAVE_M17N_FLT */
2591 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2593 static int
2594 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2596 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2597 OTF *otf = ftfont_get_otf (ftfont_info);
2599 if (! otf)
2600 return 0;
2601 return OTF_get_variation_glyphs (otf, c, variations);
2604 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2605 #endif /* HAVE_LIBOTF */
2607 static const char *const ftfont_booleans [] = {
2608 ":antialias",
2609 ":hinting",
2610 ":verticallayout",
2611 ":autohint",
2612 ":globaladvance",
2613 ":outline",
2614 ":scalable",
2615 ":minspace",
2616 ":embolden",
2617 NULL,
2620 static const char *const ftfont_non_booleans [] = {
2621 ":family",
2622 ":familylang",
2623 ":style",
2624 ":stylelang",
2625 ":fullname",
2626 ":fullnamelang",
2627 ":slant",
2628 ":weight",
2629 ":size",
2630 ":width",
2631 ":aspect",
2632 ":pixelsize",
2633 ":spacing",
2634 ":foundry",
2635 ":hintstyle",
2636 ":file",
2637 ":index",
2638 ":ftface",
2639 ":rasterizer",
2640 ":scale",
2641 ":dpi",
2642 ":rgba",
2643 ":lcdfilter",
2644 ":charset",
2645 ":lang",
2646 ":fontversion",
2647 ":capability",
2648 NULL,
2651 static void
2652 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2654 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2658 void
2659 syms_of_ftfont (void)
2661 /* Symbolic type of this font-driver. */
2662 DEFSYM (Qfreetype, "freetype");
2664 /* Fontconfig's generic families and their aliases. */
2665 DEFSYM (Qmonospace, "monospace");
2666 DEFSYM (Qsans_serif, "sans-serif");
2667 DEFSYM (Qserif, "serif");
2668 DEFSYM (Qmono, "mono");
2669 DEFSYM (Qsans, "sans");
2670 DEFSYM (Qsans__serif, "sans serif");
2672 staticpro (&freetype_font_cache);
2673 freetype_font_cache = list1 (Qt);
2675 staticpro (&ftfont_generic_family_list);
2676 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2677 Fcons (Qsans_serif, Qt),
2678 Fcons (Qsans, Qt));
2680 staticpro (&ft_face_cache);
2681 ft_face_cache = Qnil;
2683 ftfont_driver.type = Qfreetype;
2684 register_font_driver (&ftfont_driver, NULL);