src/gtkutil.c (xg_update_scrollbar_pos): Avoid C99 mid-block variable declaration.
[emacs.git] / src / ftfont.c
blob9699dc580090d0a77feded7b76faebd29b2cd4cf
1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
3 Copyright (C) 2006, 2007, 2008, 2009, 2010
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 <setjmp.h>
26 #include <fontconfig/fontconfig.h>
27 #include <fontconfig/fcfreetype.h>
29 #include "lisp.h"
30 #include "dispextern.h"
31 #include "frame.h"
32 #include "blockinput.h"
33 #include "character.h"
34 #include "charset.h"
35 #include "coding.h"
36 #include "composite.h"
37 #include "fontset.h"
38 #include "font.h"
39 #include "ftfont.h"
41 /* Symbolic type of this font-driver. */
42 Lisp_Object Qfreetype;
44 /* Fontconfig's generic families and their aliases. */
45 static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
47 /* Flag to tell if FcInit is already called or not. */
48 static int fc_initialized;
50 /* Handle to a FreeType library instance. */
51 static FT_Library ft_library;
53 /* Cache for FreeType fonts. */
54 static Lisp_Object freetype_font_cache;
56 /* Cache for FT_Face and FcCharSet. */
57 static Lisp_Object ft_face_cache;
59 /* The actual structure for FreeType font that can be casted to struct
60 font. */
62 struct ftfont_info
64 struct font font;
65 #ifdef HAVE_LIBOTF
66 /* The following four members must be here in this order to be
67 compatible with struct xftfont_info (in xftfont.c). */
68 int maybe_otf; /* Flag to tell if this may be OTF or not. */
69 OTF *otf;
70 #endif /* HAVE_LIBOTF */
71 FT_Size ft_size;
72 int index;
73 FT_Matrix matrix;
76 enum ftfont_cache_for
78 FTFONT_CACHE_FOR_FACE,
79 FTFONT_CACHE_FOR_CHARSET,
80 FTFONT_CACHE_FOR_ENTITY
83 static Lisp_Object ftfont_pattern_entity P_ ((FcPattern *, Lisp_Object));
85 static Lisp_Object ftfont_resolve_generic_family P_ ((Lisp_Object,
86 FcPattern *));
87 static Lisp_Object ftfont_lookup_cache P_ ((Lisp_Object,
88 enum ftfont_cache_for));
90 static void ftfont_filter_properties P_ ((Lisp_Object font, Lisp_Object alist));
92 Lisp_Object ftfont_font_format P_ ((FcPattern *, Lisp_Object));
94 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
96 static struct
98 /* registry name */
99 char *name;
100 /* characters to distinguish the charset from the others */
101 int uniquifier[6];
102 /* additional constraint by language */
103 char *lang;
104 /* set on demand */
105 FcCharSet *fc_charset;
106 } fc_charset_table[] =
107 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
108 { "iso8859-2", { 0x00A0, 0x010E }},
109 { "iso8859-3", { 0x00A0, 0x0108 }},
110 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
111 { "iso8859-5", { 0x00A0, 0x0401 }},
112 { "iso8859-6", { 0x00A0, 0x060C }},
113 { "iso8859-7", { 0x00A0, 0x0384 }},
114 { "iso8859-8", { 0x00A0, 0x05D0 }},
115 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
116 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
117 { "iso8859-11", { 0x00A0, 0x0E01 }},
118 { "iso8859-13", { 0x00A0, 0x201C }},
119 { "iso8859-14", { 0x00A0, 0x0174 }},
120 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
121 { "iso8859-16", { 0x00A0, 0x0218}},
122 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
123 { "big5-0", { 0xF6B1 }, "zh-tw" },
124 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
125 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
126 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
127 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
128 { "cns11643.1992-3", { 0x201A9 }},
129 { "cns11643.1992-4", { 0x20057 }},
130 { "cns11643.1992-5", { 0x20000 }},
131 { "cns11643.1992-6", { 0x20003 }},
132 { "cns11643.1992-7", { 0x20055 }},
133 { "gbk-0", { 0x4E06 }, "zh-cn"},
134 { "jisx0212.1990-0", { 0x4E44 }},
135 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
136 { "jisx0213.2000-2", { 0xFA49 }},
137 { "jisx0213.2004-1", { 0x20B9F }},
138 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
139 { "tis620.2529-1", { 0x0E01 }, "th"},
140 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
141 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
142 { "mulelao-1", { 0x0E81 }, "lo"},
143 { "unicode-sip", { 0x20000 }},
144 { NULL }
147 extern Lisp_Object Qc, Qm, Qp, Qd;
149 /* Dirty hack for handing ADSTYLE property.
151 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
152 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
153 "Oblique", "Italic", or any non-normal SWIDTH property names
154 (e.g. SemiCondensed) are appended. In addition, if there's no
155 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
156 "Regular" is used for FC_STYLE (see the function
157 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
159 Unfortunately this behavior is not documented, so the following
160 code may fail if FreeType changes the behavior in the future. */
162 static Lisp_Object
163 get_adstyle_property (FcPattern *p)
165 char *str, *end;
166 Lisp_Object adstyle;
168 if (FcPatternGetString (p, FC_STYLE, 0, (FcChar8 **) &str) != FcResultMatch)
169 return Qnil;
170 for (end = str; *end && *end != ' '; end++);
171 if (*end)
173 char *p = alloca (end - str + 1);
174 memcpy (p, str, end - str);
175 p[end - str] = '\0';
176 end = p + (end - str);
177 str = p;
179 if (xstrcasecmp (str, "Regular") == 0
180 || xstrcasecmp (str, "Bold") == 0
181 || xstrcasecmp (str, "Oblique") == 0
182 || xstrcasecmp (str, "Italic") == 0)
183 return Qnil;
184 adstyle = font_intern_prop (str, end - str, 1);
185 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
186 return Qnil;
187 return adstyle;
190 static Lisp_Object
191 ftfont_pattern_entity (p, extra)
192 FcPattern *p;
193 Lisp_Object extra;
195 Lisp_Object key, cache, entity;
196 char *file, *str;
197 int index;
198 int numeric;
199 double dbl;
200 FcBool b;
202 if (FcPatternGetString (p, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch)
203 return Qnil;
204 if (FcPatternGetInteger (p, FC_INDEX, 0, &index) != FcResultMatch)
205 return Qnil;
207 key = Fcons (make_unibyte_string ((char *) file, strlen ((char *) file)),
208 make_number (index));
209 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
210 entity = XCAR (cache);
211 if (! NILP (entity))
213 Lisp_Object val = font_make_entity ();
214 int i;
216 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
217 ASET (val, i, AREF (entity, i));
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, (FcChar8 **) &str) == FcResultMatch)
227 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (str, strlen (str), 1));
228 if (FcPatternGetString (p, FC_FAMILY, 0, (FcChar8 **) &str) == FcResultMatch)
229 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (str, strlen (str), 1));
230 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
232 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
233 numeric = FC_WEIGHT_MEDIUM;
234 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
236 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
238 numeric += 100;
239 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
241 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
243 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
245 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
247 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
249 else
250 ASET (entity, FONT_SIZE_INDEX, make_number (0));
251 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
252 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
253 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
255 int dpi = dbl;
256 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
258 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
259 && b == FcTrue)
261 ASET (entity, FONT_SIZE_INDEX, make_number (0));
262 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
264 else
266 /* As this font is not scalable, parhaps this is a BDF or PCF
267 font. */
268 FT_Face ft_face;
270 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
271 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
272 && FT_New_Face (ft_library, file, index, &ft_face) == 0)
274 BDF_PropertyRec rec;
276 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
277 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
278 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
279 FT_Done_Face (ft_face);
283 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
284 font_put_extra (entity, QCfont_entity, key);
285 return entity;
289 static Lisp_Object ftfont_generic_family_list;
291 static Lisp_Object
292 ftfont_resolve_generic_family (family, pattern)
293 Lisp_Object family;
294 FcPattern *pattern;
296 Lisp_Object slot;
297 FcPattern *match;
298 FcResult result;
299 FcLangSet *langset;
301 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
302 if (EQ (family, Qmono))
303 family = Qmonospace;
304 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
305 family = Qsans_serif;
306 slot = assq_no_quit (family, ftfont_generic_family_list);
307 if (! CONSP (slot))
308 return Qnil;
309 if (! EQ (XCDR (slot), Qt))
310 return XCDR (slot);
311 pattern = FcPatternDuplicate (pattern);
312 if (! pattern)
313 goto err;
314 FcPatternDel (pattern, FC_FOUNDRY);
315 FcPatternDel (pattern, FC_FAMILY);
316 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
317 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
319 /* This is to avoid the effect of locale. */
320 langset = FcLangSetCreate ();
321 FcLangSetAdd (langset, "en");
322 FcPatternAddLangSet (pattern, FC_LANG, langset);
323 FcLangSetDestroy (langset);
325 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
326 FcDefaultSubstitute (pattern);
327 match = FcFontMatch (NULL, pattern, &result);
328 if (match)
330 FcChar8 *fam;
332 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
333 family = intern ((char *) fam);
335 else
336 family = Qnil;
337 XSETCDR (slot, family);
338 if (match) FcPatternDestroy (match);
339 err:
340 if (pattern) FcPatternDestroy (pattern);
341 return family;
344 struct ftfont_cache_data
346 FT_Face ft_face;
347 FcCharSet *fc_charset;
350 static Lisp_Object
351 ftfont_lookup_cache (key, cache_for)
352 Lisp_Object key;
353 enum ftfont_cache_for cache_for;
355 Lisp_Object cache, val, entity;
356 struct ftfont_cache_data *cache_data;
358 if (FONT_ENTITY_P (key))
360 entity = key;
361 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
362 xassert (CONSP (val));
363 key = XCDR (val);
365 else
366 entity = Qnil;
368 if (NILP (ft_face_cache))
369 cache = Qnil;
370 else
371 cache = Fgethash (key, ft_face_cache, Qnil);
372 if (NILP (cache))
374 if (NILP (ft_face_cache))
376 Lisp_Object args[2];
378 args[0] = QCtest;
379 args[1] = Qequal;
380 ft_face_cache = Fmake_hash_table (2, args);
382 cache_data = xmalloc (sizeof (struct ftfont_cache_data));
383 cache_data->ft_face = NULL;
384 cache_data->fc_charset = NULL;
385 val = make_save_value (NULL, 0);
386 XSAVE_VALUE (val)->integer = 0;
387 XSAVE_VALUE (val)->pointer = cache_data;
388 cache = Fcons (Qnil, val);
389 Fputhash (key, cache, ft_face_cache);
391 else
393 val = XCDR (cache);
394 cache_data = XSAVE_VALUE (val)->pointer;
397 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
398 return cache;
400 if (cache_for == FTFONT_CACHE_FOR_FACE
401 ? ! cache_data->ft_face : ! cache_data->fc_charset)
403 char *filename = (char *) SDATA (XCAR (key));
404 int index = XINT (XCDR (key));
406 if (cache_for == FTFONT_CACHE_FOR_FACE)
408 if (! ft_library
409 && FT_Init_FreeType (&ft_library) != 0)
410 return Qnil;
411 if (FT_New_Face (ft_library, filename, index, &cache_data->ft_face)
412 != 0)
413 return Qnil;
415 else
417 FcPattern *pat = NULL;
418 FcFontSet *fontset = NULL;
419 FcObjectSet *objset = NULL;
420 FcCharSet *charset = NULL;
422 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
423 FC_INDEX, FcTypeInteger, index, NULL);
424 if (! pat)
425 goto finish;
426 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
427 if (! objset)
428 goto finish;
429 fontset = FcFontList (NULL, pat, objset);
430 if (! fontset)
431 goto finish;
432 if (fontset && fontset->nfont > 0
433 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
434 &charset)
435 == FcResultMatch))
436 cache_data->fc_charset = FcCharSetCopy (charset);
437 else
438 cache_data->fc_charset = FcCharSetCreate ();
440 finish:
441 if (fontset)
442 FcFontSetDestroy (fontset);
443 if (objset)
444 FcObjectSetDestroy (objset);
445 if (pat)
446 FcPatternDestroy (pat);
449 return cache;
452 FcCharSet *
453 ftfont_get_fc_charset (entity)
454 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_VALUE (val)->pointer;
462 return cache_data->fc_charset;
465 #ifdef HAVE_LIBOTF
466 static OTF *
467 ftfont_get_otf (ftfont_info)
468 struct ftfont_info *ftfont_info;
470 OTF *otf;
472 if (ftfont_info->otf)
473 return ftfont_info->otf;
474 if (! ftfont_info->maybe_otf)
475 return NULL;
476 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
477 if (! otf || OTF_get_table (otf, "head") < 0)
479 if (otf)
480 OTF_close (otf);
481 ftfont_info->maybe_otf = 0;
482 return NULL;
484 ftfont_info->otf = otf;
485 return otf;
487 #endif /* HAVE_LIBOTF */
489 static Lisp_Object ftfont_get_cache P_ ((FRAME_PTR));
490 static Lisp_Object ftfont_list P_ ((Lisp_Object, Lisp_Object));
491 static Lisp_Object ftfont_match P_ ((Lisp_Object, Lisp_Object));
492 static Lisp_Object ftfont_list_family P_ ((Lisp_Object));
493 static Lisp_Object ftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
494 static void ftfont_close P_ ((FRAME_PTR, struct font *));
495 static int ftfont_has_char P_ ((Lisp_Object, int));
496 static unsigned ftfont_encode_char P_ ((struct font *, int));
497 static int ftfont_text_extents P_ ((struct font *, unsigned *, int,
498 struct font_metrics *));
499 static int ftfont_get_bitmap P_ ((struct font *, unsigned,
500 struct font_bitmap *, int));
501 static int ftfont_anchor_point P_ ((struct font *, unsigned, int,
502 int *, int *));
503 static Lisp_Object ftfont_otf_capability P_ ((struct font *));
504 static Lisp_Object ftfont_shape P_ ((Lisp_Object));
506 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
507 static int ftfont_variation_glyphs P_ ((struct font *, int c,
508 unsigned variations[256]));
509 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
511 struct font_driver ftfont_driver =
513 0, /* Qfreetype */
514 0, /* case insensitive */
515 ftfont_get_cache,
516 ftfont_list,
517 ftfont_match,
518 ftfont_list_family,
519 NULL, /* free_entity */
520 ftfont_open,
521 ftfont_close,
522 /* We can't draw a text without device dependent functions. */
523 NULL, /* prepare_face */
524 NULL, /* done_face */
525 ftfont_has_char,
526 ftfont_encode_char,
527 ftfont_text_extents,
528 /* We can't draw a text without device dependent functions. */
529 NULL, /* draw */
530 ftfont_get_bitmap,
531 NULL, /* get_bitmap */
532 NULL, /* free_bitmap */
533 NULL, /* get_outline */
534 ftfont_anchor_point,
535 #ifdef HAVE_LIBOTF
536 ftfont_otf_capability,
537 #else /* not HAVE_LIBOTF */
538 NULL,
539 #endif /* not HAVE_LIBOTF */
540 NULL, /* otf_drive */
541 NULL, /* start_for_frame */
542 NULL, /* end_for_frame */
543 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
544 ftfont_shape,
545 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
546 NULL,
547 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
548 NULL, /* check */
550 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
551 ftfont_variation_glyphs,
552 #else
553 NULL,
554 #endif
556 ftfont_filter_properties, /* filter_properties */
559 extern Lisp_Object QCname;
561 static Lisp_Object
562 ftfont_get_cache (f)
563 FRAME_PTR f;
565 return freetype_font_cache;
568 static int
569 ftfont_get_charset (registry)
570 Lisp_Object registry;
572 char *str = (char *) SDATA (SYMBOL_NAME (registry));
573 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
574 Lisp_Object regexp;
575 int i, j;
577 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
579 if (str[i] == '.')
580 re[j++] = '\\';
581 else if (str[i] == '*')
582 re[j++] = '.';
583 re[j] = str[i];
584 if (re[j] == '?')
585 re[j] = '.';
587 re[j] = '\0';
588 regexp = make_unibyte_string (re, j);
589 for (i = 0; fc_charset_table[i].name; i++)
590 if (fast_c_string_match_ignore_case (regexp, fc_charset_table[i].name) >= 0)
591 break;
592 if (! fc_charset_table[i].name)
593 return -1;
594 if (! fc_charset_table[i].fc_charset)
596 FcCharSet *charset = FcCharSetCreate ();
597 int *uniquifier = fc_charset_table[i].uniquifier;
599 if (! charset)
600 return -1;
601 for (j = 0; uniquifier[j]; j++)
602 if (! FcCharSetAddChar (charset, uniquifier[j]))
604 FcCharSetDestroy (charset);
605 return -1;
607 fc_charset_table[i].fc_charset = charset;
609 return i;
612 struct OpenTypeSpec
614 Lisp_Object script;
615 unsigned int script_tag, langsys_tag;
616 int nfeatures[2];
617 unsigned int *features[2];
620 #define OTF_SYM_TAG(SYM, TAG) \
621 do { \
622 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
623 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
624 } while (0)
626 #define OTF_TAG_STR(TAG, P) \
627 do { \
628 (P)[0] = (char) (TAG >> 24); \
629 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
630 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
631 (P)[3] = (char) (TAG & 0xFF); \
632 (P)[4] = '\0'; \
633 } while (0)
635 #define OTF_TAG_SYM(SYM, TAG) \
636 do { \
637 char str[5]; \
639 OTF_TAG_STR (TAG, str); \
640 (SYM) = font_intern_prop (str, 4, 1); \
641 } while (0)
644 static struct OpenTypeSpec *
645 ftfont_get_open_type_spec (Lisp_Object otf_spec)
647 struct OpenTypeSpec *spec = malloc (sizeof (struct OpenTypeSpec));
648 Lisp_Object val;
649 int i, j, negative;
651 if (! spec)
652 return NULL;
653 spec->script = XCAR (otf_spec);
654 if (! NILP (spec->script))
656 OTF_SYM_TAG (spec->script, spec->script_tag);
657 val = assq_no_quit (spec->script, Votf_script_alist);
658 if (CONSP (val) && SYMBOLP (XCDR (val)))
659 spec->script = XCDR (val);
660 else
661 spec->script = Qnil;
663 else
664 spec->script_tag = 0x44464C54; /* "DFLT" */
665 otf_spec = XCDR (otf_spec);
666 spec->langsys_tag = 0;
667 if (! NILP (otf_spec))
669 val = XCAR (otf_spec);
670 if (! NILP (val))
671 OTF_SYM_TAG (val, spec->langsys_tag);
672 otf_spec = XCDR (otf_spec);
674 spec->nfeatures[0] = spec->nfeatures[1] = 0;
675 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
677 Lisp_Object len;
679 val = XCAR (otf_spec);
680 if (NILP (val))
681 continue;
682 len = Flength (val);
683 spec->features[i] = malloc (sizeof (int) * XINT (len));
684 if (! spec->features[i])
686 if (i > 0 && spec->features[0])
687 free (spec->features[0]);
688 free (spec);
689 return NULL;
691 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
693 if (NILP (XCAR (val)))
694 negative = 1;
695 else
697 unsigned int tag;
699 OTF_SYM_TAG (XCAR (val), tag);
700 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
703 spec->nfeatures[i] = j;
705 return spec;
708 static FcPattern *ftfont_spec_pattern P_ ((Lisp_Object, char *,
709 struct OpenTypeSpec **,
710 char **langname));
712 static FcPattern *
713 ftfont_spec_pattern (spec, otlayout, otspec, langname)
714 Lisp_Object spec;
715 char *otlayout;
716 struct OpenTypeSpec **otspec;
717 char **langname;
719 Lisp_Object tmp, extra;
720 FcPattern *pattern = NULL;
721 FcCharSet *charset = NULL;
722 FcLangSet *langset = NULL;
723 int n;
724 int dpi = -1;
725 int scalable = -1;
726 Lisp_Object script = Qnil;
727 Lisp_Object registry;
728 int fc_charset_idx;
730 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
731 && n < 100)
732 /* Fontconfig doesn't support reverse-italic/obligue. */
733 return NULL;
735 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
736 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
737 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
738 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
739 scalable = 1;
741 registry = AREF (spec, FONT_REGISTRY_INDEX);
742 if (NILP (registry)
743 || EQ (registry, Qascii_0)
744 || EQ (registry, Qiso10646_1)
745 || EQ (registry, Qunicode_bmp))
746 fc_charset_idx = -1;
747 else
749 FcChar8 *lang;
751 fc_charset_idx = ftfont_get_charset (registry);
752 if (fc_charset_idx < 0)
753 return NULL;
754 charset = fc_charset_table[fc_charset_idx].fc_charset;
755 *langname = fc_charset_table[fc_charset_idx].lang;
756 lang = (FcChar8 *) *langname;
757 if (lang)
759 langset = FcLangSetCreate ();
760 if (! langset)
761 goto err;
762 FcLangSetAdd (langset, lang);
766 otlayout[0] = '\0';
767 for (extra = AREF (spec, FONT_EXTRA_INDEX);
768 CONSP (extra); extra = XCDR (extra))
770 Lisp_Object key, val;
772 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
773 if (EQ (key, QCdpi))
774 dpi = XINT (val);
775 else if (EQ (key, QClang))
777 if (! langset)
778 langset = FcLangSetCreate ();
779 if (! langset)
780 goto err;
781 if (SYMBOLP (val))
783 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
784 goto err;
786 else
787 for (; CONSP (val); val = XCDR (val))
788 if (SYMBOLP (XCAR (val))
789 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
790 goto err;
792 else if (EQ (key, QCotf))
794 *otspec = ftfont_get_open_type_spec (val);
795 if (! *otspec)
796 return NULL;
797 strcat (otlayout, "otlayout:");
798 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
799 script = (*otspec)->script;
801 else if (EQ (key, QCscript))
802 script = val;
803 else if (EQ (key, QCscalable))
804 scalable = ! NILP (val);
807 if (! NILP (script) && ! charset)
809 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
811 if (CONSP (chars) && CONSP (CDR (chars)))
813 charset = FcCharSetCreate ();
814 if (! charset)
815 goto err;
816 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
817 if (CHARACTERP (XCAR (chars))
818 && ! FcCharSetAddChar (charset, XUINT (XCAR (chars))))
819 goto err;
823 pattern = FcPatternCreate ();
824 if (! pattern)
825 goto err;
826 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
827 if (! NILP (tmp)
828 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
829 goto err;
830 tmp = AREF (spec, FONT_FAMILY_INDEX);
831 if (! NILP (tmp)
832 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
833 goto err;
834 if (charset
835 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
836 goto err;
837 if (langset
838 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
839 goto err;
840 if (dpi >= 0
841 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
842 goto err;
843 if (scalable >= 0
844 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
845 goto err;
847 goto finish;
849 err:
850 /* We come here because of unexpected error in fontconfig API call
851 (usually insufficient memory). */
852 if (pattern)
854 FcPatternDestroy (pattern);
855 pattern = NULL;
857 if (*otspec)
859 if ((*otspec)->nfeatures[0] > 0)
860 free ((*otspec)->features[0]);
861 if ((*otspec)->nfeatures[1] > 0)
862 free ((*otspec)->features[1]);
863 free (*otspec);
864 *otspec = NULL;
867 finish:
868 if (langset) FcLangSetDestroy (langset);
869 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
870 return pattern;
873 static Lisp_Object
874 ftfont_list (frame, spec)
875 Lisp_Object frame, spec;
877 Lisp_Object val = Qnil, family, adstyle;
878 int i;
879 FcPattern *pattern;
880 FcFontSet *fontset = NULL;
881 FcObjectSet *objset = NULL;
882 FcCharSet *charset;
883 Lisp_Object chars = Qnil;
884 FcResult result;
885 char otlayout[15]; /* For "otlayout:XXXX" */
886 struct OpenTypeSpec *otspec = NULL;
887 int spacing = -1;
888 char *langname = NULL;
890 if (! fc_initialized)
892 FcInit ();
893 fc_initialized = 1;
896 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
897 if (! pattern)
898 return Qnil;
899 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
901 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
902 if (! NILP (val))
904 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
905 if (CONSP (val) && VECTORP (XCDR (val)))
906 chars = XCDR (val);
908 val = Qnil;
910 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
911 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
912 family = AREF (spec, FONT_FAMILY_INDEX);
913 if (! NILP (family))
915 Lisp_Object resolved;
917 resolved = ftfont_resolve_generic_family (family, pattern);
918 if (! NILP (resolved))
920 FcPatternDel (pattern, FC_FAMILY);
921 if (! FcPatternAddString (pattern, FC_FAMILY,
922 SYMBOL_FcChar8 (resolved)))
923 goto err;
926 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
927 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
928 adstyle = Qnil;
929 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
930 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
931 FC_STYLE, FC_FILE, FC_INDEX,
932 #ifdef FC_CAPABILITY
933 FC_CAPABILITY,
934 #endif /* FC_CAPABILITY */
935 #ifdef FC_FONTFORMAT
936 FC_FONTFORMAT,
937 #endif
938 NULL);
939 if (! objset)
940 goto err;
941 if (! NILP (chars))
942 FcObjectSetAdd (objset, FC_CHARSET);
944 fontset = FcFontList (NULL, pattern, objset);
945 if (! fontset || fontset->nfont == 0)
946 goto finish;
947 #if 0
948 /* Need fix because this finds any fonts. */
949 if (fontset->nfont == 0 && ! NILP (family))
951 /* Try maching with configuration. For instance, the
952 configuration may specify "Nimbus Mono L" as an alias of
953 "Courier". */
954 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
955 SYMBOL_FcChar8 (family), NULL);
956 FcChar8 *fam;
958 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
960 for (i = 0;
961 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
962 i++)
964 FcPatternDel (pattern, FC_FAMILY);
965 FcPatternAddString (pattern, FC_FAMILY, fam);
966 FcFontSetDestroy (fontset);
967 fontset = FcFontList (NULL, pattern, objset);
968 if (fontset && fontset->nfont > 0)
969 break;
973 #endif
974 for (i = 0; i < fontset->nfont; i++)
976 Lisp_Object entity;
978 if (spacing >= 0)
980 int this;
982 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
983 == FcResultMatch)
984 && spacing != this)
985 continue;
988 #ifdef FC_CAPABILITY
989 if (otlayout[0])
991 FcChar8 *this;
993 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
994 != FcResultMatch
995 || ! strstr ((char *) this, otlayout))
996 continue;
998 #endif /* FC_CAPABILITY */
999 #ifdef HAVE_LIBOTF
1000 if (otspec)
1002 FcChar8 *file;
1003 OTF *otf;
1005 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1006 != FcResultMatch)
1007 continue;
1008 otf = OTF_open ((char *) file);
1009 if (! otf)
1010 continue;
1011 if (OTF_check_features (otf, 1,
1012 otspec->script_tag, otspec->langsys_tag,
1013 otspec->features[0],
1014 otspec->nfeatures[0]) != 1
1015 || OTF_check_features (otf, 0,
1016 otspec->script_tag, otspec->langsys_tag,
1017 otspec->features[1],
1018 otspec->nfeatures[1]) != 1)
1019 continue;
1021 #endif /* HAVE_LIBOTF */
1022 if (VECTORP (chars))
1024 int j;
1026 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1027 != FcResultMatch)
1028 continue;
1029 for (j = 0; j < ASIZE (chars); j++)
1030 if (NATNUMP (AREF (chars, j))
1031 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1032 break;
1033 if (j == ASIZE (chars))
1034 continue;
1036 if (! NILP (adstyle) || langname)
1038 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1040 if (! NILP (adstyle)
1041 && (NILP (this_adstyle)
1042 || xstrcasecmp (SDATA (SYMBOL_NAME (adstyle)),
1043 SDATA (SYMBOL_NAME (this_adstyle))) != 0))
1044 continue;
1045 if (langname
1046 && ! NILP (this_adstyle)
1047 && xstrcasecmp (langname, SDATA (SYMBOL_NAME (this_adstyle))))
1048 continue;
1050 entity = ftfont_pattern_entity (fontset->fonts[i],
1051 AREF (spec, FONT_EXTRA_INDEX));
1052 if (! NILP (entity))
1053 val = Fcons (entity, val);
1055 val = Fnreverse (val);
1056 goto finish;
1058 err:
1059 /* We come here because of unexpected error in fontconfig API call
1060 (usually insufficient memory). */
1061 val = Qnil;
1063 finish:
1064 FONT_ADD_LOG ("ftfont-list", spec, val);
1065 if (objset) FcObjectSetDestroy (objset);
1066 if (fontset) FcFontSetDestroy (fontset);
1067 if (pattern) FcPatternDestroy (pattern);
1068 return val;
1071 static Lisp_Object
1072 ftfont_match (frame, spec)
1073 Lisp_Object frame, spec;
1075 Lisp_Object entity = Qnil;
1076 FcPattern *pattern, *match = NULL;
1077 FcResult result;
1078 char otlayout[15]; /* For "otlayout:XXXX" */
1079 struct OpenTypeSpec *otspec = NULL;
1080 char *langname = NULL;
1082 if (! fc_initialized)
1084 FcInit ();
1085 fc_initialized = 1;
1088 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1089 if (! pattern)
1090 return Qnil;
1092 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1094 FcValue value;
1096 value.type = FcTypeDouble;
1097 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1098 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1100 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1102 FcDefaultSubstitute (pattern);
1103 match = FcFontMatch (NULL, pattern, &result);
1104 if (match)
1106 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1107 FcPatternDestroy (match);
1108 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1109 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1110 ftfont_generic_family_list))
1111 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1112 AREF (entity, FONT_FAMILY_INDEX))))
1113 entity = Qnil;
1116 FcPatternDestroy (pattern);
1118 FONT_ADD_LOG ("ftfont-match", spec, entity);
1119 return entity;
1122 static Lisp_Object
1123 ftfont_list_family (frame)
1124 Lisp_Object frame;
1126 Lisp_Object list = Qnil;
1127 FcPattern *pattern = NULL;
1128 FcFontSet *fontset = NULL;
1129 FcObjectSet *objset = NULL;
1130 int i;
1132 if (! fc_initialized)
1134 FcInit ();
1135 fc_initialized = 1;
1138 pattern = FcPatternCreate ();
1139 if (! pattern)
1140 goto finish;
1141 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1142 if (! objset)
1143 goto finish;
1144 fontset = FcFontList (NULL, pattern, objset);
1145 if (! fontset)
1146 goto finish;
1148 for (i = 0; i < fontset->nfont; i++)
1150 FcPattern *pat = fontset->fonts[i];
1151 FcChar8 *str;
1153 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1154 list = Fcons (intern ((char *) str), list);
1157 finish:
1158 if (objset) FcObjectSetDestroy (objset);
1159 if (fontset) FcFontSetDestroy (fontset);
1160 if (pattern) FcPatternDestroy (pattern);
1162 return list;
1166 static Lisp_Object
1167 ftfont_open (f, entity, pixel_size)
1168 FRAME_PTR f;
1169 Lisp_Object entity;
1170 int pixel_size;
1172 struct ftfont_info *ftfont_info;
1173 struct font *font;
1174 struct ftfont_cache_data *cache_data;
1175 FT_Face ft_face;
1176 FT_Size ft_size;
1177 FT_UInt size;
1178 Lisp_Object val, filename, index, cache, font_object;
1179 int scalable;
1180 int spacing;
1181 char name[256];
1182 int i, len;
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 index = XCDR (val);
1194 val = XCDR (cache);
1195 cache_data = XSAVE_VALUE (XCDR (cache))->pointer;
1196 ft_face = cache_data->ft_face;
1197 if (XSAVE_VALUE (val)->integer > 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 XSAVE_VALUE (val)->integer++;
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_VALUE (val)->integer == 0)
1215 FT_Done_Face (ft_face);
1216 return Qnil;
1219 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
1220 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
1221 len = font_unparse_xlfd (entity, size, name, 256);
1222 if (len > 0)
1223 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
1224 len = font_unparse_fcname (entity, size, name, 256);
1225 if (len > 0)
1226 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
1227 else
1228 ASET (font_object, FONT_FULLNAME_INDEX,
1229 AREF (font_object, FONT_NAME_INDEX));
1230 ASET (font_object, FONT_FILE_INDEX, filename);
1231 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
1232 font = XFONT_OBJECT (font_object);
1233 ftfont_info = (struct ftfont_info *) font;
1234 ftfont_info->ft_size = ft_face->size;
1235 ftfont_info->index = XINT (index);
1236 #ifdef HAVE_LIBOTF
1237 ftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
1238 ftfont_info->otf = NULL;
1239 #endif /* HAVE_LIBOTF */
1240 /* This means that there's no need of transformation. */
1241 ftfont_info->matrix.xx = 0;
1242 font->pixel_size = size;
1243 font->driver = &ftfont_driver;
1244 font->encoding_charset = font->repertory_charset = -1;
1246 upEM = ft_face->units_per_EM;
1247 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1248 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1249 if (scalable)
1251 font->ascent = ft_face->ascender * size / upEM;
1252 font->descent = - ft_face->descender * size / upEM;
1253 font->height = ft_face->height * size / upEM;
1255 else
1257 font->ascent = ft_face->size->metrics.ascender >> 6;
1258 font->descent = - ft_face->size->metrics.descender >> 6;
1259 font->height = ft_face->size->metrics.height >> 6;
1261 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1262 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1263 else
1264 spacing = FC_PROPORTIONAL;
1265 if (spacing != FC_PROPORTIONAL)
1266 font->min_width = font->average_width = font->space_width
1267 = (scalable ? ft_face->max_advance_width * size / upEM
1268 : ft_face->size->metrics.max_advance >> 6);
1269 else
1271 int n;
1273 font->min_width = font->average_width = font->space_width = 0;
1274 for (i = 32, n = 0; i < 127; i++)
1275 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1277 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1279 if (this_width > 0
1280 && (! font->min_width || font->min_width > this_width))
1281 font->min_width = this_width;
1282 if (i == 32)
1283 font->space_width = this_width;
1284 font->average_width += this_width;
1285 n++;
1287 if (n > 0)
1288 font->average_width /= n;
1291 font->baseline_offset = 0;
1292 font->relative_compose = 0;
1293 font->default_ascent = 0;
1294 font->vertical_centering = 0;
1295 if (scalable)
1297 font->underline_position = -ft_face->underline_position * size / upEM;
1298 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1300 else
1302 font->underline_position = -1;
1303 font->underline_thickness = 0;
1306 return font_object;
1309 static void
1310 ftfont_close (f, font)
1311 FRAME_PTR f;
1312 struct font *font;
1314 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1315 Lisp_Object val, cache;
1317 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1318 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1319 xassert (CONSP (cache));
1320 val = XCDR (cache);
1321 (XSAVE_VALUE (val)->integer)--;
1322 if (XSAVE_VALUE (val)->integer == 0)
1324 struct ftfont_cache_data *cache_data = XSAVE_VALUE (val)->pointer;
1326 FT_Done_Face (cache_data->ft_face);
1327 #ifdef HAVE_LIBOTF
1328 if (ftfont_info->otf)
1329 OTF_close (ftfont_info->otf);
1330 #endif
1331 cache_data->ft_face = NULL;
1333 else
1334 FT_Done_Size (ftfont_info->ft_size);
1337 static int
1338 ftfont_has_char (font, c)
1339 Lisp_Object font;
1340 int c;
1342 struct charset *cs = NULL;
1344 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1345 && charset_jisx0208 >= 0)
1346 cs = CHARSET_FROM_ID (charset_jisx0208);
1347 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1348 && charset_ksc5601 >= 0)
1349 cs = CHARSET_FROM_ID (charset_ksc5601);
1350 if (cs)
1351 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1353 if (FONT_ENTITY_P (font))
1355 FcCharSet *charset = ftfont_get_fc_charset (font);
1357 return (FcCharSetHasChar (charset, c) == FcTrue);
1359 else
1361 struct ftfont_info *ftfont_info;
1363 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1364 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1365 != 0);
1369 static unsigned
1370 ftfont_encode_char (font, c)
1371 struct font *font;
1372 int c;
1374 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1375 FT_Face ft_face = ftfont_info->ft_size->face;
1376 FT_ULong charcode = c;
1377 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1379 return (code > 0 ? code : FONT_INVALID_CODE);
1382 static int
1383 ftfont_text_extents (font, code, nglyphs, metrics)
1384 struct font *font;
1385 unsigned *code;
1386 int nglyphs;
1387 struct font_metrics *metrics;
1389 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1390 FT_Face ft_face = ftfont_info->ft_size->face;
1391 int width = 0;
1392 int i, first;
1394 if (ftfont_info->ft_size != ft_face->size)
1395 FT_Activate_Size (ftfont_info->ft_size);
1396 if (metrics)
1397 bzero (metrics, sizeof (struct font_metrics));
1398 for (i = 0, first = 1; i < nglyphs; i++)
1400 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1402 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1404 if (first)
1406 if (metrics)
1408 metrics->lbearing = m->horiBearingX >> 6;
1409 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1410 metrics->ascent = m->horiBearingY >> 6;
1411 metrics->descent = (m->height - m->horiBearingY) >> 6;
1413 first = 0;
1415 if (metrics)
1417 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1418 metrics->lbearing = width + (m->horiBearingX >> 6);
1419 if (metrics->rbearing
1420 < width + ((m->horiBearingX + m->width) >> 6))
1421 metrics->rbearing
1422 = width + ((m->horiBearingX + m->width) >> 6);
1423 if (metrics->ascent < (m->horiBearingY >> 6))
1424 metrics->ascent = m->horiBearingY >> 6;
1425 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1426 metrics->descent = (m->height - m->horiBearingY) >> 6;
1428 width += m->horiAdvance >> 6;
1430 else
1432 width += font->space_width;
1435 if (metrics)
1436 metrics->width = width;
1438 return width;
1441 static int
1442 ftfont_get_bitmap (font, code, bitmap, bits_per_pixel)
1443 struct font *font;
1444 unsigned code;
1445 struct font_bitmap *bitmap;
1446 int bits_per_pixel;
1448 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1449 FT_Face ft_face = ftfont_info->ft_size->face;
1450 FT_Int32 load_flags = FT_LOAD_RENDER;
1452 if (ftfont_info->ft_size != ft_face->size)
1453 FT_Activate_Size (ftfont_info->ft_size);
1454 if (bits_per_pixel == 1)
1456 #ifdef FT_LOAD_TARGET_MONO
1457 load_flags |= FT_LOAD_TARGET_MONO;
1458 #else
1459 load_flags |= FT_LOAD_MONOCHROME;
1460 #endif
1462 else if (bits_per_pixel != 8)
1463 /* We don't support such a rendering. */
1464 return -1;
1466 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1467 return -1;
1468 bitmap->bits_per_pixel
1469 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1470 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1471 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1472 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1473 : -1);
1474 if (bitmap->bits_per_pixel < 0)
1475 /* We don't suport that kind of pixel mode. */
1476 return -1;
1477 bitmap->rows = ft_face->glyph->bitmap.rows;
1478 bitmap->width = ft_face->glyph->bitmap.width;
1479 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1480 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1481 bitmap->left = ft_face->glyph->bitmap_left;
1482 bitmap->top = ft_face->glyph->bitmap_top;
1483 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1484 bitmap->extra = NULL;
1486 return 0;
1489 static int
1490 ftfont_anchor_point (font, code, index, x, y)
1491 struct font *font;
1492 unsigned code;
1493 int index;
1494 int *x, *y;
1496 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1497 FT_Face ft_face = ftfont_info->ft_size->face;
1499 if (ftfont_info->ft_size != ft_face->size)
1500 FT_Activate_Size (ftfont_info->ft_size);
1501 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1502 return -1;
1503 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1504 return -1;
1505 if (index >= ft_face->glyph->outline.n_points)
1506 return -1;
1507 *x = ft_face->glyph->outline.points[index].x;
1508 *y = ft_face->glyph->outline.points[index].y;
1509 return 0;
1512 #ifdef HAVE_LIBOTF
1514 static Lisp_Object
1515 ftfont_otf_features (gsub_gpos)
1516 OTF_GSUB_GPOS *gsub_gpos;
1518 Lisp_Object scripts, langsyses, features, sym;
1519 int i, j, k, l;
1521 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1523 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1525 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1527 OTF_LangSys *otf_langsys;
1529 if (j >= 0)
1530 otf_langsys = otf_script->LangSys + j;
1531 else if (otf_script->DefaultLangSysOffset)
1532 otf_langsys = &otf_script->DefaultLangSys;
1533 else
1534 break;
1536 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1538 l = otf_langsys->FeatureIndex[k];
1539 if (l >= gsub_gpos->FeatureList.FeatureCount)
1540 continue;
1541 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1542 features = Fcons (sym, features);
1544 if (j >= 0)
1545 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1546 else
1547 sym = Qnil;
1548 langsyses = Fcons (Fcons (sym, features), langsyses);
1551 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1552 scripts = Fcons (Fcons (sym, langsyses), scripts);
1554 return scripts;
1559 static Lisp_Object
1560 ftfont_otf_capability (font)
1561 struct font *font;
1563 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1564 OTF *otf = ftfont_get_otf (ftfont_info);
1565 Lisp_Object gsub_gpos;
1567 if (! otf)
1568 return Qnil;
1569 gsub_gpos = Fcons (Qnil, Qnil);
1570 if (OTF_get_table (otf, "GSUB") == 0
1571 && otf->gsub->FeatureList.FeatureCount > 0)
1572 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1573 if (OTF_get_table (otf, "GPOS") == 0
1574 && otf->gpos->FeatureList.FeatureCount > 0)
1575 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1576 return gsub_gpos;
1579 #ifdef HAVE_M17N_FLT
1581 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1582 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1583 /* We can use the new feature of libotf and m17n-flt to handle the
1584 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1585 some Agian scripts. */
1586 #define M17N_FLT_USE_NEW_FEATURE
1587 #endif
1589 struct MFLTFontFT
1591 MFLTFont flt_font;
1592 struct font *font;
1593 FT_Face ft_face;
1594 OTF *otf;
1595 FT_Matrix *matrix;
1598 static int
1599 ftfont_get_glyph_id (font, gstring, from, to)
1600 MFLTFont *font;
1601 MFLTGlyphString *gstring;
1602 int from, to;
1604 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1605 FT_Face ft_face = flt_font_ft->ft_face;
1606 MFLTGlyph *g;
1608 for (g = gstring->glyphs + from; from < to; g++, from++)
1609 if (! g->encoded)
1611 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1613 g->code = code > 0 ? code : FONT_INVALID_CODE;
1614 g->encoded = 1;
1616 return 0;
1619 /* Operators for 26.6 fixed fractional pixel format */
1621 #define FLOOR(x) ((x) & -64)
1622 #define CEIL(x) (((x)+63) & -64)
1623 #define ROUND(x) (((x)+32) & -64)
1625 static int
1626 ftfont_get_metrics (font, gstring, from, to)
1627 MFLTFont *font;
1628 MFLTGlyphString *gstring;
1629 int from, to;
1631 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1632 FT_Face ft_face = flt_font_ft->ft_face;
1633 MFLTGlyph *g;
1635 for (g = gstring->glyphs + from; from < to; g++, from++)
1636 if (! g->measured)
1638 if (g->code != FONT_INVALID_CODE)
1640 FT_Glyph_Metrics *m;
1641 int lbearing, rbearing, ascent, descent, xadv;
1643 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1644 abort ();
1645 m = &ft_face->glyph->metrics;
1646 if (flt_font_ft->matrix)
1648 FT_Vector v[4];
1649 int i;
1651 v[0].x = v[1].x = m->horiBearingX;
1652 v[2].x = v[3].x = m->horiBearingX + m->width;
1653 v[0].y = v[2].y = m->horiBearingY;
1654 v[1].y = v[3].y = m->horiBearingY - m->height;
1655 for (i = 0; i < 4; i++)
1656 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1657 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1658 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1659 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1660 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1662 else
1664 g->lbearing = FLOOR (m->horiBearingX);
1665 g->rbearing = CEIL (m->horiBearingX + m->width);
1666 g->ascent = CEIL (m->horiBearingY);
1667 g->descent = - FLOOR (m->horiBearingY - m->height);
1669 g->xadv = ROUND (ft_face->glyph->advance.x);
1671 else
1673 g->lbearing = 0;
1674 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1675 g->ascent = flt_font_ft->font->ascent << 6;
1676 g->descent = flt_font_ft->font->descent << 6;
1678 g->yadv = 0;
1679 g->measured = 1;
1681 return 0;
1684 static int
1685 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1687 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1688 OTF *otf = flt_font_ft->otf;
1689 OTF_Tag *tags;
1690 int i, n, negative;
1692 for (i = 0; i < 2; i++)
1694 if (! spec->features[i])
1695 continue;
1696 for (n = 0; spec->features[i][n]; n++);
1697 tags = alloca (sizeof (OTF_Tag) * n);
1698 for (n = 0, negative = 0; spec->features[i][n]; n++)
1700 if (spec->features[i][n] == 0xFFFFFFFF)
1701 negative = 1;
1702 else if (negative)
1703 tags[n - 1] = spec->features[i][n] | 0x80000000;
1704 else
1705 tags[n] = spec->features[i][n];
1707 #ifdef M17N_FLT_USE_NEW_FEATURE
1708 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1709 tags, n - negative) != 1)
1710 return 0;
1711 #else /* not M17N_FLT_USE_NEW_FEATURE */
1712 if (n - negative > 0
1713 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1714 tags, n - negative) != 1)
1715 return 0;
1716 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1718 return 1;
1721 #define DEVICE_DELTA(table, size) \
1722 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1723 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1724 : 0)
1726 static void
1727 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1728 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1730 if (anchor->AnchorFormat == 2)
1732 FT_Outline *outline;
1733 int ap = anchor->f.f1.AnchorPoint;
1735 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1736 outline = &ft_face->glyph->outline;
1737 if (ap < outline->n_points)
1739 *x = outline->points[ap].x << 6;
1740 *y = outline->points[ap].y << 6;
1743 else if (anchor->AnchorFormat == 3)
1745 if (anchor->f.f2.XDeviceTable.offset
1746 && anchor->f.f2.XDeviceTable.DeltaValue)
1747 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1748 if (anchor->f.f2.YDeviceTable.offset
1749 && anchor->f.f2.YDeviceTable.DeltaValue)
1750 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1754 static OTF_GlyphString otf_gstring;
1756 static void
1757 setup_otf_gstring (int size)
1759 if (otf_gstring.size == 0)
1761 otf_gstring.glyphs = (OTF_Glyph *) xmalloc (sizeof (OTF_Glyph) * size);
1762 otf_gstring.size = size;
1764 else if (otf_gstring.size < size)
1766 otf_gstring.glyphs = xrealloc (otf_gstring.glyphs,
1767 sizeof (OTF_Glyph) * size);
1768 otf_gstring.size = size;
1770 otf_gstring.used = size;
1771 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1774 #ifdef M17N_FLT_USE_NEW_FEATURE
1776 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1777 #define PACK_OTF_TAG(TAG) \
1778 ((((TAG) & 0x7F000000) >> 3) \
1779 | (((TAG) & 0x7F0000) >> 2) \
1780 | (((TAG) & 0x7F00) >> 1) \
1781 | ((TAG) & 0x7F))
1783 /* Assuming that FONT is an OpenType font, apply OpenType features
1784 specified in SPEC on glyphs between FROM and TO of IN, and record
1785 the lastly applied feature in each glyph of IN. If OUT is not
1786 NULL, append the resulting glyphs to OUT while storing glyph
1787 position adjustment information in ADJUSTMENT. */
1789 static int
1790 ftfont_drive_otf (font, spec, in, from, to, out, adjustment)
1791 MFLTFont *font;
1792 MFLTOtfSpec *spec;
1793 MFLTGlyphString *in;
1794 int from, to;
1795 MFLTGlyphString *out;
1796 MFLTGlyphAdjustment *adjustment;
1798 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1799 FT_Face ft_face = flt_font_ft->ft_face;
1800 OTF *otf = flt_font_ft->otf;
1801 int len = to - from;
1802 int i, j, gidx;
1803 OTF_Glyph *otfg;
1804 char script[5], *langsys = NULL;
1805 char *gsub_features = NULL, *gpos_features = NULL;
1806 OTF_Feature *features;
1808 if (len == 0)
1809 return from;
1810 OTF_tag_name (spec->script, script);
1811 if (spec->langsys)
1813 langsys = alloca (5);
1814 OTF_tag_name (spec->langsys, langsys);
1816 for (i = 0; i < 2; i++)
1818 char *p;
1820 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1822 for (j = 0; spec->features[i][j]; j++);
1823 if (i == 0)
1824 p = gsub_features = alloca (6 * j);
1825 else
1826 p = gpos_features = alloca (6 * j);
1827 for (j = 0; spec->features[i][j]; j++)
1829 if (spec->features[i][j] == 0xFFFFFFFF)
1830 *p++ = '*', *p++ = ',';
1831 else
1833 OTF_tag_name (spec->features[i][j], p);
1834 p[4] = ',';
1835 p += 5;
1838 *--p = '\0';
1842 setup_otf_gstring (len);
1843 for (i = 0; i < len; i++)
1845 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
1846 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1849 OTF_drive_gdef (otf, &otf_gstring);
1850 gidx = out ? out->used : from;
1852 if (gsub_features && out)
1854 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1855 gsub_features) < 0)
1856 goto simple_copy;
1857 if (out->allocated < out->used + otf_gstring.used)
1858 return -2;
1859 features = otf->gsub->FeatureList.Feature;
1860 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1862 MFLTGlyph *g;
1863 int min_from, max_to;
1864 int j;
1865 int feature_idx = otfg->positioning_type >> 4;
1867 g = out->glyphs + out->used;
1868 *g = in->glyphs[from + otfg->f.index.from];
1869 if (g->code != otfg->glyph_id)
1871 g->c = 0;
1872 g->code = otfg->glyph_id;
1873 g->measured = 0;
1875 out->used++;
1876 min_from = g->from;
1877 max_to = g->to;
1878 if (otfg->f.index.from < otfg->f.index.to)
1880 /* OTFG substitutes multiple glyphs in IN. */
1881 for (j = from + otfg->f.index.from + 1;
1882 j <= from + otfg->f.index.to; j++)
1884 if (min_from > in->glyphs[j].from)
1885 min_from = in->glyphs[j].from;
1886 if (max_to < in->glyphs[j].to)
1887 max_to = in->glyphs[j].to;
1889 g->from = min_from;
1890 g->to = max_to;
1892 if (feature_idx)
1894 unsigned int tag = features[feature_idx - 1].FeatureTag;
1895 tag = PACK_OTF_TAG (tag);
1896 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1898 for (i++, otfg++; (i < otf_gstring.used
1899 && otfg->f.index.from == otfg[-1].f.index.from);
1900 i++, otfg++)
1902 g = out->glyphs + out->used;
1903 *g = in->glyphs[from + otfg->f.index.to];
1904 if (g->code != otfg->glyph_id)
1906 g->c = 0;
1907 g->code = otfg->glyph_id;
1908 g->measured = 0;
1910 feature_idx = otfg->positioning_type >> 4;
1911 if (feature_idx)
1913 unsigned int tag = features[feature_idx - 1].FeatureTag;
1914 tag = PACK_OTF_TAG (tag);
1915 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1917 out->used++;
1921 else if (gsub_features)
1923 /* Just for checking which features will be applied. */
1924 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1925 gsub_features) < 0)
1926 goto simple_copy;
1927 features = otf->gsub->FeatureList.Feature;
1928 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1929 otfg++)
1931 int feature_idx = otfg->positioning_type >> 4;
1933 if (feature_idx)
1935 unsigned int tag = features[feature_idx - 1].FeatureTag;
1936 tag = PACK_OTF_TAG (tag);
1937 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1939 MFLTGlyph *g = in->glyphs + (from + j);
1940 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1945 else if (out)
1947 if (out->allocated < out->used + len)
1948 return -2;
1949 for (i = 0; i < len; i++)
1950 out->glyphs[out->used++] = in->glyphs[from + i];
1953 if (gpos_features && out)
1955 MFLTGlyph *base = NULL, *mark = NULL, *g;
1956 int x_ppem, y_ppem, x_scale, y_scale;
1958 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1959 gpos_features) < 0)
1960 return to;
1961 features = otf->gpos->FeatureList.Feature;
1962 x_ppem = ft_face->size->metrics.x_ppem;
1963 y_ppem = ft_face->size->metrics.y_ppem;
1964 x_scale = ft_face->size->metrics.x_scale;
1965 y_scale = ft_face->size->metrics.y_scale;
1967 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1968 i < otf_gstring.used; i++, otfg++, g++)
1970 MFLTGlyph *prev;
1971 int feature_idx = otfg->positioning_type >> 4;
1973 if (feature_idx)
1975 unsigned int tag = features[feature_idx - 1].FeatureTag;
1976 tag = PACK_OTF_TAG (tag);
1977 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1980 if (! otfg->glyph_id)
1981 continue;
1982 switch (otfg->positioning_type & 0xF)
1984 case 0:
1985 break;
1986 case 1: /* Single */
1987 case 2: /* Pair */
1989 int format = otfg->f.f1.format;
1991 if (format & OTF_XPlacement)
1992 adjustment[i].xoff
1993 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
1994 if (format & OTF_XPlaDevice)
1995 adjustment[i].xoff
1996 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
1997 if (format & OTF_YPlacement)
1998 adjustment[i].yoff
1999 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2000 if (format & OTF_YPlaDevice)
2001 adjustment[i].yoff
2002 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2003 if (format & OTF_XAdvance)
2004 adjustment[i].xadv
2005 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2006 if (format & OTF_XAdvDevice)
2007 adjustment[i].xadv
2008 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2009 if (format & OTF_YAdvance)
2010 adjustment[i].yadv
2011 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2012 if (format & OTF_YAdvDevice)
2013 adjustment[i].yadv
2014 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2015 adjustment[i].set = 1;
2017 break;
2018 case 3: /* Cursive */
2019 /* Not yet supported. */
2020 break;
2021 case 4: /* Mark-to-Base */
2022 case 5: /* Mark-to-Ligature */
2023 if (! base)
2024 break;
2025 prev = base;
2026 goto label_adjust_anchor;
2027 default: /* i.e. case 6 Mark-to-Mark */
2028 if (! mark)
2029 break;
2030 prev = mark;
2032 label_adjust_anchor:
2034 int base_x, base_y, mark_x, mark_y;
2035 int this_from, this_to;
2037 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2038 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2039 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2040 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2042 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2043 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2044 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2045 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2046 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2047 x_ppem, y_ppem, &mark_x, &mark_y);
2048 adjustment[i].xoff = (base_x - mark_x);
2049 adjustment[i].yoff = - (base_y - mark_y);
2050 adjustment[i].back = (g - prev);
2051 adjustment[i].xadv = 0;
2052 adjustment[i].advance_is_absolute = 1;
2053 adjustment[i].set = 1;
2054 this_from = g->from;
2055 this_to = g->to;
2056 for (j = 0; prev + j < g; j++)
2058 if (this_from > prev[j].from)
2059 this_from = prev[j].from;
2060 if (this_to < prev[j].to)
2061 this_to = prev[j].to;
2063 for (; prev <= g; prev++)
2065 prev->from = this_from;
2066 prev->to = this_to;
2070 if (otfg->GlyphClass == OTF_GlyphClass0)
2071 base = mark = g;
2072 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2073 mark = g;
2074 else
2075 base = g;
2078 else if (gpos_features)
2080 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2081 gpos_features) < 0)
2082 return to;
2083 features = otf->gpos->FeatureList.Feature;
2084 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2085 i++, otfg++)
2086 if (otfg->positioning_type & 0xF)
2088 int feature_idx = otfg->positioning_type >> 4;
2090 if (feature_idx)
2092 unsigned int tag = features[feature_idx - 1].FeatureTag;
2093 tag = PACK_OTF_TAG (tag);
2094 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2096 MFLTGlyph *g = in->glyphs + (from + j);
2097 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2102 return to;
2104 simple_copy:
2105 if (! out)
2106 return to;
2107 if (out->allocated < out->used + len)
2108 return -2;
2109 font->get_metrics (font, in, from, to);
2110 memcpy (out->glyphs + out->used, in->glyphs + from,
2111 sizeof (MFLTGlyph) * len);
2112 out->used += len;
2113 return to;
2116 static int
2117 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2118 MFLTGlyphString *in, int from, int to)
2120 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2123 #else /* not M17N_FLT_USE_NEW_FEATURE */
2125 static int
2126 ftfont_drive_otf (font, spec, in, from, to, out, adjustment)
2127 MFLTFont *font;
2128 MFLTOtfSpec *spec;
2129 MFLTGlyphString *in;
2130 int from, to;
2131 MFLTGlyphString *out;
2132 MFLTGlyphAdjustment *adjustment;
2134 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2135 FT_Face ft_face = flt_font_ft->ft_face;
2136 OTF *otf = flt_font_ft->otf;
2137 int len = to - from;
2138 int i, j, gidx;
2139 OTF_Glyph *otfg;
2140 char script[5], *langsys = NULL;
2141 char *gsub_features = NULL, *gpos_features = NULL;
2143 if (len == 0)
2144 return from;
2145 OTF_tag_name (spec->script, script);
2146 if (spec->langsys)
2148 langsys = alloca (5);
2149 OTF_tag_name (spec->langsys, langsys);
2151 for (i = 0; i < 2; i++)
2153 char *p;
2155 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2157 for (j = 0; spec->features[i][j]; j++);
2158 if (i == 0)
2159 p = gsub_features = alloca (6 * j);
2160 else
2161 p = gpos_features = alloca (6 * j);
2162 for (j = 0; spec->features[i][j]; j++)
2164 if (spec->features[i][j] == 0xFFFFFFFF)
2165 *p++ = '*', *p++ = ',';
2166 else
2168 OTF_tag_name (spec->features[i][j], p);
2169 p[4] = ',';
2170 p += 5;
2173 *--p = '\0';
2177 setup_otf_gstring (len);
2178 for (i = 0; i < len; i++)
2180 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2181 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2184 OTF_drive_gdef (otf, &otf_gstring);
2185 gidx = out->used;
2187 if (gsub_features)
2189 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2190 < 0)
2191 goto simple_copy;
2192 if (out->allocated < out->used + otf_gstring.used)
2193 return -2;
2194 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2196 MFLTGlyph *g;
2197 int min_from, max_to;
2198 int j;
2200 g = out->glyphs + out->used;
2201 *g = in->glyphs[from + otfg->f.index.from];
2202 if (g->code != otfg->glyph_id)
2204 g->c = 0;
2205 g->code = otfg->glyph_id;
2206 g->measured = 0;
2208 out->used++;
2209 min_from = g->from;
2210 max_to = g->to;
2211 if (otfg->f.index.from < otfg->f.index.to)
2213 /* OTFG substitutes multiple glyphs in IN. */
2214 for (j = from + otfg->f.index.from + 1;
2215 j <= from + otfg->f.index.to; j++)
2217 if (min_from > in->glyphs[j].from)
2218 min_from = in->glyphs[j].from;
2219 if (max_to < in->glyphs[j].to)
2220 max_to = in->glyphs[j].to;
2222 g->from = min_from;
2223 g->to = max_to;
2225 for (i++, otfg++; (i < otf_gstring.used
2226 && otfg->f.index.from == otfg[-1].f.index.from);
2227 i++, otfg++)
2229 g = out->glyphs + out->used;
2230 *g = in->glyphs[from + otfg->f.index.to];
2231 if (g->code != otfg->glyph_id)
2233 g->c = 0;
2234 g->code = otfg->glyph_id;
2235 g->measured = 0;
2237 out->used++;
2241 else
2243 if (out->allocated < out->used + len)
2244 return -2;
2245 for (i = 0; i < len; i++)
2246 out->glyphs[out->used++] = in->glyphs[from + i];
2249 if (gpos_features)
2251 MFLTGlyph *base = NULL, *mark = NULL, *g;
2252 int x_ppem, y_ppem, x_scale, y_scale;
2254 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2255 < 0)
2256 return to;
2258 x_ppem = ft_face->size->metrics.x_ppem;
2259 y_ppem = ft_face->size->metrics.y_ppem;
2260 x_scale = ft_face->size->metrics.x_scale;
2261 y_scale = ft_face->size->metrics.y_scale;
2263 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2264 i < otf_gstring.used; i++, otfg++, g++)
2266 MFLTGlyph *prev;
2268 if (! otfg->glyph_id)
2269 continue;
2270 switch (otfg->positioning_type)
2272 case 0:
2273 break;
2274 case 1: /* Single */
2275 case 2: /* Pair */
2277 int format = otfg->f.f1.format;
2279 if (format & OTF_XPlacement)
2280 adjustment[i].xoff
2281 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2282 if (format & OTF_XPlaDevice)
2283 adjustment[i].xoff
2284 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2285 if (format & OTF_YPlacement)
2286 adjustment[i].yoff
2287 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2288 if (format & OTF_YPlaDevice)
2289 adjustment[i].yoff
2290 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2291 if (format & OTF_XAdvance)
2292 adjustment[i].xadv
2293 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2294 if (format & OTF_XAdvDevice)
2295 adjustment[i].xadv
2296 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2297 if (format & OTF_YAdvance)
2298 adjustment[i].yadv
2299 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2300 if (format & OTF_YAdvDevice)
2301 adjustment[i].yadv
2302 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2303 adjustment[i].set = 1;
2305 break;
2306 case 3: /* Cursive */
2307 /* Not yet supported. */
2308 break;
2309 case 4: /* Mark-to-Base */
2310 case 5: /* Mark-to-Ligature */
2311 if (! base)
2312 break;
2313 prev = base;
2314 goto label_adjust_anchor;
2315 default: /* i.e. case 6 Mark-to-Mark */
2316 if (! mark)
2317 break;
2318 prev = mark;
2320 label_adjust_anchor:
2322 int base_x, base_y, mark_x, mark_y;
2323 int this_from, this_to;
2325 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2326 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2327 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2328 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2330 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2331 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2332 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2333 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2334 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2335 x_ppem, y_ppem, &mark_x, &mark_y);
2336 adjustment[i].xoff = (base_x - mark_x);
2337 adjustment[i].yoff = - (base_y - mark_y);
2338 adjustment[i].back = (g - prev);
2339 adjustment[i].xadv = 0;
2340 adjustment[i].advance_is_absolute = 1;
2341 adjustment[i].set = 1;
2342 this_from = g->from;
2343 this_to = g->to;
2344 for (j = 0; prev + j < g; j++)
2346 if (this_from > prev[j].from)
2347 this_from = prev[j].from;
2348 if (this_to < prev[j].to)
2349 this_to = prev[j].to;
2351 for (; prev <= g; prev++)
2353 prev->from = this_from;
2354 prev->to = this_to;
2358 if (otfg->GlyphClass == OTF_GlyphClass0)
2359 base = mark = g;
2360 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2361 mark = g;
2362 else
2363 base = g;
2366 return to;
2368 simple_copy:
2369 if (out->allocated < out->used + len)
2370 return -2;
2371 font->get_metrics (font, in, from, to);
2372 memcpy (out->glyphs + out->used, in->glyphs + from,
2373 sizeof (MFLTGlyph) * len);
2374 out->used += len;
2375 return to;
2378 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2380 static MFLTGlyphString gstring;
2382 static int m17n_flt_initialized;
2384 extern Lisp_Object QCfamily;
2386 static Lisp_Object
2387 ftfont_shape_by_flt (lgstring, font, ft_face, otf, matrix)
2388 Lisp_Object lgstring;
2389 struct font *font;
2390 FT_Face ft_face;
2391 OTF *otf;
2392 FT_Matrix *matrix;
2394 EMACS_UINT len = LGSTRING_GLYPH_LEN (lgstring);
2395 EMACS_UINT i;
2396 struct MFLTFontFT flt_font_ft;
2397 MFLT *flt = NULL;
2398 int with_variation_selector = 0;
2400 if (! m17n_flt_initialized)
2402 M17N_INIT ();
2403 #ifdef M17N_FLT_USE_NEW_FEATURE
2404 mflt_enable_new_feature = 1;
2405 mflt_try_otf = ftfont_try_otf;
2406 #endif /* M17N_FLT_USE_NEW_FEATURE */
2407 m17n_flt_initialized = 1;
2410 for (i = 0; i < len; i++)
2412 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2413 int c;
2415 if (NILP (g))
2416 break;
2417 c = LGLYPH_CHAR (g);
2418 if (CHAR_VARIATION_SELECTOR_P (c))
2419 with_variation_selector++;
2421 len = i;
2422 if (with_variation_selector)
2424 setup_otf_gstring (len);
2425 for (i = 0; i < len; i++)
2427 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2429 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2430 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2431 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2433 OTF_drive_cmap (otf, &otf_gstring);
2434 for (i = 0; i < otf_gstring.used; i++)
2436 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2437 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2438 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2440 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2441 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2442 LGSTRING_SET_GLYPH (lgstring, i, g0);
2444 if (len > otf_gstring.used)
2446 len = otf_gstring.used;
2447 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2451 if (gstring.allocated == 0)
2453 gstring.allocated = len * 2;
2454 gstring.glyph_size = sizeof (MFLTGlyph);
2455 gstring.glyphs = xmalloc (sizeof (MFLTGlyph) * gstring.allocated);
2457 else if (gstring.allocated < len * 2)
2459 gstring.allocated = len * 2;
2460 gstring.glyphs = xrealloc (gstring.glyphs,
2461 sizeof (MFLTGlyph) * gstring.allocated);
2463 memset (gstring.glyphs, 0, sizeof (MFLTGlyph) * len);
2464 for (i = 0; i < len; i++)
2466 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2468 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2469 if (with_variation_selector)
2471 gstring.glyphs[i].code = LGLYPH_CODE (g);
2472 gstring.glyphs[i].encoded = 1;
2476 gstring.used = len;
2477 gstring.r2l = 0;
2480 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2482 if (NILP (family))
2483 flt_font_ft.flt_font.family = Mnil;
2484 else
2485 flt_font_ft.flt_font.family
2486 = msymbol ((char *) SDATA (Fdowncase (SYMBOL_NAME (family))));
2488 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2489 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2490 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2491 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2492 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2493 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2494 flt_font_ft.flt_font.internal = NULL;
2495 flt_font_ft.font = font;
2496 flt_font_ft.ft_face = ft_face;
2497 flt_font_ft.otf = otf;
2498 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2499 if (len > 1
2500 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2501 /* A little bit ad hoc. Perhaps, shaper must get script and
2502 language information, and select a proper flt for them
2503 here. */
2504 flt = mflt_get (msymbol ("combining"));
2505 for (i = 0; i < 3; i++)
2507 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2508 if (result != -2)
2509 break;
2510 gstring.allocated += gstring.allocated;
2511 gstring.glyphs = xrealloc (gstring.glyphs,
2512 sizeof (MFLTGlyph) * gstring.allocated);
2514 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2515 return Qnil;
2516 for (i = 0; i < gstring.used; i++)
2518 MFLTGlyph *g = gstring.glyphs + i;
2520 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2521 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2524 for (i = 0; i < gstring.used; i++)
2526 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2527 MFLTGlyph *g = gstring.glyphs + i;
2529 if (NILP (lglyph))
2531 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2532 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2534 LGLYPH_SET_FROM (lglyph, g->from);
2535 LGLYPH_SET_TO (lglyph, g->to);
2536 LGLYPH_SET_CHAR (lglyph, g->c);
2537 LGLYPH_SET_CODE (lglyph, g->code);
2538 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2539 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2540 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2541 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2542 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2543 if (g->adjusted)
2545 Lisp_Object vec;
2547 vec = Fmake_vector (make_number (3), Qnil);
2548 ASET (vec, 0, make_number (g->xoff >> 6));
2549 ASET (vec, 1, make_number (g->yoff >> 6));
2550 ASET (vec, 2, make_number (g->xadv >> 6));
2551 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2554 return make_number (i);
2557 Lisp_Object
2558 ftfont_shape (lgstring)
2559 Lisp_Object lgstring;
2561 struct font *font;
2562 struct ftfont_info *ftfont_info;
2563 OTF *otf;
2565 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2566 ftfont_info = (struct ftfont_info *) font;
2567 otf = ftfont_get_otf (ftfont_info);
2568 if (! otf)
2569 return make_number (0);
2570 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2571 &ftfont_info->matrix);
2574 #endif /* HAVE_M17N_FLT */
2576 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2578 static int
2579 ftfont_variation_glyphs (font, c, variations)
2580 struct font *font;
2581 int c;
2582 unsigned variations[256];
2584 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2585 OTF *otf = ftfont_get_otf (ftfont_info);
2587 if (! otf)
2588 return 0;
2589 return OTF_get_variation_glyphs (otf, c, variations);
2592 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2593 #endif /* HAVE_LIBOTF */
2595 Lisp_Object
2596 ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
2598 FcChar8 *str;
2600 #ifdef FC_FONTFORMAT
2601 if (pattern)
2603 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2604 return Qnil;
2605 if (strcmp ((char *) str, "TrueType") == 0)
2606 return intern ("truetype");
2607 if (strcmp ((char *) str, "Type 1") == 0)
2608 return intern ("type1");
2609 if (strcmp ((char *) str, "PCF") == 0)
2610 return intern ("pcf");
2611 if (strcmp ((char *) str, "BDF") == 0)
2612 return intern ("bdf");
2614 #endif /* FC_FONTFORMAT */
2615 if (STRINGP (filename))
2617 int len = SBYTES (filename);
2619 if (len >= 4)
2621 str = (FcChar8 *) (SDATA (filename) + len - 4);
2622 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2623 return intern ("truetype");
2624 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2625 return intern ("type1");
2626 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2627 return intern ("pcf");
2628 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2629 return intern ("bdf");
2632 return intern ("unknown");
2635 static const char *ftfont_booleans [] = {
2636 ":antialias",
2637 ":hinting",
2638 ":verticallayout",
2639 ":autohint",
2640 ":globaladvance",
2641 ":outline",
2642 ":scalable",
2643 ":minspace",
2644 ":embolden",
2645 NULL,
2648 static const char *ftfont_non_booleans [] = {
2649 ":family",
2650 ":familylang",
2651 ":style",
2652 ":stylelang",
2653 ":fullname",
2654 ":fullnamelang",
2655 ":slant",
2656 ":weight",
2657 ":size",
2658 ":width",
2659 ":aspect",
2660 ":pixelsize",
2661 ":spacing",
2662 ":foundry",
2663 ":hintstyle",
2664 ":file",
2665 ":index",
2666 ":ftface",
2667 ":rasterizer",
2668 ":scale",
2669 ":dpi",
2670 ":rgba",
2671 ":lcdfilter",
2672 ":charset",
2673 ":lang",
2674 ":fontversion",
2675 ":capability",
2676 NULL,
2679 static void
2680 ftfont_filter_properties (font, alist)
2681 Lisp_Object font;
2682 Lisp_Object alist;
2684 Lisp_Object it;
2685 int i;
2687 /* Set boolean values to Qt or Qnil */
2688 for (i = 0; ftfont_booleans[i] != NULL; ++i)
2689 for (it = alist; ! NILP (it); it = XCDR (it))
2691 Lisp_Object key = XCAR (XCAR (it));
2692 Lisp_Object val = XCDR (XCAR (it));
2693 char *keystr = SDATA (SYMBOL_NAME (key));
2695 if (strcmp (ftfont_booleans[i], keystr) == 0)
2697 char *str = SYMBOLP (val) ? SDATA (SYMBOL_NAME (val)) : NULL;
2698 if (INTEGERP (val)) str = XINT (val) != 0 ? "true" : "false";
2699 if (str == NULL) str = "true";
2701 val = Qt;
2702 if (strcmp ("false", str) == 0 || strcmp ("False", str) == 0
2703 || strcmp ("FALSE", str) == 0 || strcmp ("FcFalse", str) == 0
2704 || strcmp ("off", str) == 0 || strcmp ("OFF", str) == 0
2705 || strcmp ("Off", str) == 0)
2706 val = Qnil;
2707 Ffont_put (font, key, val);
2711 for (i = 0; ftfont_non_booleans[i] != NULL; ++i)
2712 for (it = alist; ! NILP (it); it = XCDR (it))
2714 Lisp_Object key = XCAR (XCAR (it));
2715 Lisp_Object val = XCDR (XCAR (it));
2716 char *keystr = SDATA (SYMBOL_NAME (key));
2717 if (strcmp (ftfont_non_booleans[i], keystr) == 0)
2718 Ffont_put (font, key, val);
2723 void
2724 syms_of_ftfont ()
2726 DEFSYM (Qfreetype, "freetype");
2727 DEFSYM (Qmonospace, "monospace");
2728 DEFSYM (Qsans_serif, "sans-serif");
2729 DEFSYM (Qserif, "serif");
2730 DEFSYM (Qmono, "mono");
2731 DEFSYM (Qsans, "sans");
2732 DEFSYM (Qsans__serif, "sans serif");
2734 staticpro (&freetype_font_cache);
2735 freetype_font_cache = Fcons (Qt, Qnil);
2737 staticpro (&ftfont_generic_family_list);
2738 ftfont_generic_family_list
2739 = Fcons (Fcons (Qmonospace, Qt),
2740 Fcons (Fcons (Qsans_serif, Qt),
2741 Fcons (Fcons (Qsans, Qt), Qnil)));
2743 staticpro (&ft_face_cache);
2744 ft_face_cache = Qnil;
2746 ftfont_driver.type = Qfreetype;
2747 register_font_driver (&ftfont_driver, NULL);
2750 /* arch-tag: 7cfa432c-33a6-4988-83d2-a82ed8604aca
2751 (do not change this comment) */