* lisp/emacs-lisp/easy-mmode.el (define-minor-mode): Use mode function
[emacs.git] / src / ftfont.c
blob1cad158065be6712609ee7e9c9038e7157f4464f
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2014 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 "lisp.h"
28 #include "dispextern.h"
29 #include "frame.h"
30 #include "blockinput.h"
31 #include "character.h"
32 #include "charset.h"
33 #include "coding.h"
34 #include "composite.h"
35 #include "fontset.h"
36 #include "font.h"
37 #include "ftfont.h"
39 /* Symbolic type of this font-driver. */
40 static Lisp_Object Qfreetype;
42 /* Fontconfig's generic families and their aliases. */
43 static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
45 /* Flag to tell if FcInit is already called or not. */
46 static bool fc_initialized;
48 /* Handle to a FreeType library instance. */
49 static FT_Library ft_library;
51 /* Cache for FreeType fonts. */
52 static Lisp_Object freetype_font_cache;
54 /* Cache for FT_Face and FcCharSet. */
55 static Lisp_Object ft_face_cache;
57 /* The actual structure for FreeType font that can be cast to struct
58 font. */
60 struct ftfont_info
62 struct font font;
63 #ifdef HAVE_LIBOTF
64 /* The following four members must be here in this order to be
65 compatible with struct xftfont_info (in xftfont.c). */
66 bool maybe_otf; /* Flag to tell if this may be OTF or not. */
67 OTF *otf;
68 #endif /* HAVE_LIBOTF */
69 FT_Size ft_size;
70 int index;
71 FT_Matrix matrix;
74 enum ftfont_cache_for
76 FTFONT_CACHE_FOR_FACE,
77 FTFONT_CACHE_FOR_CHARSET,
78 FTFONT_CACHE_FOR_ENTITY
81 static Lisp_Object ftfont_pattern_entity (FcPattern *, Lisp_Object);
83 static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
84 FcPattern *);
85 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
86 enum ftfont_cache_for);
88 static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
90 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
92 static struct
94 /* registry name */
95 const char *name;
96 /* characters to distinguish the charset from the others */
97 int uniquifier[6];
98 /* additional constraint by language */
99 const char *lang;
100 /* set on demand */
101 FcCharSet *fc_charset;
102 } fc_charset_table[] =
103 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
104 { "iso8859-2", { 0x00A0, 0x010E }},
105 { "iso8859-3", { 0x00A0, 0x0108 }},
106 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
107 { "iso8859-5", { 0x00A0, 0x0401 }},
108 { "iso8859-6", { 0x00A0, 0x060C }},
109 { "iso8859-7", { 0x00A0, 0x0384 }},
110 { "iso8859-8", { 0x00A0, 0x05D0 }},
111 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
112 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
113 { "iso8859-11", { 0x00A0, 0x0E01 }},
114 { "iso8859-13", { 0x00A0, 0x201C }},
115 { "iso8859-14", { 0x00A0, 0x0174 }},
116 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
117 { "iso8859-16", { 0x00A0, 0x0218}},
118 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
119 { "big5-0", { 0xF6B1 }, "zh-tw" },
120 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
121 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
122 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
123 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
124 { "cns11643.1992-3", { 0x201A9 }},
125 { "cns11643.1992-4", { 0x20057 }},
126 { "cns11643.1992-5", { 0x20000 }},
127 { "cns11643.1992-6", { 0x20003 }},
128 { "cns11643.1992-7", { 0x20055 }},
129 { "gbk-0", { 0x4E06 }, "zh-cn"},
130 { "jisx0212.1990-0", { 0x4E44 }},
131 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
132 { "jisx0213.2000-2", { 0xFA49 }},
133 { "jisx0213.2004-1", { 0x20B9F }},
134 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
135 { "tis620.2529-1", { 0x0E01 }, "th"},
136 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
137 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
138 { "mulelao-1", { 0x0E81 }, "lo"},
139 { "unicode-sip", { 0x20000 }},
140 { NULL }
143 /* Dirty hack for handing ADSTYLE property.
145 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
146 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
147 "Oblique", "Italic", or any non-normal SWIDTH property names
148 (e.g. SemiCondensed) are appended. In addition, if there's no
149 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
150 "Regular" is used for FC_STYLE (see the function
151 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
153 Unfortunately this behavior is not documented, so the following
154 code may fail if FreeType changes the behavior in the future. */
156 static Lisp_Object
157 get_adstyle_property (FcPattern *p)
159 FcChar8 *fcstr;
160 char *str, *end;
161 Lisp_Object adstyle;
163 #ifdef FC_FONTFORMAT
164 if ((FcPatternGetString (p, FC_FONTFORMAT, 0, &fcstr) == FcResultMatch)
165 && xstrcasecmp ((char *) fcstr, "bdf") != 0
166 && xstrcasecmp ((char *) fcstr, "pcf") != 0)
167 /* Not a BDF nor PCF font. */
168 return Qnil;
169 #endif
170 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
171 return Qnil;
172 str = (char *) fcstr;
173 for (end = str; *end && *end != ' '; end++);
174 if (*end)
176 char *newstr = alloca (end - str + 1);
177 memcpy (newstr, str, end - str);
178 newstr[end - str] = '\0';
179 end = newstr + (end - str);
180 str = newstr;
182 if (xstrcasecmp (str, "Regular") == 0
183 || xstrcasecmp (str, "Bold") == 0
184 || xstrcasecmp (str, "Oblique") == 0
185 || xstrcasecmp (str, "Italic") == 0)
186 return Qnil;
187 adstyle = font_intern_prop (str, end - str, 1);
188 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
189 return Qnil;
190 return adstyle;
193 static Lisp_Object
194 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
196 Lisp_Object key, cache, entity;
197 FcChar8 *str;
198 char *file;
199 int idx;
200 int numeric;
201 double dbl;
202 FcBool b;
204 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
205 return Qnil;
206 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
207 return Qnil;
209 file = (char *) str;
210 key = Fcons (build_unibyte_string (file), make_number (idx));
211 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
212 entity = XCAR (cache);
213 if (! NILP (entity))
215 Lisp_Object val = font_make_entity ();
216 int i;
218 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
219 ASET (val, i, AREF (entity, i));
221 ASET (val, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
222 font_put_extra (val, QCfont_entity, key);
224 return val;
226 entity = font_make_entity ();
227 XSETCAR (cache, entity);
229 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
230 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
232 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
234 char *s = (char *) str;
235 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
237 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
239 char *s = (char *) str;
240 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
242 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
244 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
245 numeric = FC_WEIGHT_MEDIUM;
246 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
248 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
250 numeric += 100;
251 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
253 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
255 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
257 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
259 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
261 else
262 ASET (entity, FONT_SIZE_INDEX, make_number (0));
263 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
264 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
265 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
267 int dpi = dbl;
268 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
270 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
271 && b == FcTrue)
273 ASET (entity, FONT_SIZE_INDEX, make_number (0));
274 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
276 else
278 /* As this font is not scalable, perhaps this is a BDF or PCF
279 font. */
280 FT_Face ft_face;
282 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
283 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
284 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
286 BDF_PropertyRec rec;
288 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
289 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
290 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
291 FT_Done_Face (ft_face);
295 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
296 font_put_extra (entity, QCfont_entity, key);
297 return entity;
301 static Lisp_Object ftfont_generic_family_list;
303 static Lisp_Object
304 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
306 Lisp_Object slot;
307 FcPattern *match;
308 FcResult result;
309 FcLangSet *langset;
311 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
312 if (EQ (family, Qmono))
313 family = Qmonospace;
314 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
315 family = Qsans_serif;
316 slot = assq_no_quit (family, ftfont_generic_family_list);
317 if (! CONSP (slot))
318 return Qnil;
319 if (! EQ (XCDR (slot), Qt))
320 return XCDR (slot);
321 pattern = FcPatternDuplicate (pattern);
322 if (! pattern)
323 goto err;
324 FcPatternDel (pattern, FC_FOUNDRY);
325 FcPatternDel (pattern, FC_FAMILY);
326 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
327 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
329 /* This is to avoid the effect of locale. */
330 static const FcChar8 lang[] = "en";
331 langset = FcLangSetCreate ();
332 FcLangSetAdd (langset, lang);
333 FcPatternAddLangSet (pattern, FC_LANG, langset);
334 FcLangSetDestroy (langset);
336 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
337 FcDefaultSubstitute (pattern);
338 match = FcFontMatch (NULL, pattern, &result);
339 if (match)
341 FcChar8 *fam;
343 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
344 family = intern ((char *) fam);
346 else
347 family = Qnil;
348 XSETCDR (slot, family);
349 if (match) FcPatternDestroy (match);
350 err:
351 if (pattern) FcPatternDestroy (pattern);
352 return family;
355 struct ftfont_cache_data
357 FT_Face ft_face;
358 FcCharSet *fc_charset;
361 static Lisp_Object
362 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
364 Lisp_Object cache, val, entity;
365 struct ftfont_cache_data *cache_data;
367 if (FONT_ENTITY_P (key))
369 entity = key;
370 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
371 eassert (CONSP (val));
372 key = XCDR (val);
374 else
375 entity = Qnil;
377 if (NILP (ft_face_cache))
378 cache = Qnil;
379 else
380 cache = Fgethash (key, ft_face_cache, Qnil);
381 if (NILP (cache))
383 if (NILP (ft_face_cache))
385 Lisp_Object args[2];
387 args[0] = QCtest;
388 args[1] = Qequal;
389 ft_face_cache = Fmake_hash_table (2, args);
391 cache_data = xmalloc (sizeof *cache_data);
392 cache_data->ft_face = NULL;
393 cache_data->fc_charset = NULL;
394 val = make_save_ptr_int (cache_data, 0);
395 cache = Fcons (Qnil, val);
396 Fputhash (key, cache, ft_face_cache);
398 else
400 val = XCDR (cache);
401 cache_data = XSAVE_POINTER (val, 0);
404 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
405 return cache;
407 if (cache_for == FTFONT_CACHE_FOR_FACE
408 ? ! cache_data->ft_face : ! cache_data->fc_charset)
410 char *filename = SSDATA (XCAR (key));
411 int idx = XINT (XCDR (key));
413 if (cache_for == FTFONT_CACHE_FOR_FACE)
415 if (! ft_library
416 && FT_Init_FreeType (&ft_library) != 0)
417 return Qnil;
418 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
419 != 0)
420 return Qnil;
422 else
424 FcPattern *pat = NULL;
425 FcFontSet *fontset = NULL;
426 FcObjectSet *objset = NULL;
427 FcCharSet *charset = NULL;
429 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
430 FC_INDEX, FcTypeInteger, idx, NULL);
431 if (! pat)
432 goto finish;
433 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
434 if (! objset)
435 goto finish;
436 fontset = FcFontList (NULL, pat, objset);
437 if (! fontset)
438 goto finish;
439 if (fontset && fontset->nfont > 0
440 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
441 &charset)
442 == FcResultMatch))
443 cache_data->fc_charset = FcCharSetCopy (charset);
444 else
445 cache_data->fc_charset = FcCharSetCreate ();
447 finish:
448 if (fontset)
449 FcFontSetDestroy (fontset);
450 if (objset)
451 FcObjectSetDestroy (objset);
452 if (pat)
453 FcPatternDestroy (pat);
456 return cache;
459 FcCharSet *
460 ftfont_get_fc_charset (Lisp_Object entity)
462 Lisp_Object val, cache;
463 struct ftfont_cache_data *cache_data;
465 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
466 val = XCDR (cache);
467 cache_data = XSAVE_POINTER (val, 0);
468 return cache_data->fc_charset;
471 #ifdef HAVE_LIBOTF
472 static OTF *
473 ftfont_get_otf (struct ftfont_info *ftfont_info)
475 OTF *otf;
477 if (ftfont_info->otf)
478 return ftfont_info->otf;
479 if (! ftfont_info->maybe_otf)
480 return NULL;
481 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
482 if (! otf || OTF_get_table (otf, "head") < 0)
484 if (otf)
485 OTF_close (otf);
486 ftfont_info->maybe_otf = 0;
487 return NULL;
489 ftfont_info->otf = otf;
490 return otf;
492 #endif /* HAVE_LIBOTF */
494 static Lisp_Object ftfont_get_cache (struct frame *);
495 static Lisp_Object ftfont_list (struct frame *, Lisp_Object);
496 static Lisp_Object ftfont_match (struct frame *, Lisp_Object);
497 static Lisp_Object ftfont_list_family (struct frame *);
498 static Lisp_Object ftfont_open (struct frame *, Lisp_Object, int);
499 static void ftfont_close (struct font *);
500 static int ftfont_has_char (Lisp_Object, int);
501 static unsigned ftfont_encode_char (struct font *, int);
502 static void ftfont_text_extents (struct font *, unsigned *, int,
503 struct font_metrics *);
504 static int ftfont_get_bitmap (struct font *, unsigned,
505 struct font_bitmap *, int);
506 static int ftfont_anchor_point (struct font *, unsigned, int,
507 int *, int *);
508 #ifdef HAVE_LIBOTF
509 static Lisp_Object ftfont_otf_capability (struct font *);
510 # ifdef HAVE_M17N_FLT
511 static Lisp_Object ftfont_shape (Lisp_Object);
512 # endif
513 #endif
515 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
516 static int ftfont_variation_glyphs (struct font *, int c,
517 unsigned variations[256]);
518 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
520 struct font_driver ftfont_driver =
522 LISP_INITIALLY_ZERO, /* Qfreetype */
523 0, /* case insensitive */
524 ftfont_get_cache,
525 ftfont_list,
526 ftfont_match,
527 ftfont_list_family,
528 NULL, /* free_entity */
529 ftfont_open,
530 ftfont_close,
531 /* We can't draw a text without device dependent functions. */
532 NULL, /* prepare_face */
533 NULL, /* done_face */
534 ftfont_has_char,
535 ftfont_encode_char,
536 ftfont_text_extents,
537 /* We can't draw a text without device dependent functions. */
538 NULL, /* draw */
539 ftfont_get_bitmap,
540 NULL, /* free_bitmap */
541 ftfont_anchor_point,
542 #ifdef HAVE_LIBOTF
543 ftfont_otf_capability,
544 #else /* not HAVE_LIBOTF */
545 NULL,
546 #endif /* not HAVE_LIBOTF */
547 NULL, /* otf_drive */
548 NULL, /* start_for_frame */
549 NULL, /* end_for_frame */
550 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
551 ftfont_shape,
552 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
553 NULL,
554 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
555 NULL, /* check */
557 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
558 ftfont_variation_glyphs,
559 #else
560 NULL,
561 #endif
563 ftfont_filter_properties, /* filter_properties */
566 static Lisp_Object
567 ftfont_get_cache (struct frame *f)
569 return freetype_font_cache;
572 static int
573 ftfont_get_charset (Lisp_Object registry)
575 char *str = SSDATA (SYMBOL_NAME (registry));
576 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
577 Lisp_Object regexp;
578 int i, j;
580 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
582 if (str[i] == '.')
583 re[j++] = '\\';
584 else if (str[i] == '*')
585 re[j++] = '.';
586 re[j] = str[i];
587 if (re[j] == '?')
588 re[j] = '.';
590 re[j] = '\0';
591 regexp = make_unibyte_string (re, j);
592 for (i = 0; fc_charset_table[i].name; i++)
593 if (fast_c_string_match_ignore_case
594 (regexp, fc_charset_table[i].name,
595 strlen (fc_charset_table[i].name)) >= 0)
596 break;
597 if (! fc_charset_table[i].name)
598 return -1;
599 if (! fc_charset_table[i].fc_charset)
601 FcCharSet *charset = FcCharSetCreate ();
602 int *uniquifier = fc_charset_table[i].uniquifier;
604 if (! charset)
605 return -1;
606 for (j = 0; uniquifier[j]; j++)
607 if (! FcCharSetAddChar (charset, uniquifier[j]))
609 FcCharSetDestroy (charset);
610 return -1;
612 fc_charset_table[i].fc_charset = charset;
614 return i;
617 struct OpenTypeSpec
619 Lisp_Object script;
620 unsigned int script_tag, langsys_tag;
621 int nfeatures[2];
622 unsigned int *features[2];
625 #define OTF_SYM_TAG(SYM, TAG) \
626 do { \
627 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
628 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
629 } while (0)
631 #define OTF_TAG_STR(TAG, P) \
632 do { \
633 (P)[0] = (char) (TAG >> 24); \
634 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
635 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
636 (P)[3] = (char) (TAG & 0xFF); \
637 (P)[4] = '\0'; \
638 } while (0)
640 #ifdef HAVE_LIBOTF
641 #define OTF_TAG_SYM(SYM, TAG) \
642 do { \
643 char str[5]; \
645 OTF_TAG_STR (TAG, str); \
646 (SYM) = font_intern_prop (str, 4, 1); \
647 } while (0)
648 #endif
651 static struct OpenTypeSpec *
652 ftfont_get_open_type_spec (Lisp_Object otf_spec)
654 struct OpenTypeSpec *spec = malloc (sizeof *spec);
655 Lisp_Object val;
656 int i, j;
657 bool negative;
659 if (! spec)
660 return NULL;
661 spec->script = XCAR (otf_spec);
662 if (! NILP (spec->script))
664 OTF_SYM_TAG (spec->script, spec->script_tag);
665 val = assq_no_quit (spec->script, Votf_script_alist);
666 if (CONSP (val) && SYMBOLP (XCDR (val)))
667 spec->script = XCDR (val);
668 else
669 spec->script = Qnil;
671 else
672 spec->script_tag = 0x44464C54; /* "DFLT" */
673 otf_spec = XCDR (otf_spec);
674 spec->langsys_tag = 0;
675 if (! NILP (otf_spec))
677 val = XCAR (otf_spec);
678 if (! NILP (val))
679 OTF_SYM_TAG (val, spec->langsys_tag);
680 otf_spec = XCDR (otf_spec);
682 spec->nfeatures[0] = spec->nfeatures[1] = 0;
683 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
685 Lisp_Object len;
687 val = XCAR (otf_spec);
688 if (NILP (val))
689 continue;
690 len = Flength (val);
691 spec->features[i] =
692 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
694 : malloc (XINT (len) * sizeof *spec->features[i]));
695 if (! spec->features[i])
697 if (i > 0 && spec->features[0])
698 free (spec->features[0]);
699 free (spec);
700 return NULL;
702 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
704 if (NILP (XCAR (val)))
705 negative = 1;
706 else
708 unsigned int tag;
710 OTF_SYM_TAG (XCAR (val), tag);
711 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
714 spec->nfeatures[i] = j;
716 return spec;
719 static FcPattern *
720 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
722 Lisp_Object tmp, extra;
723 FcPattern *pattern = NULL;
724 FcCharSet *charset = NULL;
725 FcLangSet *langset = NULL;
726 int n;
727 int dpi = -1;
728 int scalable = -1;
729 Lisp_Object script = Qnil;
730 Lisp_Object registry;
731 int fc_charset_idx;
733 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
734 && n < 100)
735 /* Fontconfig doesn't support reverse-italic/oblique. */
736 return NULL;
738 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
739 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
740 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
741 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
742 scalable = 1;
744 registry = AREF (spec, FONT_REGISTRY_INDEX);
745 if (NILP (registry)
746 || EQ (registry, Qascii_0)
747 || EQ (registry, Qiso10646_1)
748 || EQ (registry, Qunicode_bmp))
749 fc_charset_idx = -1;
750 else
752 FcChar8 *lang;
754 fc_charset_idx = ftfont_get_charset (registry);
755 if (fc_charset_idx < 0)
756 return NULL;
757 charset = fc_charset_table[fc_charset_idx].fc_charset;
758 *langname = fc_charset_table[fc_charset_idx].lang;
759 lang = (FcChar8 *) *langname;
760 if (lang)
762 langset = FcLangSetCreate ();
763 if (! langset)
764 goto err;
765 FcLangSetAdd (langset, lang);
769 otlayout[0] = '\0';
770 for (extra = AREF (spec, FONT_EXTRA_INDEX);
771 CONSP (extra); extra = XCDR (extra))
773 Lisp_Object key, val;
775 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
776 if (EQ (key, QCdpi))
778 if (INTEGERP (val))
779 dpi = XINT (val);
781 else if (EQ (key, QClang))
783 if (! langset)
784 langset = FcLangSetCreate ();
785 if (! langset)
786 goto err;
787 if (SYMBOLP (val))
789 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
790 goto err;
792 else
793 for (; CONSP (val); val = XCDR (val))
794 if (SYMBOLP (XCAR (val))
795 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
796 goto err;
798 else if (EQ (key, QCotf))
800 if (CONSP (val))
802 *otspec = ftfont_get_open_type_spec (val);
803 if (! *otspec)
804 return NULL;
805 strcat (otlayout, "otlayout:");
806 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
807 script = (*otspec)->script;
810 else if (EQ (key, QCscript))
811 script = val;
812 else if (EQ (key, QCscalable))
813 scalable = ! NILP (val);
816 if (! NILP (script) && ! charset)
818 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
820 if (CONSP (chars) && CONSP (CDR (chars)))
822 charset = FcCharSetCreate ();
823 if (! charset)
824 goto err;
825 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
826 if (CHARACTERP (XCAR (chars))
827 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
828 goto err;
832 pattern = FcPatternCreate ();
833 if (! pattern)
834 goto err;
835 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
836 if (! NILP (tmp)
837 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
838 goto err;
839 tmp = AREF (spec, FONT_FAMILY_INDEX);
840 if (! NILP (tmp)
841 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
842 goto err;
843 if (charset
844 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
845 goto err;
846 if (langset
847 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
848 goto err;
849 if (dpi >= 0
850 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
851 goto err;
852 if (scalable >= 0
853 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
854 goto err;
856 goto finish;
858 err:
859 /* We come here because of unexpected error in fontconfig API call
860 (usually insufficient memory). */
861 if (pattern)
863 FcPatternDestroy (pattern);
864 pattern = NULL;
866 if (*otspec)
868 if ((*otspec)->nfeatures[0] > 0)
869 free ((*otspec)->features[0]);
870 if ((*otspec)->nfeatures[1] > 0)
871 free ((*otspec)->features[1]);
872 free (*otspec);
873 *otspec = NULL;
876 finish:
877 if (langset) FcLangSetDestroy (langset);
878 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
879 return pattern;
882 static Lisp_Object
883 ftfont_list (struct frame *f, Lisp_Object spec)
885 Lisp_Object val = Qnil, family, adstyle;
886 int i;
887 FcPattern *pattern;
888 FcFontSet *fontset = NULL;
889 FcObjectSet *objset = NULL;
890 FcCharSet *charset;
891 Lisp_Object chars = Qnil;
892 char otlayout[15]; /* For "otlayout:XXXX" */
893 struct OpenTypeSpec *otspec = NULL;
894 int spacing = -1;
895 const char *langname = NULL;
897 if (! fc_initialized)
899 FcInit ();
900 fc_initialized = 1;
903 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
904 if (! pattern)
905 return Qnil;
906 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
908 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
909 if (! NILP (val))
911 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
912 if (CONSP (val) && VECTORP (XCDR (val)))
913 chars = XCDR (val);
915 val = Qnil;
917 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
918 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
919 family = AREF (spec, FONT_FAMILY_INDEX);
920 if (! NILP (family))
922 Lisp_Object resolved;
924 resolved = ftfont_resolve_generic_family (family, pattern);
925 if (! NILP (resolved))
927 FcPatternDel (pattern, FC_FAMILY);
928 if (! FcPatternAddString (pattern, FC_FAMILY,
929 SYMBOL_FcChar8 (resolved)))
930 goto err;
933 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
934 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
935 adstyle = Qnil;
936 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
937 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
938 FC_STYLE, FC_FILE, FC_INDEX,
939 #ifdef FC_CAPABILITY
940 FC_CAPABILITY,
941 #endif /* FC_CAPABILITY */
942 #ifdef FC_FONTFORMAT
943 FC_FONTFORMAT,
944 #endif
945 NULL);
946 if (! objset)
947 goto err;
948 if (! NILP (chars))
949 FcObjectSetAdd (objset, FC_CHARSET);
951 fontset = FcFontList (NULL, pattern, objset);
952 if (! fontset || fontset->nfont == 0)
953 goto finish;
954 #if 0
955 /* Need fix because this finds any fonts. */
956 if (fontset->nfont == 0 && ! NILP (family))
958 /* Try matching with configuration. For instance, the
959 configuration may specify "Nimbus Mono L" as an alias of
960 "Courier". */
961 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
962 SYMBOL_FcChar8 (family), NULL);
963 FcChar8 *fam;
965 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
967 for (i = 0;
968 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
969 i++)
971 FcPatternDel (pattern, FC_FAMILY);
972 FcPatternAddString (pattern, FC_FAMILY, fam);
973 FcFontSetDestroy (fontset);
974 fontset = FcFontList (NULL, pattern, objset);
975 if (fontset && fontset->nfont > 0)
976 break;
980 #endif
981 for (i = 0; i < fontset->nfont; i++)
983 Lisp_Object entity;
985 if (spacing >= 0)
987 int this;
989 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
990 == FcResultMatch)
991 && spacing != this)
992 continue;
995 #ifdef FC_CAPABILITY
996 if (otlayout[0])
998 FcChar8 *this;
1000 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
1001 != FcResultMatch
1002 || ! strstr ((char *) this, otlayout))
1003 continue;
1005 #endif /* FC_CAPABILITY */
1006 #ifdef HAVE_LIBOTF
1007 if (otspec)
1009 FcChar8 *file;
1010 bool passed;
1011 OTF *otf;
1013 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1014 != FcResultMatch)
1015 continue;
1016 otf = OTF_open ((char *) file);
1017 if (! otf)
1018 continue;
1019 passed = (OTF_check_features (otf, 1, otspec->script_tag,
1020 otspec->langsys_tag,
1021 otspec->features[0],
1022 otspec->nfeatures[0]) == 1
1023 && OTF_check_features (otf, 0, otspec->script_tag,
1024 otspec->langsys_tag,
1025 otspec->features[1],
1026 otspec->nfeatures[1]) == 1);
1027 OTF_close (otf);
1028 if (!passed)
1029 continue;
1031 #endif /* HAVE_LIBOTF */
1032 if (VECTORP (chars))
1034 ptrdiff_t j;
1036 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1037 != FcResultMatch)
1038 continue;
1039 for (j = 0; j < ASIZE (chars); j++)
1040 if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
1041 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1042 break;
1043 if (j == ASIZE (chars))
1044 continue;
1046 if (! NILP (adstyle) || langname)
1048 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1050 if (! NILP (adstyle)
1051 && (NILP (this_adstyle)
1052 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1053 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
1054 continue;
1055 if (langname
1056 && ! NILP (this_adstyle)
1057 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
1058 continue;
1060 entity = ftfont_pattern_entity (fontset->fonts[i],
1061 AREF (spec, FONT_EXTRA_INDEX));
1062 if (! NILP (entity))
1063 val = Fcons (entity, val);
1065 val = Fnreverse (val);
1066 goto finish;
1068 err:
1069 /* We come here because of unexpected error in fontconfig API call
1070 (usually insufficient memory). */
1071 val = Qnil;
1073 finish:
1074 FONT_ADD_LOG ("ftfont-list", spec, val);
1075 if (objset) FcObjectSetDestroy (objset);
1076 if (fontset) FcFontSetDestroy (fontset);
1077 if (pattern) FcPatternDestroy (pattern);
1078 return val;
1081 static Lisp_Object
1082 ftfont_match (struct frame *f, Lisp_Object spec)
1084 Lisp_Object entity = Qnil;
1085 FcPattern *pattern, *match = NULL;
1086 FcResult result;
1087 char otlayout[15]; /* For "otlayout:XXXX" */
1088 struct OpenTypeSpec *otspec = NULL;
1089 const char *langname = NULL;
1091 if (! fc_initialized)
1093 FcInit ();
1094 fc_initialized = 1;
1097 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1098 if (! pattern)
1099 return Qnil;
1101 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1103 FcValue value;
1105 value.type = FcTypeDouble;
1106 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1107 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1109 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1111 FcDefaultSubstitute (pattern);
1112 match = FcFontMatch (NULL, pattern, &result);
1113 if (match)
1115 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1116 FcPatternDestroy (match);
1117 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1118 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1119 ftfont_generic_family_list))
1120 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1121 AREF (entity, FONT_FAMILY_INDEX))))
1122 entity = Qnil;
1125 FcPatternDestroy (pattern);
1127 FONT_ADD_LOG ("ftfont-match", spec, entity);
1128 return entity;
1131 static Lisp_Object
1132 ftfont_list_family (struct frame *f)
1134 Lisp_Object list = Qnil;
1135 FcPattern *pattern = NULL;
1136 FcFontSet *fontset = NULL;
1137 FcObjectSet *objset = NULL;
1138 int i;
1140 if (! fc_initialized)
1142 FcInit ();
1143 fc_initialized = 1;
1146 pattern = FcPatternCreate ();
1147 if (! pattern)
1148 goto finish;
1149 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1150 if (! objset)
1151 goto finish;
1152 fontset = FcFontList (NULL, pattern, objset);
1153 if (! fontset)
1154 goto finish;
1156 for (i = 0; i < fontset->nfont; i++)
1158 FcPattern *pat = fontset->fonts[i];
1159 FcChar8 *str;
1161 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1162 list = Fcons (intern ((char *) str), list);
1165 finish:
1166 if (objset) FcObjectSetDestroy (objset);
1167 if (fontset) FcFontSetDestroy (fontset);
1168 if (pattern) FcPatternDestroy (pattern);
1170 return list;
1174 static Lisp_Object
1175 ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
1177 struct ftfont_info *ftfont_info;
1178 struct font *font;
1179 struct ftfont_cache_data *cache_data;
1180 FT_Face ft_face;
1181 FT_Size ft_size;
1182 FT_UInt size;
1183 Lisp_Object val, filename, idx, cache, font_object;
1184 bool scalable;
1185 int spacing;
1186 int i;
1187 int upEM;
1189 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1190 if (! CONSP (val))
1191 return Qnil;
1192 val = XCDR (val);
1193 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1194 if (NILP (cache))
1195 return Qnil;
1196 filename = XCAR (val);
1197 idx = XCDR (val);
1198 val = XCDR (cache);
1199 cache_data = XSAVE_POINTER (XCDR (cache), 0);
1200 ft_face = cache_data->ft_face;
1201 if (XSAVE_INTEGER (val, 1) > 0)
1203 /* FT_Face in this cache is already used by the different size. */
1204 if (FT_New_Size (ft_face, &ft_size) != 0)
1205 return Qnil;
1206 if (FT_Activate_Size (ft_size) != 0)
1208 FT_Done_Size (ft_size);
1209 return Qnil;
1212 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
1213 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1214 if (size == 0)
1215 size = pixel_size;
1216 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1218 if (XSAVE_INTEGER (val, 1) == 0)
1219 FT_Done_Face (ft_face);
1220 return Qnil;
1223 font_object = font_build_object (VECSIZE (struct ftfont_info),
1224 Qfreetype, entity, size);
1225 ASET (font_object, FONT_FILE_INDEX, filename);
1226 font = XFONT_OBJECT (font_object);
1227 ftfont_info = (struct ftfont_info *) font;
1228 ftfont_info->ft_size = ft_face->size;
1229 ftfont_info->index = XINT (idx);
1230 #ifdef HAVE_LIBOTF
1231 ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
1232 ftfont_info->otf = NULL;
1233 #endif /* HAVE_LIBOTF */
1234 /* This means that there's no need of transformation. */
1235 ftfont_info->matrix.xx = 0;
1236 font->pixel_size = size;
1237 font->driver = &ftfont_driver;
1238 font->encoding_charset = font->repertory_charset = -1;
1240 upEM = ft_face->units_per_EM;
1241 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1242 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1243 if (scalable)
1245 font->ascent = ft_face->ascender * size / upEM;
1246 font->descent = - ft_face->descender * size / upEM;
1247 font->height = ft_face->height * size / upEM;
1249 else
1251 font->ascent = ft_face->size->metrics.ascender >> 6;
1252 font->descent = - ft_face->size->metrics.descender >> 6;
1253 font->height = ft_face->size->metrics.height >> 6;
1255 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1256 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1257 else
1258 spacing = FC_PROPORTIONAL;
1259 if (spacing != FC_PROPORTIONAL
1260 #ifdef FC_DUAL
1261 && spacing != FC_DUAL
1262 #endif /* FC_DUAL */
1264 font->min_width = font->average_width = font->space_width
1265 = (scalable ? ft_face->max_advance_width * size / upEM
1266 : ft_face->size->metrics.max_advance >> 6);
1267 else
1269 int n;
1271 font->min_width = font->average_width = font->space_width = 0;
1272 for (i = 32, n = 0; i < 127; i++)
1273 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1275 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1277 if (this_width > 0
1278 && (! font->min_width || font->min_width > this_width))
1279 font->min_width = this_width;
1280 if (i == 32)
1281 font->space_width = this_width;
1282 font->average_width += this_width;
1283 n++;
1285 if (n > 0)
1286 font->average_width /= n;
1289 font->baseline_offset = 0;
1290 font->relative_compose = 0;
1291 font->default_ascent = 0;
1292 font->vertical_centering = 0;
1293 if (scalable)
1295 font->underline_position = -ft_face->underline_position * size / upEM;
1296 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1298 else
1300 font->underline_position = -1;
1301 font->underline_thickness = 0;
1304 return font_object;
1307 static void
1308 ftfont_close (struct font *font)
1310 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1311 Lisp_Object val, cache;
1313 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1314 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1315 eassert (CONSP (cache));
1316 val = XCDR (cache);
1317 set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
1318 if (XSAVE_INTEGER (val, 1) == 0)
1320 struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
1322 FT_Done_Face (cache_data->ft_face);
1323 #ifdef HAVE_LIBOTF
1324 if (ftfont_info->otf)
1325 OTF_close (ftfont_info->otf);
1326 #endif
1327 cache_data->ft_face = NULL;
1329 else
1330 FT_Done_Size (ftfont_info->ft_size);
1333 static int
1334 ftfont_has_char (Lisp_Object font, int c)
1336 struct charset *cs = NULL;
1338 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1339 && charset_jisx0208 >= 0)
1340 cs = CHARSET_FROM_ID (charset_jisx0208);
1341 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1342 && charset_ksc5601 >= 0)
1343 cs = CHARSET_FROM_ID (charset_ksc5601);
1344 if (cs)
1345 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1347 if (FONT_ENTITY_P (font))
1349 FcCharSet *charset = ftfont_get_fc_charset (font);
1351 return (FcCharSetHasChar (charset, c) == FcTrue);
1353 else
1355 struct ftfont_info *ftfont_info;
1357 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1358 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1359 != 0);
1363 static unsigned
1364 ftfont_encode_char (struct font *font, int c)
1366 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1367 FT_Face ft_face = ftfont_info->ft_size->face;
1368 FT_ULong charcode = c;
1369 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1371 return (code > 0 ? code : FONT_INVALID_CODE);
1374 static void
1375 ftfont_text_extents (struct font *font, unsigned int *code,
1376 int nglyphs, struct font_metrics *metrics)
1378 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1379 FT_Face ft_face = ftfont_info->ft_size->face;
1380 int i, width = 0;
1381 bool first;
1383 if (ftfont_info->ft_size != ft_face->size)
1384 FT_Activate_Size (ftfont_info->ft_size);
1386 for (i = 0, first = 1; i < nglyphs; i++)
1388 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1390 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1392 if (first)
1394 metrics->lbearing = m->horiBearingX >> 6;
1395 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1396 metrics->ascent = m->horiBearingY >> 6;
1397 metrics->descent = (m->height - m->horiBearingY) >> 6;
1398 first = 0;
1400 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1401 metrics->lbearing = width + (m->horiBearingX >> 6);
1402 if (metrics->rbearing
1403 < width + ((m->horiBearingX + m->width) >> 6))
1404 metrics->rbearing
1405 = width + ((m->horiBearingX + m->width) >> 6);
1406 if (metrics->ascent < (m->horiBearingY >> 6))
1407 metrics->ascent = m->horiBearingY >> 6;
1408 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1409 metrics->descent = (m->height - m->horiBearingY) >> 6;
1410 width += m->horiAdvance >> 6;
1412 else
1413 width += font->space_width;
1415 metrics->width = width;
1418 static int
1419 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1421 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1422 FT_Face ft_face = ftfont_info->ft_size->face;
1423 FT_Int32 load_flags = FT_LOAD_RENDER;
1425 if (ftfont_info->ft_size != ft_face->size)
1426 FT_Activate_Size (ftfont_info->ft_size);
1427 if (bits_per_pixel == 1)
1429 #ifdef FT_LOAD_TARGET_MONO
1430 load_flags |= FT_LOAD_TARGET_MONO;
1431 #else
1432 load_flags |= FT_LOAD_MONOCHROME;
1433 #endif
1435 else if (bits_per_pixel != 8)
1436 /* We don't support such a rendering. */
1437 return -1;
1439 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1440 return -1;
1441 bitmap->bits_per_pixel
1442 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1443 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1444 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1445 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1446 : -1);
1447 if (bitmap->bits_per_pixel < 0)
1448 /* We don't support that kind of pixel mode. */
1449 return -1;
1450 bitmap->rows = ft_face->glyph->bitmap.rows;
1451 bitmap->width = ft_face->glyph->bitmap.width;
1452 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1453 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1454 bitmap->left = ft_face->glyph->bitmap_left;
1455 bitmap->top = ft_face->glyph->bitmap_top;
1456 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1458 return 0;
1461 static int
1462 ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1463 int *x, int *y)
1465 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1466 FT_Face ft_face = ftfont_info->ft_size->face;
1468 if (ftfont_info->ft_size != ft_face->size)
1469 FT_Activate_Size (ftfont_info->ft_size);
1470 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1471 return -1;
1472 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1473 return -1;
1474 if (idx >= ft_face->glyph->outline.n_points)
1475 return -1;
1476 *x = ft_face->glyph->outline.points[idx].x;
1477 *y = ft_face->glyph->outline.points[idx].y;
1478 return 0;
1481 #ifdef HAVE_LIBOTF
1483 static Lisp_Object
1484 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1486 Lisp_Object scripts, langsyses, features, sym;
1487 int i, j, k, l;
1489 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1491 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1493 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1495 OTF_LangSys *otf_langsys;
1497 if (j >= 0)
1498 otf_langsys = otf_script->LangSys + j;
1499 else if (otf_script->DefaultLangSysOffset)
1500 otf_langsys = &otf_script->DefaultLangSys;
1501 else
1502 break;
1504 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1506 l = otf_langsys->FeatureIndex[k];
1507 if (l >= gsub_gpos->FeatureList.FeatureCount)
1508 continue;
1509 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1510 features = Fcons (sym, features);
1512 if (j >= 0)
1513 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1514 else
1515 sym = Qnil;
1516 langsyses = Fcons (Fcons (sym, features), langsyses);
1519 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1520 scripts = Fcons (Fcons (sym, langsyses), scripts);
1522 return scripts;
1527 static Lisp_Object
1528 ftfont_otf_capability (struct font *font)
1530 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1531 OTF *otf = ftfont_get_otf (ftfont_info);
1532 Lisp_Object gsub_gpos;
1534 if (! otf)
1535 return Qnil;
1536 gsub_gpos = Fcons (Qnil, Qnil);
1537 if (OTF_get_table (otf, "GSUB") == 0
1538 && otf->gsub->FeatureList.FeatureCount > 0)
1539 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1540 if (OTF_get_table (otf, "GPOS") == 0
1541 && otf->gpos->FeatureList.FeatureCount > 0)
1542 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1543 return gsub_gpos;
1546 #ifdef HAVE_M17N_FLT
1548 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1549 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1550 /* We can use the new feature of libotf and m17n-flt to handle the
1551 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1552 some Agian scripts. */
1553 #define M17N_FLT_USE_NEW_FEATURE
1554 #endif
1556 struct MFLTFontFT
1558 MFLTFont flt_font;
1559 struct font *font;
1560 FT_Face ft_face;
1561 OTF *otf;
1562 FT_Matrix *matrix;
1565 static int
1566 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1567 int from, int to)
1569 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1570 FT_Face ft_face = flt_font_ft->ft_face;
1571 MFLTGlyph *g;
1573 for (g = gstring->glyphs + from; from < to; g++, from++)
1574 if (! g->encoded)
1576 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1578 g->code = code > 0 ? code : FONT_INVALID_CODE;
1579 g->encoded = 1;
1581 return 0;
1584 /* Operators for 26.6 fixed fractional pixel format */
1586 #define FLOOR(x) ((x) & -64)
1587 #define CEIL(x) (((x)+63) & -64)
1588 #define ROUND(x) (((x)+32) & -64)
1590 static int
1591 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1592 int from, int to)
1594 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1595 FT_Face ft_face = flt_font_ft->ft_face;
1596 MFLTGlyph *g;
1598 for (g = gstring->glyphs + from; from < to; g++, from++)
1599 if (! g->measured)
1601 if (g->code != FONT_INVALID_CODE)
1603 FT_Glyph_Metrics *m;
1605 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1606 emacs_abort ();
1607 m = &ft_face->glyph->metrics;
1608 if (flt_font_ft->matrix)
1610 FT_Vector v[4];
1611 int i;
1613 v[0].x = v[1].x = m->horiBearingX;
1614 v[2].x = v[3].x = m->horiBearingX + m->width;
1615 v[0].y = v[2].y = m->horiBearingY;
1616 v[1].y = v[3].y = m->horiBearingY - m->height;
1617 for (i = 0; i < 4; i++)
1618 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1619 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1620 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1621 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1622 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1624 else
1626 g->lbearing = FLOOR (m->horiBearingX);
1627 g->rbearing = CEIL (m->horiBearingX + m->width);
1628 g->ascent = CEIL (m->horiBearingY);
1629 g->descent = - FLOOR (m->horiBearingY - m->height);
1631 g->xadv = ROUND (ft_face->glyph->advance.x);
1633 else
1635 g->lbearing = 0;
1636 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1637 g->ascent = flt_font_ft->font->ascent << 6;
1638 g->descent = flt_font_ft->font->descent << 6;
1640 g->yadv = 0;
1641 g->measured = 1;
1643 return 0;
1646 static int
1647 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1649 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1651 #define FEATURE_ANY(IDX) \
1652 (spec->features[IDX] \
1653 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1655 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1656 OTF *otf = flt_font_ft->otf;
1657 OTF_Tag *tags;
1658 int i, n;
1659 bool negative;
1661 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1662 /* Return true iff any of GSUB or GPOS support the script (and
1663 language). */
1664 return (otf
1665 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1666 NULL, 0) > 0
1667 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1668 NULL, 0) > 0));
1670 for (i = 0; i < 2; i++)
1671 if (! FEATURE_ANY (i))
1673 if (FEATURE_NONE (i))
1675 if (otf
1676 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1677 NULL, 0) > 0)
1678 return 0;
1679 continue;
1681 if (spec->features[i][0] == 0xFFFFFFFF)
1683 if (! otf
1684 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1685 NULL, 0) <= 0)
1686 continue;
1688 else if (! otf)
1689 return 0;
1690 for (n = 1; spec->features[i][n]; n++);
1691 tags = alloca (sizeof (OTF_Tag) * n);
1692 for (n = 0, negative = 0; spec->features[i][n]; n++)
1694 if (spec->features[i][n] == 0xFFFFFFFF)
1695 negative = 1;
1696 else if (negative)
1697 tags[n - 1] = spec->features[i][n] | 0x80000000;
1698 else
1699 tags[n] = spec->features[i][n];
1701 #ifdef M17N_FLT_USE_NEW_FEATURE
1702 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1703 tags, n - negative) != 1)
1704 return 0;
1705 #else /* not M17N_FLT_USE_NEW_FEATURE */
1706 if (n - negative > 0
1707 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1708 tags, n - negative) != 1)
1709 return 0;
1710 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1712 return 1;
1713 #undef FEATURE_NONE
1714 #undef FEATURE_ANY
1717 #define DEVICE_DELTA(table, size) \
1718 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1719 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1720 : 0)
1722 static void
1723 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1724 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1726 if (anchor->AnchorFormat == 2)
1728 FT_Outline *outline;
1729 int ap = anchor->f.f1.AnchorPoint;
1731 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1732 outline = &ft_face->glyph->outline;
1733 if (ap < outline->n_points)
1735 *x = outline->points[ap].x << 6;
1736 *y = outline->points[ap].y << 6;
1739 else if (anchor->AnchorFormat == 3)
1741 if (anchor->f.f2.XDeviceTable.offset
1742 && anchor->f.f2.XDeviceTable.DeltaValue)
1743 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1744 if (anchor->f.f2.YDeviceTable.offset
1745 && anchor->f.f2.YDeviceTable.DeltaValue)
1746 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1750 static OTF_GlyphString otf_gstring;
1752 static void
1753 setup_otf_gstring (int size)
1755 if (otf_gstring.size < size)
1757 otf_gstring.glyphs = xnrealloc (otf_gstring.glyphs,
1758 size, sizeof (OTF_Glyph));
1759 otf_gstring.size = size;
1761 otf_gstring.used = size;
1762 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1765 #ifdef M17N_FLT_USE_NEW_FEATURE
1767 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1768 #define PACK_OTF_TAG(TAG) \
1769 ((((TAG) & 0x7F000000) >> 3) \
1770 | (((TAG) & 0x7F0000) >> 2) \
1771 | (((TAG) & 0x7F00) >> 1) \
1772 | ((TAG) & 0x7F))
1774 /* Assuming that FONT is an OpenType font, apply OpenType features
1775 specified in SPEC on glyphs between FROM and TO of IN, and record
1776 the lastly applied feature in each glyph of IN. If OUT is not
1777 NULL, append the resulting glyphs to OUT while storing glyph
1778 position adjustment information in ADJUSTMENT. */
1780 static int
1781 ftfont_drive_otf (MFLTFont *font,
1782 MFLTOtfSpec *spec,
1783 MFLTGlyphString *in,
1784 int from,
1785 int to,
1786 MFLTGlyphString *out,
1787 MFLTGlyphAdjustment *adjustment)
1789 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1790 FT_Face ft_face = flt_font_ft->ft_face;
1791 OTF *otf = flt_font_ft->otf;
1792 int len = to - from;
1793 int i, j, gidx;
1794 OTF_Glyph *otfg;
1795 char script[5], *langsys = NULL;
1796 char *gsub_features = NULL, *gpos_features = NULL;
1797 OTF_Feature *features;
1799 if (len == 0)
1800 return from;
1801 OTF_tag_name (spec->script, script);
1802 if (spec->langsys)
1804 langsys = alloca (5);
1805 OTF_tag_name (spec->langsys, langsys);
1807 for (i = 0; i < 2; i++)
1809 char *p;
1811 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1813 for (j = 0; spec->features[i][j]; j++);
1814 if (i == 0)
1815 p = gsub_features = alloca (6 * j);
1816 else
1817 p = gpos_features = alloca (6 * j);
1818 for (j = 0; spec->features[i][j]; j++)
1820 if (spec->features[i][j] == 0xFFFFFFFF)
1821 *p++ = '*', *p++ = ',';
1822 else
1824 OTF_tag_name (spec->features[i][j], p);
1825 p[4] = ',';
1826 p += 5;
1829 *--p = '\0';
1833 setup_otf_gstring (len);
1834 for (i = 0; i < len; i++)
1836 otf_gstring.glyphs[i].c = in->glyphs[from + i].c & 0x11FFFF;
1837 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1840 OTF_drive_gdef (otf, &otf_gstring);
1841 gidx = out ? out->used : from;
1843 if (gsub_features && out)
1845 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1846 gsub_features) < 0)
1847 goto simple_copy;
1848 if (out->allocated < out->used + otf_gstring.used)
1849 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)
1938 return -2;
1939 for (i = 0; i < len; i++)
1940 out->glyphs[out->used++] = in->glyphs[from + i];
1943 if (gpos_features && out)
1945 MFLTGlyph *base = NULL, *mark = NULL, *g;
1946 int x_ppem, y_ppem, x_scale, y_scale;
1948 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1949 gpos_features) < 0)
1950 return to;
1951 features = otf->gpos->FeatureList.Feature;
1952 x_ppem = ft_face->size->metrics.x_ppem;
1953 y_ppem = ft_face->size->metrics.y_ppem;
1954 x_scale = ft_face->size->metrics.x_scale;
1955 y_scale = ft_face->size->metrics.y_scale;
1957 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1958 i < otf_gstring.used; i++, otfg++, g++)
1960 MFLTGlyph *prev;
1961 int feature_idx = otfg->positioning_type >> 4;
1963 if (feature_idx)
1965 unsigned int tag = features[feature_idx - 1].FeatureTag;
1966 tag = PACK_OTF_TAG (tag);
1967 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1970 if (! otfg->glyph_id)
1971 continue;
1972 switch (otfg->positioning_type & 0xF)
1974 case 0:
1975 break;
1976 case 1: /* Single */
1977 case 2: /* Pair */
1979 int format = otfg->f.f1.format;
1981 if (format & OTF_XPlacement)
1982 adjustment[i].xoff
1983 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
1984 if (format & OTF_XPlaDevice)
1985 adjustment[i].xoff
1986 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
1987 if (format & OTF_YPlacement)
1988 adjustment[i].yoff
1989 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
1990 if (format & OTF_YPlaDevice)
1991 adjustment[i].yoff
1992 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
1993 if (format & OTF_XAdvance)
1994 adjustment[i].xadv
1995 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
1996 if (format & OTF_XAdvDevice)
1997 adjustment[i].xadv
1998 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
1999 if (format & OTF_YAdvance)
2000 adjustment[i].yadv
2001 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2002 if (format & OTF_YAdvDevice)
2003 adjustment[i].yadv
2004 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2005 adjustment[i].set = 1;
2007 break;
2008 case 3: /* Cursive */
2009 /* Not yet supported. */
2010 break;
2011 case 4: /* Mark-to-Base */
2012 case 5: /* Mark-to-Ligature */
2013 if (! base)
2014 break;
2015 prev = base;
2016 goto label_adjust_anchor;
2017 default: /* i.e. case 6 Mark-to-Mark */
2018 if (! mark)
2019 break;
2020 prev = mark;
2022 label_adjust_anchor:
2024 int base_x, base_y, mark_x, mark_y;
2025 int this_from, this_to;
2027 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2028 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2029 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2030 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2032 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2033 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2034 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2035 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2036 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2037 x_ppem, y_ppem, &mark_x, &mark_y);
2038 adjustment[i].xoff = (base_x - mark_x);
2039 adjustment[i].yoff = - (base_y - mark_y);
2040 adjustment[i].back = (g - prev);
2041 adjustment[i].xadv = 0;
2042 adjustment[i].advance_is_absolute = 1;
2043 adjustment[i].set = 1;
2044 this_from = g->from;
2045 this_to = g->to;
2046 for (j = 0; prev + j < g; j++)
2048 if (this_from > prev[j].from)
2049 this_from = prev[j].from;
2050 if (this_to < prev[j].to)
2051 this_to = prev[j].to;
2053 for (; prev <= g; prev++)
2055 prev->from = this_from;
2056 prev->to = this_to;
2060 if (otfg->GlyphClass == OTF_GlyphClass0)
2061 base = mark = g;
2062 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2063 mark = g;
2064 else
2065 base = g;
2068 else if (gpos_features)
2070 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2071 gpos_features) < 0)
2072 return to;
2073 features = otf->gpos->FeatureList.Feature;
2074 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2075 i++, otfg++)
2076 if (otfg->positioning_type & 0xF)
2078 int feature_idx = otfg->positioning_type >> 4;
2080 if (feature_idx)
2082 unsigned int tag = features[feature_idx - 1].FeatureTag;
2083 tag = PACK_OTF_TAG (tag);
2084 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2086 MFLTGlyph *g = in->glyphs + (from + j);
2087 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2092 return to;
2094 simple_copy:
2095 if (! out)
2096 return to;
2097 if (out->allocated < out->used + len)
2098 return -2;
2099 font->get_metrics (font, in, from, to);
2100 memcpy (out->glyphs + out->used, in->glyphs + from,
2101 sizeof (MFLTGlyph) * len);
2102 out->used += len;
2103 return to;
2106 static int
2107 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2108 MFLTGlyphString *in, int from, int to)
2110 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2113 #else /* not M17N_FLT_USE_NEW_FEATURE */
2115 static int
2116 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2117 int from, int to,
2118 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2120 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2121 FT_Face ft_face = flt_font_ft->ft_face;
2122 OTF *otf = flt_font_ft->otf;
2123 int len = to - from;
2124 int i, j, gidx;
2125 OTF_Glyph *otfg;
2126 char script[5], *langsys = NULL;
2127 char *gsub_features = NULL, *gpos_features = NULL;
2129 if (len == 0)
2130 return from;
2131 OTF_tag_name (spec->script, script);
2132 if (spec->langsys)
2134 langsys = alloca (5);
2135 OTF_tag_name (spec->langsys, langsys);
2137 for (i = 0; i < 2; i++)
2139 char *p;
2141 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2143 for (j = 0; spec->features[i][j]; j++);
2144 if (i == 0)
2145 p = gsub_features = alloca (6 * j);
2146 else
2147 p = gpos_features = alloca (6 * j);
2148 for (j = 0; spec->features[i][j]; j++)
2150 if (spec->features[i][j] == 0xFFFFFFFF)
2151 *p++ = '*', *p++ = ',';
2152 else
2154 OTF_tag_name (spec->features[i][j], p);
2155 p[4] = ',';
2156 p += 5;
2159 *--p = '\0';
2163 setup_otf_gstring (len);
2164 for (i = 0; i < len; i++)
2166 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2167 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2170 OTF_drive_gdef (otf, &otf_gstring);
2171 gidx = out->used;
2173 if (gsub_features)
2175 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2176 < 0)
2177 goto simple_copy;
2178 if (out->allocated < out->used + otf_gstring.used)
2179 return -2;
2180 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2182 MFLTGlyph *g;
2183 int min_from, max_to;
2184 int j;
2186 g = out->glyphs + out->used;
2187 *g = in->glyphs[from + otfg->f.index.from];
2188 if (g->code != otfg->glyph_id)
2190 g->c = 0;
2191 g->code = otfg->glyph_id;
2192 g->measured = 0;
2194 out->used++;
2195 min_from = g->from;
2196 max_to = g->to;
2197 if (otfg->f.index.from < otfg->f.index.to)
2199 /* OTFG substitutes multiple glyphs in IN. */
2200 for (j = from + otfg->f.index.from + 1;
2201 j <= from + otfg->f.index.to; j++)
2203 if (min_from > in->glyphs[j].from)
2204 min_from = in->glyphs[j].from;
2205 if (max_to < in->glyphs[j].to)
2206 max_to = in->glyphs[j].to;
2208 g->from = min_from;
2209 g->to = max_to;
2211 for (i++, otfg++; (i < otf_gstring.used
2212 && otfg->f.index.from == otfg[-1].f.index.from);
2213 i++, otfg++)
2215 g = out->glyphs + out->used;
2216 *g = in->glyphs[from + otfg->f.index.to];
2217 if (g->code != otfg->glyph_id)
2219 g->c = 0;
2220 g->code = otfg->glyph_id;
2221 g->measured = 0;
2223 out->used++;
2227 else
2229 if (out->allocated < out->used + len)
2230 return -2;
2231 for (i = 0; i < len; i++)
2232 out->glyphs[out->used++] = in->glyphs[from + i];
2235 if (gpos_features)
2237 MFLTGlyph *base = NULL, *mark = NULL, *g;
2238 int x_ppem, y_ppem, x_scale, y_scale;
2240 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2241 < 0)
2242 return to;
2244 x_ppem = ft_face->size->metrics.x_ppem;
2245 y_ppem = ft_face->size->metrics.y_ppem;
2246 x_scale = ft_face->size->metrics.x_scale;
2247 y_scale = ft_face->size->metrics.y_scale;
2249 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2250 i < otf_gstring.used; i++, otfg++, g++)
2252 MFLTGlyph *prev;
2254 if (! otfg->glyph_id)
2255 continue;
2256 switch (otfg->positioning_type)
2258 case 0:
2259 break;
2260 case 1: /* Single */
2261 case 2: /* Pair */
2263 int format = otfg->f.f1.format;
2265 if (format & OTF_XPlacement)
2266 adjustment[i].xoff
2267 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2268 if (format & OTF_XPlaDevice)
2269 adjustment[i].xoff
2270 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2271 if (format & OTF_YPlacement)
2272 adjustment[i].yoff
2273 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2274 if (format & OTF_YPlaDevice)
2275 adjustment[i].yoff
2276 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2277 if (format & OTF_XAdvance)
2278 adjustment[i].xadv
2279 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2280 if (format & OTF_XAdvDevice)
2281 adjustment[i].xadv
2282 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2283 if (format & OTF_YAdvance)
2284 adjustment[i].yadv
2285 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2286 if (format & OTF_YAdvDevice)
2287 adjustment[i].yadv
2288 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2289 adjustment[i].set = 1;
2291 break;
2292 case 3: /* Cursive */
2293 /* Not yet supported. */
2294 break;
2295 case 4: /* Mark-to-Base */
2296 case 5: /* Mark-to-Ligature */
2297 if (! base)
2298 break;
2299 prev = base;
2300 goto label_adjust_anchor;
2301 default: /* i.e. case 6 Mark-to-Mark */
2302 if (! mark)
2303 break;
2304 prev = mark;
2306 label_adjust_anchor:
2308 int base_x, base_y, mark_x, mark_y;
2309 int this_from, this_to;
2311 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2312 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2313 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2314 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2316 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2317 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2318 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2319 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2320 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2321 x_ppem, y_ppem, &mark_x, &mark_y);
2322 adjustment[i].xoff = (base_x - mark_x);
2323 adjustment[i].yoff = - (base_y - mark_y);
2324 adjustment[i].back = (g - prev);
2325 adjustment[i].xadv = 0;
2326 adjustment[i].advance_is_absolute = 1;
2327 adjustment[i].set = 1;
2328 this_from = g->from;
2329 this_to = g->to;
2330 for (j = 0; prev + j < g; j++)
2332 if (this_from > prev[j].from)
2333 this_from = prev[j].from;
2334 if (this_to < prev[j].to)
2335 this_to = prev[j].to;
2337 for (; prev <= g; prev++)
2339 prev->from = this_from;
2340 prev->to = this_to;
2344 if (otfg->GlyphClass == OTF_GlyphClass0)
2345 base = mark = g;
2346 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2347 mark = g;
2348 else
2349 base = g;
2352 return to;
2354 simple_copy:
2355 if (out->allocated < out->used + len)
2356 return -2;
2357 font->get_metrics (font, in, from, to);
2358 memcpy (out->glyphs + out->used, in->glyphs + from,
2359 sizeof (MFLTGlyph) * len);
2360 out->used += len;
2361 return to;
2364 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2366 static MFLTGlyphString gstring;
2368 static bool m17n_flt_initialized;
2370 static Lisp_Object
2371 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2372 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2374 ptrdiff_t len = LGSTRING_GLYPH_LEN (lgstring);
2375 ptrdiff_t i;
2376 struct MFLTFontFT flt_font_ft;
2377 MFLT *flt = NULL;
2378 bool with_variation_selector = 0;
2380 if (! m17n_flt_initialized)
2382 M17N_INIT ();
2383 #ifdef M17N_FLT_USE_NEW_FEATURE
2384 mflt_enable_new_feature = 1;
2385 mflt_try_otf = ftfont_try_otf;
2386 #endif /* M17N_FLT_USE_NEW_FEATURE */
2387 m17n_flt_initialized = 1;
2390 for (i = 0; i < len; i++)
2392 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2393 int c;
2395 if (NILP (g))
2396 break;
2397 c = LGLYPH_CHAR (g);
2398 if (CHAR_VARIATION_SELECTOR_P (c))
2399 with_variation_selector = 1;
2402 len = i;
2404 if (with_variation_selector)
2406 setup_otf_gstring (len);
2407 for (i = 0; i < len; i++)
2409 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2411 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2412 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2413 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2415 OTF_drive_cmap (otf, &otf_gstring);
2416 for (i = 0; i < otf_gstring.used; i++)
2418 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2419 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2420 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2422 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2423 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2424 LGSTRING_SET_GLYPH (lgstring, i, g0);
2426 if (len > otf_gstring.used)
2428 len = otf_gstring.used;
2429 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2433 if (INT_MAX / 2 < len)
2434 memory_full (SIZE_MAX);
2436 if (gstring.allocated == 0)
2438 gstring.glyph_size = sizeof (MFLTGlyph);
2439 gstring.glyphs = xnmalloc (len * 2, sizeof *gstring.glyphs);
2440 gstring.allocated = len * 2;
2442 else if (gstring.allocated < len * 2)
2444 gstring.glyphs = xnrealloc (gstring.glyphs, len * 2,
2445 sizeof *gstring.glyphs);
2446 gstring.allocated = len * 2;
2448 memset (gstring.glyphs, 0, len * sizeof *gstring.glyphs);
2449 for (i = 0; i < len; i++)
2451 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2453 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2454 if (with_variation_selector)
2456 gstring.glyphs[i].code = LGLYPH_CODE (g);
2457 gstring.glyphs[i].encoded = 1;
2461 gstring.used = len;
2462 gstring.r2l = 0;
2465 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2467 if (NILP (family))
2468 flt_font_ft.flt_font.family = Mnil;
2469 else
2470 flt_font_ft.flt_font.family
2471 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
2473 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2474 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2475 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2476 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2477 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2478 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2479 flt_font_ft.flt_font.internal = NULL;
2480 flt_font_ft.font = font;
2481 flt_font_ft.ft_face = ft_face;
2482 flt_font_ft.otf = otf;
2483 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2484 if (len > 1
2485 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2486 /* A little bit ad hoc. Perhaps, shaper must get script and
2487 language information, and select a proper flt for them
2488 here. */
2489 flt = mflt_get (msymbol ("combining"));
2490 for (i = 0; i < 3; i++)
2492 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2493 if (result != -2)
2494 break;
2495 if (INT_MAX / 2 < gstring.allocated)
2496 memory_full (SIZE_MAX);
2497 gstring.glyphs = xnrealloc (gstring.glyphs,
2498 gstring.allocated, 2 * sizeof (MFLTGlyph));
2499 gstring.allocated *= 2;
2501 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2502 return Qnil;
2503 for (i = 0; i < gstring.used; i++)
2505 MFLTGlyph *g = gstring.glyphs + i;
2507 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2508 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2511 for (i = 0; i < gstring.used; i++)
2513 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2514 MFLTGlyph *g = gstring.glyphs + i;
2516 if (NILP (lglyph))
2518 lglyph = LGLYPH_NEW ();
2519 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2521 LGLYPH_SET_FROM (lglyph, g->from);
2522 LGLYPH_SET_TO (lglyph, g->to);
2523 LGLYPH_SET_CHAR (lglyph, g->c);
2524 LGLYPH_SET_CODE (lglyph, g->code);
2525 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2526 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2527 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2528 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2529 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2530 if (g->adjusted)
2532 Lisp_Object vec = make_uninit_vector (3);
2534 ASET (vec, 0, make_number (g->xoff >> 6));
2535 ASET (vec, 1, make_number (g->yoff >> 6));
2536 ASET (vec, 2, make_number (g->xadv >> 6));
2537 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2540 return make_number (i);
2543 Lisp_Object
2544 ftfont_shape (Lisp_Object lgstring)
2546 struct font *font;
2547 struct ftfont_info *ftfont_info;
2548 OTF *otf;
2550 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2551 ftfont_info = (struct ftfont_info *) font;
2552 otf = ftfont_get_otf (ftfont_info);
2553 if (! otf)
2554 return make_number (0);
2555 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2556 &ftfont_info->matrix);
2559 #endif /* HAVE_M17N_FLT */
2561 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2563 static int
2564 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2566 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2567 OTF *otf = ftfont_get_otf (ftfont_info);
2569 if (! otf)
2570 return 0;
2571 return OTF_get_variation_glyphs (otf, c, variations);
2574 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2575 #endif /* HAVE_LIBOTF */
2577 static const char *const ftfont_booleans [] = {
2578 ":antialias",
2579 ":hinting",
2580 ":verticallayout",
2581 ":autohint",
2582 ":globaladvance",
2583 ":outline",
2584 ":scalable",
2585 ":minspace",
2586 ":embolden",
2587 NULL,
2590 static const char *const ftfont_non_booleans [] = {
2591 ":family",
2592 ":familylang",
2593 ":style",
2594 ":stylelang",
2595 ":fullname",
2596 ":fullnamelang",
2597 ":slant",
2598 ":weight",
2599 ":size",
2600 ":width",
2601 ":aspect",
2602 ":pixelsize",
2603 ":spacing",
2604 ":foundry",
2605 ":hintstyle",
2606 ":file",
2607 ":index",
2608 ":ftface",
2609 ":rasterizer",
2610 ":scale",
2611 ":dpi",
2612 ":rgba",
2613 ":lcdfilter",
2614 ":charset",
2615 ":lang",
2616 ":fontversion",
2617 ":capability",
2618 NULL,
2621 static void
2622 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2624 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
2628 void
2629 syms_of_ftfont (void)
2631 DEFSYM (Qfreetype, "freetype");
2632 DEFSYM (Qmonospace, "monospace");
2633 DEFSYM (Qsans_serif, "sans-serif");
2634 DEFSYM (Qserif, "serif");
2635 DEFSYM (Qmono, "mono");
2636 DEFSYM (Qsans, "sans");
2637 DEFSYM (Qsans__serif, "sans serif");
2639 staticpro (&freetype_font_cache);
2640 freetype_font_cache = list1 (Qt);
2642 staticpro (&ftfont_generic_family_list);
2643 ftfont_generic_family_list = list3 (Fcons (Qmonospace, Qt),
2644 Fcons (Qsans_serif, Qt),
2645 Fcons (Qsans, Qt));
2647 staticpro (&ft_face_cache);
2648 ft_face_cache = Qnil;
2650 ftfont_driver.type = Qfreetype;
2651 register_font_driver (&ftfont_driver, NULL);