* doc/misc/url.texi (Disk Caching): Tweak previous change.
[emacs.git] / src / ftfont.c
blob97bf265a84cdd4e45697aaa8cd4d8c7db69e383f
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 (FcPattern *, Lisp_Object);
85 static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
86 FcPattern *);
87 static Lisp_Object ftfont_lookup_cache (Lisp_Object,
88 enum ftfont_cache_for);
90 static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
92 Lisp_Object ftfont_font_format (FcPattern *, Lisp_Object);
94 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
96 static struct
98 /* registry name */
99 const char *name;
100 /* characters to distinguish the charset from the others */
101 int uniquifier[6];
102 /* additional constraint by language */
103 const 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 /* Dirty hack for handing ADSTYLE property.
149 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
150 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
151 "Oblique", "Italic", or any non-normal SWIDTH property names
152 (e.g. SemiCondensed) are appended. In addition, if there's no
153 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
154 "Regular" is used for FC_STYLE (see the function
155 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
157 Unfortunately this behavior is not documented, so the following
158 code may fail if FreeType changes the behavior in the future. */
160 static Lisp_Object
161 get_adstyle_property (FcPattern *p)
163 char *str, *end;
164 Lisp_Object adstyle;
166 if (FcPatternGetString (p, FC_STYLE, 0, (FcChar8 **) &str) != FcResultMatch)
167 return Qnil;
168 for (end = str; *end && *end != ' '; end++);
169 if (*end)
171 char *p = alloca (end - str + 1);
172 memcpy (p, str, end - str);
173 p[end - str] = '\0';
174 end = p + (end - str);
175 str = p;
177 if (xstrcasecmp (str, "Regular") == 0
178 || xstrcasecmp (str, "Bold") == 0
179 || xstrcasecmp (str, "Oblique") == 0
180 || xstrcasecmp (str, "Italic") == 0)
181 return Qnil;
182 adstyle = font_intern_prop (str, end - str, 1);
183 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
184 return Qnil;
185 return adstyle;
188 static Lisp_Object
189 ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
191 Lisp_Object key, cache, entity;
192 char *file, *str;
193 int index;
194 int numeric;
195 double dbl;
196 FcBool b;
198 if (FcPatternGetString (p, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch)
199 return Qnil;
200 if (FcPatternGetInteger (p, FC_INDEX, 0, &index) != FcResultMatch)
201 return Qnil;
203 key = Fcons (make_unibyte_string ((char *) file, strlen ((char *) file)),
204 make_number (index));
205 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
206 entity = XCAR (cache);
207 if (! NILP (entity))
209 Lisp_Object val = font_make_entity ();
210 int i;
212 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
213 ASET (val, i, AREF (entity, i));
214 return val;
216 entity = font_make_entity ();
217 XSETCAR (cache, entity);
219 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
220 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
222 if (FcPatternGetString (p, FC_FOUNDRY, 0, (FcChar8 **) &str) == FcResultMatch)
223 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (str, strlen (str), 1));
224 if (FcPatternGetString (p, FC_FAMILY, 0, (FcChar8 **) &str) == FcResultMatch)
225 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (str, strlen (str), 1));
226 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
228 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
229 numeric = FC_WEIGHT_MEDIUM;
230 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
232 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
234 numeric += 100;
235 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
237 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
239 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
241 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
243 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
245 else
246 ASET (entity, FONT_SIZE_INDEX, make_number (0));
247 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
248 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
249 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
251 int dpi = dbl;
252 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
254 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
255 && b == FcTrue)
257 ASET (entity, FONT_SIZE_INDEX, make_number (0));
258 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
260 else
262 /* As this font is not scalable, parhaps this is a BDF or PCF
263 font. */
264 FT_Face ft_face;
266 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
267 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
268 && FT_New_Face (ft_library, file, index, &ft_face) == 0)
270 BDF_PropertyRec rec;
272 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
273 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
274 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
275 FT_Done_Face (ft_face);
279 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
280 font_put_extra (entity, QCfont_entity, key);
281 return entity;
285 static Lisp_Object ftfont_generic_family_list;
287 static Lisp_Object
288 ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
290 Lisp_Object slot;
291 FcPattern *match;
292 FcResult result;
293 FcLangSet *langset;
295 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
296 if (EQ (family, Qmono))
297 family = Qmonospace;
298 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
299 family = Qsans_serif;
300 slot = assq_no_quit (family, ftfont_generic_family_list);
301 if (! CONSP (slot))
302 return Qnil;
303 if (! EQ (XCDR (slot), Qt))
304 return XCDR (slot);
305 pattern = FcPatternDuplicate (pattern);
306 if (! pattern)
307 goto err;
308 FcPatternDel (pattern, FC_FOUNDRY);
309 FcPatternDel (pattern, FC_FAMILY);
310 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
311 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
313 /* This is to avoid the effect of locale. */
314 langset = FcLangSetCreate ();
315 FcLangSetAdd (langset, "en");
316 FcPatternAddLangSet (pattern, FC_LANG, langset);
317 FcLangSetDestroy (langset);
319 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
320 FcDefaultSubstitute (pattern);
321 match = FcFontMatch (NULL, pattern, &result);
322 if (match)
324 FcChar8 *fam;
326 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
327 family = intern ((char *) fam);
329 else
330 family = Qnil;
331 XSETCDR (slot, family);
332 if (match) FcPatternDestroy (match);
333 err:
334 if (pattern) FcPatternDestroy (pattern);
335 return family;
338 struct ftfont_cache_data
340 FT_Face ft_face;
341 FcCharSet *fc_charset;
344 static Lisp_Object
345 ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
347 Lisp_Object cache, val, entity;
348 struct ftfont_cache_data *cache_data;
350 if (FONT_ENTITY_P (key))
352 entity = key;
353 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
354 xassert (CONSP (val));
355 key = XCDR (val);
357 else
358 entity = Qnil;
360 if (NILP (ft_face_cache))
361 cache = Qnil;
362 else
363 cache = Fgethash (key, ft_face_cache, Qnil);
364 if (NILP (cache))
366 if (NILP (ft_face_cache))
368 Lisp_Object args[2];
370 args[0] = QCtest;
371 args[1] = Qequal;
372 ft_face_cache = Fmake_hash_table (2, args);
374 cache_data = xmalloc (sizeof (struct ftfont_cache_data));
375 cache_data->ft_face = NULL;
376 cache_data->fc_charset = NULL;
377 val = make_save_value (NULL, 0);
378 XSAVE_VALUE (val)->integer = 0;
379 XSAVE_VALUE (val)->pointer = cache_data;
380 cache = Fcons (Qnil, val);
381 Fputhash (key, cache, ft_face_cache);
383 else
385 val = XCDR (cache);
386 cache_data = XSAVE_VALUE (val)->pointer;
389 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
390 return cache;
392 if (cache_for == FTFONT_CACHE_FOR_FACE
393 ? ! cache_data->ft_face : ! cache_data->fc_charset)
395 char *filename = (char *) SDATA (XCAR (key));
396 int index = XINT (XCDR (key));
398 if (cache_for == FTFONT_CACHE_FOR_FACE)
400 if (! ft_library
401 && FT_Init_FreeType (&ft_library) != 0)
402 return Qnil;
403 if (FT_New_Face (ft_library, filename, index, &cache_data->ft_face)
404 != 0)
405 return Qnil;
407 else
409 FcPattern *pat = NULL;
410 FcFontSet *fontset = NULL;
411 FcObjectSet *objset = NULL;
412 FcCharSet *charset = NULL;
414 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
415 FC_INDEX, FcTypeInteger, index, NULL);
416 if (! pat)
417 goto finish;
418 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
419 if (! objset)
420 goto finish;
421 fontset = FcFontList (NULL, pat, objset);
422 if (! fontset)
423 goto finish;
424 if (fontset && fontset->nfont > 0
425 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
426 &charset)
427 == FcResultMatch))
428 cache_data->fc_charset = FcCharSetCopy (charset);
429 else
430 cache_data->fc_charset = FcCharSetCreate ();
432 finish:
433 if (fontset)
434 FcFontSetDestroy (fontset);
435 if (objset)
436 FcObjectSetDestroy (objset);
437 if (pat)
438 FcPatternDestroy (pat);
441 return cache;
444 FcCharSet *
445 ftfont_get_fc_charset (Lisp_Object entity)
447 Lisp_Object val, cache;
448 struct ftfont_cache_data *cache_data;
450 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
451 val = XCDR (cache);
452 cache_data = XSAVE_VALUE (val)->pointer;
453 return cache_data->fc_charset;
456 #ifdef HAVE_LIBOTF
457 static OTF *
458 ftfont_get_otf (struct ftfont_info *ftfont_info)
460 OTF *otf;
462 if (ftfont_info->otf)
463 return ftfont_info->otf;
464 if (! ftfont_info->maybe_otf)
465 return NULL;
466 otf = OTF_open_ft_face (ftfont_info->ft_size->face);
467 if (! otf || OTF_get_table (otf, "head") < 0)
469 if (otf)
470 OTF_close (otf);
471 ftfont_info->maybe_otf = 0;
472 return NULL;
474 ftfont_info->otf = otf;
475 return otf;
477 #endif /* HAVE_LIBOTF */
479 static Lisp_Object ftfont_get_cache (FRAME_PTR);
480 static Lisp_Object ftfont_list (Lisp_Object, Lisp_Object);
481 static Lisp_Object ftfont_match (Lisp_Object, Lisp_Object);
482 static Lisp_Object ftfont_list_family (Lisp_Object);
483 static Lisp_Object ftfont_open (FRAME_PTR, Lisp_Object, int);
484 static void ftfont_close (FRAME_PTR, struct font *);
485 static int ftfont_has_char (Lisp_Object, int);
486 static unsigned ftfont_encode_char (struct font *, int);
487 static int ftfont_text_extents (struct font *, unsigned *, int,
488 struct font_metrics *);
489 static int ftfont_get_bitmap (struct font *, unsigned,
490 struct font_bitmap *, int);
491 static int ftfont_anchor_point (struct font *, unsigned, int,
492 int *, int *);
493 static Lisp_Object ftfont_otf_capability (struct font *);
494 static Lisp_Object ftfont_shape (Lisp_Object);
496 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
497 static int ftfont_variation_glyphs (struct font *, int c,
498 unsigned variations[256]);
499 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
501 struct font_driver ftfont_driver =
503 0, /* Qfreetype */
504 0, /* case insensitive */
505 ftfont_get_cache,
506 ftfont_list,
507 ftfont_match,
508 ftfont_list_family,
509 NULL, /* free_entity */
510 ftfont_open,
511 ftfont_close,
512 /* We can't draw a text without device dependent functions. */
513 NULL, /* prepare_face */
514 NULL, /* done_face */
515 ftfont_has_char,
516 ftfont_encode_char,
517 ftfont_text_extents,
518 /* We can't draw a text without device dependent functions. */
519 NULL, /* draw */
520 ftfont_get_bitmap,
521 NULL, /* get_bitmap */
522 NULL, /* free_bitmap */
523 NULL, /* get_outline */
524 ftfont_anchor_point,
525 #ifdef HAVE_LIBOTF
526 ftfont_otf_capability,
527 #else /* not HAVE_LIBOTF */
528 NULL,
529 #endif /* not HAVE_LIBOTF */
530 NULL, /* otf_drive */
531 NULL, /* start_for_frame */
532 NULL, /* end_for_frame */
533 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
534 ftfont_shape,
535 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
536 NULL,
537 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
538 NULL, /* check */
540 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
541 ftfont_variation_glyphs,
542 #else
543 NULL,
544 #endif
546 ftfont_filter_properties, /* filter_properties */
549 static Lisp_Object
550 ftfont_get_cache (FRAME_PTR f)
552 return freetype_font_cache;
555 static int
556 ftfont_get_charset (Lisp_Object registry)
558 char *str = (char *) SDATA (SYMBOL_NAME (registry));
559 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
560 Lisp_Object regexp;
561 int i, j;
563 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
565 if (str[i] == '.')
566 re[j++] = '\\';
567 else if (str[i] == '*')
568 re[j++] = '.';
569 re[j] = str[i];
570 if (re[j] == '?')
571 re[j] = '.';
573 re[j] = '\0';
574 regexp = make_unibyte_string (re, j);
575 for (i = 0; fc_charset_table[i].name; i++)
576 if (fast_c_string_match_ignore_case (regexp, fc_charset_table[i].name) >= 0)
577 break;
578 if (! fc_charset_table[i].name)
579 return -1;
580 if (! fc_charset_table[i].fc_charset)
582 FcCharSet *charset = FcCharSetCreate ();
583 int *uniquifier = fc_charset_table[i].uniquifier;
585 if (! charset)
586 return -1;
587 for (j = 0; uniquifier[j]; j++)
588 if (! FcCharSetAddChar (charset, uniquifier[j]))
590 FcCharSetDestroy (charset);
591 return -1;
593 fc_charset_table[i].fc_charset = charset;
595 return i;
598 struct OpenTypeSpec
600 Lisp_Object script;
601 unsigned int script_tag, langsys_tag;
602 int nfeatures[2];
603 unsigned int *features[2];
606 #define OTF_SYM_TAG(SYM, TAG) \
607 do { \
608 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
609 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
610 } while (0)
612 #define OTF_TAG_STR(TAG, P) \
613 do { \
614 (P)[0] = (char) (TAG >> 24); \
615 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
616 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
617 (P)[3] = (char) (TAG & 0xFF); \
618 (P)[4] = '\0'; \
619 } while (0)
621 #define OTF_TAG_SYM(SYM, TAG) \
622 do { \
623 char str[5]; \
625 OTF_TAG_STR (TAG, str); \
626 (SYM) = font_intern_prop (str, 4, 1); \
627 } while (0)
630 static struct OpenTypeSpec *
631 ftfont_get_open_type_spec (Lisp_Object otf_spec)
633 struct OpenTypeSpec *spec = malloc (sizeof (struct OpenTypeSpec));
634 Lisp_Object val;
635 int i, j, negative;
637 if (! spec)
638 return NULL;
639 spec->script = XCAR (otf_spec);
640 if (! NILP (spec->script))
642 OTF_SYM_TAG (spec->script, spec->script_tag);
643 val = assq_no_quit (spec->script, Votf_script_alist);
644 if (CONSP (val) && SYMBOLP (XCDR (val)))
645 spec->script = XCDR (val);
646 else
647 spec->script = Qnil;
649 else
650 spec->script_tag = 0x44464C54; /* "DFLT" */
651 otf_spec = XCDR (otf_spec);
652 spec->langsys_tag = 0;
653 if (! NILP (otf_spec))
655 val = XCAR (otf_spec);
656 if (! NILP (val))
657 OTF_SYM_TAG (val, spec->langsys_tag);
658 otf_spec = XCDR (otf_spec);
660 spec->nfeatures[0] = spec->nfeatures[1] = 0;
661 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
663 Lisp_Object len;
665 val = XCAR (otf_spec);
666 if (NILP (val))
667 continue;
668 len = Flength (val);
669 spec->features[i] = malloc (sizeof (int) * XINT (len));
670 if (! spec->features[i])
672 if (i > 0 && spec->features[0])
673 free (spec->features[0]);
674 free (spec);
675 return NULL;
677 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
679 if (NILP (XCAR (val)))
680 negative = 1;
681 else
683 unsigned int tag;
685 OTF_SYM_TAG (XCAR (val), tag);
686 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
689 spec->nfeatures[i] = j;
691 return spec;
694 static FcPattern *
695 ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
697 Lisp_Object tmp, extra;
698 FcPattern *pattern = NULL;
699 FcCharSet *charset = NULL;
700 FcLangSet *langset = NULL;
701 int n;
702 int dpi = -1;
703 int scalable = -1;
704 Lisp_Object script = Qnil;
705 Lisp_Object registry;
706 int fc_charset_idx;
708 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
709 && n < 100)
710 /* Fontconfig doesn't support reverse-italic/obligue. */
711 return NULL;
713 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
714 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
715 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
716 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
717 scalable = 1;
719 registry = AREF (spec, FONT_REGISTRY_INDEX);
720 if (NILP (registry)
721 || EQ (registry, Qascii_0)
722 || EQ (registry, Qiso10646_1)
723 || EQ (registry, Qunicode_bmp))
724 fc_charset_idx = -1;
725 else
727 FcChar8 *lang;
729 fc_charset_idx = ftfont_get_charset (registry);
730 if (fc_charset_idx < 0)
731 return NULL;
732 charset = fc_charset_table[fc_charset_idx].fc_charset;
733 *langname = fc_charset_table[fc_charset_idx].lang;
734 lang = (FcChar8 *) *langname;
735 if (lang)
737 langset = FcLangSetCreate ();
738 if (! langset)
739 goto err;
740 FcLangSetAdd (langset, lang);
744 otlayout[0] = '\0';
745 for (extra = AREF (spec, FONT_EXTRA_INDEX);
746 CONSP (extra); extra = XCDR (extra))
748 Lisp_Object key, val;
750 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
751 if (EQ (key, QCdpi))
752 dpi = XINT (val);
753 else if (EQ (key, QClang))
755 if (! langset)
756 langset = FcLangSetCreate ();
757 if (! langset)
758 goto err;
759 if (SYMBOLP (val))
761 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
762 goto err;
764 else
765 for (; CONSP (val); val = XCDR (val))
766 if (SYMBOLP (XCAR (val))
767 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
768 goto err;
770 else if (EQ (key, QCotf))
772 *otspec = ftfont_get_open_type_spec (val);
773 if (! *otspec)
774 return NULL;
775 strcat (otlayout, "otlayout:");
776 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
777 script = (*otspec)->script;
779 else if (EQ (key, QCscript))
780 script = val;
781 else if (EQ (key, QCscalable))
782 scalable = ! NILP (val);
785 if (! NILP (script) && ! charset)
787 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
789 if (CONSP (chars) && CONSP (CDR (chars)))
791 charset = FcCharSetCreate ();
792 if (! charset)
793 goto err;
794 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
795 if (CHARACTERP (XCAR (chars))
796 && ! FcCharSetAddChar (charset, XUINT (XCAR (chars))))
797 goto err;
801 pattern = FcPatternCreate ();
802 if (! pattern)
803 goto err;
804 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
805 if (! NILP (tmp)
806 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
807 goto err;
808 tmp = AREF (spec, FONT_FAMILY_INDEX);
809 if (! NILP (tmp)
810 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
811 goto err;
812 if (charset
813 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
814 goto err;
815 if (langset
816 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
817 goto err;
818 if (dpi >= 0
819 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
820 goto err;
821 if (scalable >= 0
822 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
823 goto err;
825 goto finish;
827 err:
828 /* We come here because of unexpected error in fontconfig API call
829 (usually insufficient memory). */
830 if (pattern)
832 FcPatternDestroy (pattern);
833 pattern = NULL;
835 if (*otspec)
837 if ((*otspec)->nfeatures[0] > 0)
838 free ((*otspec)->features[0]);
839 if ((*otspec)->nfeatures[1] > 0)
840 free ((*otspec)->features[1]);
841 free (*otspec);
842 *otspec = NULL;
845 finish:
846 if (langset) FcLangSetDestroy (langset);
847 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
848 return pattern;
851 static Lisp_Object
852 ftfont_list (Lisp_Object frame, Lisp_Object spec)
854 Lisp_Object val = Qnil, family, adstyle;
855 int i;
856 FcPattern *pattern;
857 FcFontSet *fontset = NULL;
858 FcObjectSet *objset = NULL;
859 FcCharSet *charset;
860 Lisp_Object chars = Qnil;
861 FcResult result;
862 char otlayout[15]; /* For "otlayout:XXXX" */
863 struct OpenTypeSpec *otspec = NULL;
864 int spacing = -1;
865 const char *langname = NULL;
867 if (! fc_initialized)
869 FcInit ();
870 fc_initialized = 1;
873 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
874 if (! pattern)
875 return Qnil;
876 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
878 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
879 if (! NILP (val))
881 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
882 if (CONSP (val) && VECTORP (XCDR (val)))
883 chars = XCDR (val);
885 val = Qnil;
887 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
888 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
889 family = AREF (spec, FONT_FAMILY_INDEX);
890 if (! NILP (family))
892 Lisp_Object resolved;
894 resolved = ftfont_resolve_generic_family (family, pattern);
895 if (! NILP (resolved))
897 FcPatternDel (pattern, FC_FAMILY);
898 if (! FcPatternAddString (pattern, FC_FAMILY,
899 SYMBOL_FcChar8 (resolved)))
900 goto err;
903 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
904 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
905 adstyle = Qnil;
906 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
907 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
908 FC_STYLE, FC_FILE, FC_INDEX,
909 #ifdef FC_CAPABILITY
910 FC_CAPABILITY,
911 #endif /* FC_CAPABILITY */
912 #ifdef FC_FONTFORMAT
913 FC_FONTFORMAT,
914 #endif
915 NULL);
916 if (! objset)
917 goto err;
918 if (! NILP (chars))
919 FcObjectSetAdd (objset, FC_CHARSET);
921 fontset = FcFontList (NULL, pattern, objset);
922 if (! fontset || fontset->nfont == 0)
923 goto finish;
924 #if 0
925 /* Need fix because this finds any fonts. */
926 if (fontset->nfont == 0 && ! NILP (family))
928 /* Try maching with configuration. For instance, the
929 configuration may specify "Nimbus Mono L" as an alias of
930 "Courier". */
931 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
932 SYMBOL_FcChar8 (family), NULL);
933 FcChar8 *fam;
935 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
937 for (i = 0;
938 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
939 i++)
941 FcPatternDel (pattern, FC_FAMILY);
942 FcPatternAddString (pattern, FC_FAMILY, fam);
943 FcFontSetDestroy (fontset);
944 fontset = FcFontList (NULL, pattern, objset);
945 if (fontset && fontset->nfont > 0)
946 break;
950 #endif
951 for (i = 0; i < fontset->nfont; i++)
953 Lisp_Object entity;
955 if (spacing >= 0)
957 int this;
959 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
960 == FcResultMatch)
961 && spacing != this)
962 continue;
965 #ifdef FC_CAPABILITY
966 if (otlayout[0])
968 FcChar8 *this;
970 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
971 != FcResultMatch
972 || ! strstr ((char *) this, otlayout))
973 continue;
975 #endif /* FC_CAPABILITY */
976 #ifdef HAVE_LIBOTF
977 if (otspec)
979 FcChar8 *file;
980 OTF *otf;
982 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
983 != FcResultMatch)
984 continue;
985 otf = OTF_open ((char *) file);
986 if (! otf)
987 continue;
988 if (OTF_check_features (otf, 1,
989 otspec->script_tag, otspec->langsys_tag,
990 otspec->features[0],
991 otspec->nfeatures[0]) != 1
992 || OTF_check_features (otf, 0,
993 otspec->script_tag, otspec->langsys_tag,
994 otspec->features[1],
995 otspec->nfeatures[1]) != 1)
996 continue;
998 #endif /* HAVE_LIBOTF */
999 if (VECTORP (chars))
1001 int j;
1003 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1004 != FcResultMatch)
1005 continue;
1006 for (j = 0; j < ASIZE (chars); j++)
1007 if (NATNUMP (AREF (chars, j))
1008 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1009 break;
1010 if (j == ASIZE (chars))
1011 continue;
1013 if (! NILP (adstyle) || langname)
1015 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1017 if (! NILP (adstyle)
1018 && (NILP (this_adstyle)
1019 || xstrcasecmp (SDATA (SYMBOL_NAME (adstyle)),
1020 SDATA (SYMBOL_NAME (this_adstyle))) != 0))
1021 continue;
1022 if (langname
1023 && ! NILP (this_adstyle)
1024 && xstrcasecmp (langname, SDATA (SYMBOL_NAME (this_adstyle))))
1025 continue;
1027 entity = ftfont_pattern_entity (fontset->fonts[i],
1028 AREF (spec, FONT_EXTRA_INDEX));
1029 if (! NILP (entity))
1030 val = Fcons (entity, val);
1032 val = Fnreverse (val);
1033 goto finish;
1035 err:
1036 /* We come here because of unexpected error in fontconfig API call
1037 (usually insufficient memory). */
1038 val = Qnil;
1040 finish:
1041 FONT_ADD_LOG ("ftfont-list", spec, val);
1042 if (objset) FcObjectSetDestroy (objset);
1043 if (fontset) FcFontSetDestroy (fontset);
1044 if (pattern) FcPatternDestroy (pattern);
1045 return val;
1048 static Lisp_Object
1049 ftfont_match (Lisp_Object frame, Lisp_Object spec)
1051 Lisp_Object entity = Qnil;
1052 FcPattern *pattern, *match = NULL;
1053 FcResult result;
1054 char otlayout[15]; /* For "otlayout:XXXX" */
1055 struct OpenTypeSpec *otspec = NULL;
1056 const char *langname = NULL;
1058 if (! fc_initialized)
1060 FcInit ();
1061 fc_initialized = 1;
1064 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
1065 if (! pattern)
1066 return Qnil;
1068 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
1070 FcValue value;
1072 value.type = FcTypeDouble;
1073 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1074 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1076 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1078 FcDefaultSubstitute (pattern);
1079 match = FcFontMatch (NULL, pattern, &result);
1080 if (match)
1082 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
1083 FcPatternDestroy (match);
1084 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1085 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1086 ftfont_generic_family_list))
1087 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1088 AREF (entity, FONT_FAMILY_INDEX))))
1089 entity = Qnil;
1092 FcPatternDestroy (pattern);
1094 FONT_ADD_LOG ("ftfont-match", spec, entity);
1095 return entity;
1098 static Lisp_Object
1099 ftfont_list_family (Lisp_Object frame)
1101 Lisp_Object list = Qnil;
1102 FcPattern *pattern = NULL;
1103 FcFontSet *fontset = NULL;
1104 FcObjectSet *objset = NULL;
1105 int i;
1107 if (! fc_initialized)
1109 FcInit ();
1110 fc_initialized = 1;
1113 pattern = FcPatternCreate ();
1114 if (! pattern)
1115 goto finish;
1116 objset = FcObjectSetBuild (FC_FAMILY, NULL);
1117 if (! objset)
1118 goto finish;
1119 fontset = FcFontList (NULL, pattern, objset);
1120 if (! fontset)
1121 goto finish;
1123 for (i = 0; i < fontset->nfont; i++)
1125 FcPattern *pat = fontset->fonts[i];
1126 FcChar8 *str;
1128 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1129 list = Fcons (intern ((char *) str), list);
1132 finish:
1133 if (objset) FcObjectSetDestroy (objset);
1134 if (fontset) FcFontSetDestroy (fontset);
1135 if (pattern) FcPatternDestroy (pattern);
1137 return list;
1141 static Lisp_Object
1142 ftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
1144 struct ftfont_info *ftfont_info;
1145 struct font *font;
1146 struct ftfont_cache_data *cache_data;
1147 FT_Face ft_face;
1148 FT_Size ft_size;
1149 FT_UInt size;
1150 Lisp_Object val, filename, index, cache, font_object;
1151 int scalable;
1152 int spacing;
1153 char name[256];
1154 int i, len;
1155 int upEM;
1157 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1158 if (! CONSP (val))
1159 return Qnil;
1160 val = XCDR (val);
1161 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
1162 if (NILP (cache))
1163 return Qnil;
1164 filename = XCAR (val);
1165 index = XCDR (val);
1166 val = XCDR (cache);
1167 cache_data = XSAVE_VALUE (XCDR (cache))->pointer;
1168 ft_face = cache_data->ft_face;
1169 if (XSAVE_VALUE (val)->integer > 0)
1171 /* FT_Face in this cache is already used by the different size. */
1172 if (FT_New_Size (ft_face, &ft_size) != 0)
1173 return Qnil;
1174 if (FT_Activate_Size (ft_size) != 0)
1176 FT_Done_Size (ft_size);
1177 return Qnil;
1180 XSAVE_VALUE (val)->integer++;
1181 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1182 if (size == 0)
1183 size = pixel_size;
1184 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1186 if (XSAVE_VALUE (val)->integer == 0)
1187 FT_Done_Face (ft_face);
1188 return Qnil;
1191 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
1192 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
1193 len = font_unparse_xlfd (entity, size, name, 256);
1194 if (len > 0)
1195 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
1196 len = font_unparse_fcname (entity, size, name, 256);
1197 if (len > 0)
1198 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
1199 else
1200 ASET (font_object, FONT_FULLNAME_INDEX,
1201 AREF (font_object, FONT_NAME_INDEX));
1202 ASET (font_object, FONT_FILE_INDEX, filename);
1203 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
1204 font = XFONT_OBJECT (font_object);
1205 ftfont_info = (struct ftfont_info *) font;
1206 ftfont_info->ft_size = ft_face->size;
1207 ftfont_info->index = XINT (index);
1208 #ifdef HAVE_LIBOTF
1209 ftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
1210 ftfont_info->otf = NULL;
1211 #endif /* HAVE_LIBOTF */
1212 /* This means that there's no need of transformation. */
1213 ftfont_info->matrix.xx = 0;
1214 font->pixel_size = size;
1215 font->driver = &ftfont_driver;
1216 font->encoding_charset = font->repertory_charset = -1;
1218 upEM = ft_face->units_per_EM;
1219 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1220 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
1221 if (scalable)
1223 font->ascent = ft_face->ascender * size / upEM;
1224 font->descent = - ft_face->descender * size / upEM;
1225 font->height = ft_face->height * size / upEM;
1227 else
1229 font->ascent = ft_face->size->metrics.ascender >> 6;
1230 font->descent = - ft_face->size->metrics.descender >> 6;
1231 font->height = ft_face->size->metrics.height >> 6;
1233 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1234 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1235 else
1236 spacing = FC_PROPORTIONAL;
1237 if (spacing != FC_PROPORTIONAL && spacing != FC_DUAL)
1238 font->min_width = font->average_width = font->space_width
1239 = (scalable ? ft_face->max_advance_width * size / upEM
1240 : ft_face->size->metrics.max_advance >> 6);
1241 else
1243 int n;
1245 font->min_width = font->average_width = font->space_width = 0;
1246 for (i = 32, n = 0; i < 127; i++)
1247 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
1249 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1251 if (this_width > 0
1252 && (! font->min_width || font->min_width > this_width))
1253 font->min_width = this_width;
1254 if (i == 32)
1255 font->space_width = this_width;
1256 font->average_width += this_width;
1257 n++;
1259 if (n > 0)
1260 font->average_width /= n;
1263 font->baseline_offset = 0;
1264 font->relative_compose = 0;
1265 font->default_ascent = 0;
1266 font->vertical_centering = 0;
1267 if (scalable)
1269 font->underline_position = -ft_face->underline_position * size / upEM;
1270 font->underline_thickness = ft_face->underline_thickness * size / upEM;
1272 else
1274 font->underline_position = -1;
1275 font->underline_thickness = 0;
1278 return font_object;
1281 static void
1282 ftfont_close (FRAME_PTR f, struct font *font)
1284 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1285 Lisp_Object val, cache;
1287 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
1288 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
1289 xassert (CONSP (cache));
1290 val = XCDR (cache);
1291 (XSAVE_VALUE (val)->integer)--;
1292 if (XSAVE_VALUE (val)->integer == 0)
1294 struct ftfont_cache_data *cache_data = XSAVE_VALUE (val)->pointer;
1296 FT_Done_Face (cache_data->ft_face);
1297 #ifdef HAVE_LIBOTF
1298 if (ftfont_info->otf)
1299 OTF_close (ftfont_info->otf);
1300 #endif
1301 cache_data->ft_face = NULL;
1303 else
1304 FT_Done_Size (ftfont_info->ft_size);
1307 static int
1308 ftfont_has_char (Lisp_Object font, int c)
1310 struct charset *cs = NULL;
1312 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1313 && charset_jisx0208 >= 0)
1314 cs = CHARSET_FROM_ID (charset_jisx0208);
1315 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1316 && charset_ksc5601 >= 0)
1317 cs = CHARSET_FROM_ID (charset_ksc5601);
1318 if (cs)
1319 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1321 if (FONT_ENTITY_P (font))
1323 FcCharSet *charset = ftfont_get_fc_charset (font);
1325 return (FcCharSetHasChar (charset, c) == FcTrue);
1327 else
1329 struct ftfont_info *ftfont_info;
1331 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1332 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1333 != 0);
1337 static unsigned
1338 ftfont_encode_char (struct font *font, int c)
1340 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1341 FT_Face ft_face = ftfont_info->ft_size->face;
1342 FT_ULong charcode = c;
1343 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1345 return (code > 0 ? code : FONT_INVALID_CODE);
1348 static int
1349 ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
1351 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1352 FT_Face ft_face = ftfont_info->ft_size->face;
1353 int width = 0;
1354 int i, first;
1356 if (ftfont_info->ft_size != ft_face->size)
1357 FT_Activate_Size (ftfont_info->ft_size);
1358 if (metrics)
1359 memset (metrics, 0, sizeof (struct font_metrics));
1360 for (i = 0, first = 1; i < nglyphs; i++)
1362 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1364 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1366 if (first)
1368 if (metrics)
1370 metrics->lbearing = m->horiBearingX >> 6;
1371 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1372 metrics->ascent = m->horiBearingY >> 6;
1373 metrics->descent = (m->height - m->horiBearingY) >> 6;
1375 first = 0;
1377 if (metrics)
1379 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1380 metrics->lbearing = width + (m->horiBearingX >> 6);
1381 if (metrics->rbearing
1382 < width + ((m->horiBearingX + m->width) >> 6))
1383 metrics->rbearing
1384 = width + ((m->horiBearingX + m->width) >> 6);
1385 if (metrics->ascent < (m->horiBearingY >> 6))
1386 metrics->ascent = m->horiBearingY >> 6;
1387 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1388 metrics->descent = (m->height - m->horiBearingY) >> 6;
1390 width += m->horiAdvance >> 6;
1392 else
1394 width += font->space_width;
1397 if (metrics)
1398 metrics->width = width;
1400 return width;
1403 static int
1404 ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
1406 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1407 FT_Face ft_face = ftfont_info->ft_size->face;
1408 FT_Int32 load_flags = FT_LOAD_RENDER;
1410 if (ftfont_info->ft_size != ft_face->size)
1411 FT_Activate_Size (ftfont_info->ft_size);
1412 if (bits_per_pixel == 1)
1414 #ifdef FT_LOAD_TARGET_MONO
1415 load_flags |= FT_LOAD_TARGET_MONO;
1416 #else
1417 load_flags |= FT_LOAD_MONOCHROME;
1418 #endif
1420 else if (bits_per_pixel != 8)
1421 /* We don't support such a rendering. */
1422 return -1;
1424 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1425 return -1;
1426 bitmap->bits_per_pixel
1427 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1428 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1429 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1430 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1431 : -1);
1432 if (bitmap->bits_per_pixel < 0)
1433 /* We don't suport that kind of pixel mode. */
1434 return -1;
1435 bitmap->rows = ft_face->glyph->bitmap.rows;
1436 bitmap->width = ft_face->glyph->bitmap.width;
1437 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1438 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1439 bitmap->left = ft_face->glyph->bitmap_left;
1440 bitmap->top = ft_face->glyph->bitmap_top;
1441 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1442 bitmap->extra = NULL;
1444 return 0;
1447 static int
1448 ftfont_anchor_point (struct font *font, unsigned int code, int index, int *x, int *y)
1450 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1451 FT_Face ft_face = ftfont_info->ft_size->face;
1453 if (ftfont_info->ft_size != ft_face->size)
1454 FT_Activate_Size (ftfont_info->ft_size);
1455 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1456 return -1;
1457 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1458 return -1;
1459 if (index >= ft_face->glyph->outline.n_points)
1460 return -1;
1461 *x = ft_face->glyph->outline.points[index].x;
1462 *y = ft_face->glyph->outline.points[index].y;
1463 return 0;
1466 #ifdef HAVE_LIBOTF
1468 static Lisp_Object
1469 ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
1471 Lisp_Object scripts, langsyses, features, sym;
1472 int i, j, k, l;
1474 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1476 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1478 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1480 OTF_LangSys *otf_langsys;
1482 if (j >= 0)
1483 otf_langsys = otf_script->LangSys + j;
1484 else if (otf_script->DefaultLangSysOffset)
1485 otf_langsys = &otf_script->DefaultLangSys;
1486 else
1487 break;
1489 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1491 l = otf_langsys->FeatureIndex[k];
1492 if (l >= gsub_gpos->FeatureList.FeatureCount)
1493 continue;
1494 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
1495 features = Fcons (sym, features);
1497 if (j >= 0)
1498 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1499 else
1500 sym = Qnil;
1501 langsyses = Fcons (Fcons (sym, features), langsyses);
1504 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1505 scripts = Fcons (Fcons (sym, langsyses), scripts);
1507 return scripts;
1512 static Lisp_Object
1513 ftfont_otf_capability (struct font *font)
1515 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1516 OTF *otf = ftfont_get_otf (ftfont_info);
1517 Lisp_Object gsub_gpos;
1519 if (! otf)
1520 return Qnil;
1521 gsub_gpos = Fcons (Qnil, Qnil);
1522 if (OTF_get_table (otf, "GSUB") == 0
1523 && otf->gsub->FeatureList.FeatureCount > 0)
1524 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
1525 if (OTF_get_table (otf, "GPOS") == 0
1526 && otf->gpos->FeatureList.FeatureCount > 0)
1527 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1528 return gsub_gpos;
1531 #ifdef HAVE_M17N_FLT
1533 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1534 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1535 /* We can use the new feature of libotf and m17n-flt to handle the
1536 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1537 some Agian scripts. */
1538 #define M17N_FLT_USE_NEW_FEATURE
1539 #endif
1541 struct MFLTFontFT
1543 MFLTFont flt_font;
1544 struct font *font;
1545 FT_Face ft_face;
1546 OTF *otf;
1547 FT_Matrix *matrix;
1550 static int
1551 ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1552 int from, int to)
1554 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1555 FT_Face ft_face = flt_font_ft->ft_face;
1556 MFLTGlyph *g;
1558 for (g = gstring->glyphs + from; from < to; g++, from++)
1559 if (! g->encoded)
1561 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1563 g->code = code > 0 ? code : FONT_INVALID_CODE;
1564 g->encoded = 1;
1566 return 0;
1569 /* Operators for 26.6 fixed fractional pixel format */
1571 #define FLOOR(x) ((x) & -64)
1572 #define CEIL(x) (((x)+63) & -64)
1573 #define ROUND(x) (((x)+32) & -64)
1575 static int
1576 ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1577 int from, int to)
1579 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1580 FT_Face ft_face = flt_font_ft->ft_face;
1581 MFLTGlyph *g;
1583 for (g = gstring->glyphs + from; from < to; g++, from++)
1584 if (! g->measured)
1586 if (g->code != FONT_INVALID_CODE)
1588 FT_Glyph_Metrics *m;
1589 int lbearing, rbearing, ascent, descent, xadv;
1591 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1592 abort ();
1593 m = &ft_face->glyph->metrics;
1594 if (flt_font_ft->matrix)
1596 FT_Vector v[4];
1597 int i;
1599 v[0].x = v[1].x = m->horiBearingX;
1600 v[2].x = v[3].x = m->horiBearingX + m->width;
1601 v[0].y = v[2].y = m->horiBearingY;
1602 v[1].y = v[3].y = m->horiBearingY - m->height;
1603 for (i = 0; i < 4; i++)
1604 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1605 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1606 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1607 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1608 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1610 else
1612 g->lbearing = FLOOR (m->horiBearingX);
1613 g->rbearing = CEIL (m->horiBearingX + m->width);
1614 g->ascent = CEIL (m->horiBearingY);
1615 g->descent = - FLOOR (m->horiBearingY - m->height);
1617 g->xadv = ROUND (ft_face->glyph->advance.x);
1619 else
1621 g->lbearing = 0;
1622 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
1623 g->ascent = flt_font_ft->font->ascent << 6;
1624 g->descent = flt_font_ft->font->descent << 6;
1626 g->yadv = 0;
1627 g->measured = 1;
1629 return 0;
1632 static int
1633 ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1635 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1637 #define FEATURE_ANY(IDX) \
1638 (spec->features[IDX] \
1639 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1641 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1642 OTF *otf = flt_font_ft->otf;
1643 OTF_Tag *tags;
1644 int i, n, negative;
1646 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1647 /* Return 1 iff any of GSUB or GPOS support the script (and language). */
1648 return (otf
1649 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1650 NULL, 0) > 0
1651 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1652 NULL, 0) > 0));
1654 for (i = 0; i < 2; i++)
1655 if (! FEATURE_ANY (i))
1657 if (FEATURE_NONE (i))
1659 if (otf
1660 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1661 NULL, 0) > 0)
1662 return 0;
1663 continue;
1665 if (spec->features[i][0] == 0xFFFFFFFF)
1667 if (! otf
1668 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1669 NULL, 0) <= 0)
1670 continue;
1672 else if (! otf)
1673 return 0;
1674 for (n = 1; spec->features[i][n]; n++);
1675 tags = alloca (sizeof (OTF_Tag) * n);
1676 for (n = 0, negative = 0; spec->features[i][n]; n++)
1678 if (spec->features[i][n] == 0xFFFFFFFF)
1679 negative = 1;
1680 else if (negative)
1681 tags[n - 1] = spec->features[i][n] | 0x80000000;
1682 else
1683 tags[n] = spec->features[i][n];
1685 #ifdef M17N_FLT_USE_NEW_FEATURE
1686 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1687 tags, n - negative) != 1)
1688 return 0;
1689 #else /* not M17N_FLT_USE_NEW_FEATURE */
1690 if (n - negative > 0
1691 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1692 tags, n - negative) != 1)
1693 return 0;
1694 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1696 return 1;
1697 #undef FEATURE_NONE
1698 #undef FEATURE_ANY
1701 #define DEVICE_DELTA(table, size) \
1702 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1703 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1704 : 0)
1706 static void
1707 adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1708 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1710 if (anchor->AnchorFormat == 2)
1712 FT_Outline *outline;
1713 int ap = anchor->f.f1.AnchorPoint;
1715 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1716 outline = &ft_face->glyph->outline;
1717 if (ap < outline->n_points)
1719 *x = outline->points[ap].x << 6;
1720 *y = outline->points[ap].y << 6;
1723 else if (anchor->AnchorFormat == 3)
1725 if (anchor->f.f2.XDeviceTable.offset
1726 && anchor->f.f2.XDeviceTable.DeltaValue)
1727 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1728 if (anchor->f.f2.YDeviceTable.offset
1729 && anchor->f.f2.YDeviceTable.DeltaValue)
1730 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1734 static OTF_GlyphString otf_gstring;
1736 static void
1737 setup_otf_gstring (int size)
1739 if (otf_gstring.size == 0)
1741 otf_gstring.glyphs = (OTF_Glyph *) xmalloc (sizeof (OTF_Glyph) * size);
1742 otf_gstring.size = size;
1744 else if (otf_gstring.size < size)
1746 otf_gstring.glyphs = xrealloc (otf_gstring.glyphs,
1747 sizeof (OTF_Glyph) * size);
1748 otf_gstring.size = size;
1750 otf_gstring.used = size;
1751 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1754 #ifdef M17N_FLT_USE_NEW_FEATURE
1756 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1757 #define PACK_OTF_TAG(TAG) \
1758 ((((TAG) & 0x7F000000) >> 3) \
1759 | (((TAG) & 0x7F0000) >> 2) \
1760 | (((TAG) & 0x7F00) >> 1) \
1761 | ((TAG) & 0x7F))
1763 /* Assuming that FONT is an OpenType font, apply OpenType features
1764 specified in SPEC on glyphs between FROM and TO of IN, and record
1765 the lastly applied feature in each glyph of IN. If OUT is not
1766 NULL, append the resulting glyphs to OUT while storing glyph
1767 position adjustment information in ADJUSTMENT. */
1769 static int
1770 ftfont_drive_otf (font, spec, in, from, to, out, adjustment)
1771 MFLTFont *font;
1772 MFLTOtfSpec *spec;
1773 MFLTGlyphString *in;
1774 int from, to;
1775 MFLTGlyphString *out;
1776 MFLTGlyphAdjustment *adjustment;
1778 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1779 FT_Face ft_face = flt_font_ft->ft_face;
1780 OTF *otf = flt_font_ft->otf;
1781 int len = to - from;
1782 int i, j, gidx;
1783 OTF_Glyph *otfg;
1784 char script[5], *langsys = NULL;
1785 char *gsub_features = NULL, *gpos_features = NULL;
1786 OTF_Feature *features;
1788 if (len == 0)
1789 return from;
1790 OTF_tag_name (spec->script, script);
1791 if (spec->langsys)
1793 langsys = alloca (5);
1794 OTF_tag_name (spec->langsys, langsys);
1796 for (i = 0; i < 2; i++)
1798 char *p;
1800 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1802 for (j = 0; spec->features[i][j]; j++);
1803 if (i == 0)
1804 p = gsub_features = alloca (6 * j);
1805 else
1806 p = gpos_features = alloca (6 * j);
1807 for (j = 0; spec->features[i][j]; j++)
1809 if (spec->features[i][j] == 0xFFFFFFFF)
1810 *p++ = '*', *p++ = ',';
1811 else
1813 OTF_tag_name (spec->features[i][j], p);
1814 p[4] = ',';
1815 p += 5;
1818 *--p = '\0';
1822 setup_otf_gstring (len);
1823 for (i = 0; i < len; i++)
1825 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
1826 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1829 OTF_drive_gdef (otf, &otf_gstring);
1830 gidx = out ? out->used : from;
1832 if (gsub_features && out)
1834 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1835 gsub_features) < 0)
1836 goto simple_copy;
1837 if (out->allocated < out->used + otf_gstring.used)
1838 return -2;
1839 features = otf->gsub->FeatureList.Feature;
1840 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1842 MFLTGlyph *g;
1843 int min_from, max_to;
1844 int j;
1845 int feature_idx = otfg->positioning_type >> 4;
1847 g = out->glyphs + out->used;
1848 *g = in->glyphs[from + otfg->f.index.from];
1849 if (g->code != otfg->glyph_id)
1851 g->c = 0;
1852 g->code = otfg->glyph_id;
1853 g->measured = 0;
1855 out->used++;
1856 min_from = g->from;
1857 max_to = g->to;
1858 if (otfg->f.index.from < otfg->f.index.to)
1860 /* OTFG substitutes multiple glyphs in IN. */
1861 for (j = from + otfg->f.index.from + 1;
1862 j <= from + otfg->f.index.to; j++)
1864 if (min_from > in->glyphs[j].from)
1865 min_from = in->glyphs[j].from;
1866 if (max_to < in->glyphs[j].to)
1867 max_to = in->glyphs[j].to;
1869 g->from = min_from;
1870 g->to = max_to;
1872 if (feature_idx)
1874 unsigned int tag = features[feature_idx - 1].FeatureTag;
1875 tag = PACK_OTF_TAG (tag);
1876 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1878 for (i++, otfg++; (i < otf_gstring.used
1879 && otfg->f.index.from == otfg[-1].f.index.from);
1880 i++, otfg++)
1882 g = out->glyphs + out->used;
1883 *g = in->glyphs[from + otfg->f.index.to];
1884 if (g->code != otfg->glyph_id)
1886 g->c = 0;
1887 g->code = otfg->glyph_id;
1888 g->measured = 0;
1890 feature_idx = otfg->positioning_type >> 4;
1891 if (feature_idx)
1893 unsigned int tag = features[feature_idx - 1].FeatureTag;
1894 tag = PACK_OTF_TAG (tag);
1895 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1897 out->used++;
1901 else if (gsub_features)
1903 /* Just for checking which features will be applied. */
1904 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1905 gsub_features) < 0)
1906 goto simple_copy;
1907 features = otf->gsub->FeatureList.Feature;
1908 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1909 otfg++)
1911 int feature_idx = otfg->positioning_type >> 4;
1913 if (feature_idx)
1915 unsigned int tag = features[feature_idx - 1].FeatureTag;
1916 tag = PACK_OTF_TAG (tag);
1917 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1919 MFLTGlyph *g = in->glyphs + (from + j);
1920 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1925 else if (out)
1927 if (out->allocated < out->used + len)
1928 return -2;
1929 for (i = 0; i < len; i++)
1930 out->glyphs[out->used++] = in->glyphs[from + i];
1933 if (gpos_features && out)
1935 MFLTGlyph *base = NULL, *mark = NULL, *g;
1936 int x_ppem, y_ppem, x_scale, y_scale;
1938 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1939 gpos_features) < 0)
1940 return to;
1941 features = otf->gpos->FeatureList.Feature;
1942 x_ppem = ft_face->size->metrics.x_ppem;
1943 y_ppem = ft_face->size->metrics.y_ppem;
1944 x_scale = ft_face->size->metrics.x_scale;
1945 y_scale = ft_face->size->metrics.y_scale;
1947 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1948 i < otf_gstring.used; i++, otfg++, g++)
1950 MFLTGlyph *prev;
1951 int feature_idx = otfg->positioning_type >> 4;
1953 if (feature_idx)
1955 unsigned int tag = features[feature_idx - 1].FeatureTag;
1956 tag = PACK_OTF_TAG (tag);
1957 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1960 if (! otfg->glyph_id)
1961 continue;
1962 switch (otfg->positioning_type & 0xF)
1964 case 0:
1965 break;
1966 case 1: /* Single */
1967 case 2: /* Pair */
1969 int format = otfg->f.f1.format;
1971 if (format & OTF_XPlacement)
1972 adjustment[i].xoff
1973 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
1974 if (format & OTF_XPlaDevice)
1975 adjustment[i].xoff
1976 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
1977 if (format & OTF_YPlacement)
1978 adjustment[i].yoff
1979 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
1980 if (format & OTF_YPlaDevice)
1981 adjustment[i].yoff
1982 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
1983 if (format & OTF_XAdvance)
1984 adjustment[i].xadv
1985 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
1986 if (format & OTF_XAdvDevice)
1987 adjustment[i].xadv
1988 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
1989 if (format & OTF_YAdvance)
1990 adjustment[i].yadv
1991 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
1992 if (format & OTF_YAdvDevice)
1993 adjustment[i].yadv
1994 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
1995 adjustment[i].set = 1;
1997 break;
1998 case 3: /* Cursive */
1999 /* Not yet supported. */
2000 break;
2001 case 4: /* Mark-to-Base */
2002 case 5: /* Mark-to-Ligature */
2003 if (! base)
2004 break;
2005 prev = base;
2006 goto label_adjust_anchor;
2007 default: /* i.e. case 6 Mark-to-Mark */
2008 if (! mark)
2009 break;
2010 prev = mark;
2012 label_adjust_anchor:
2014 int base_x, base_y, mark_x, mark_y;
2015 int this_from, this_to;
2017 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2018 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2019 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2020 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2022 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2023 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2024 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2025 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2026 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2027 x_ppem, y_ppem, &mark_x, &mark_y);
2028 adjustment[i].xoff = (base_x - mark_x);
2029 adjustment[i].yoff = - (base_y - mark_y);
2030 adjustment[i].back = (g - prev);
2031 adjustment[i].xadv = 0;
2032 adjustment[i].advance_is_absolute = 1;
2033 adjustment[i].set = 1;
2034 this_from = g->from;
2035 this_to = g->to;
2036 for (j = 0; prev + j < g; j++)
2038 if (this_from > prev[j].from)
2039 this_from = prev[j].from;
2040 if (this_to < prev[j].to)
2041 this_to = prev[j].to;
2043 for (; prev <= g; prev++)
2045 prev->from = this_from;
2046 prev->to = this_to;
2050 if (otfg->GlyphClass == OTF_GlyphClass0)
2051 base = mark = g;
2052 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2053 mark = g;
2054 else
2055 base = g;
2058 else if (gpos_features)
2060 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2061 gpos_features) < 0)
2062 return to;
2063 features = otf->gpos->FeatureList.Feature;
2064 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2065 i++, otfg++)
2066 if (otfg->positioning_type & 0xF)
2068 int feature_idx = otfg->positioning_type >> 4;
2070 if (feature_idx)
2072 unsigned int tag = features[feature_idx - 1].FeatureTag;
2073 tag = PACK_OTF_TAG (tag);
2074 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2076 MFLTGlyph *g = in->glyphs + (from + j);
2077 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2082 return to;
2084 simple_copy:
2085 if (! out)
2086 return to;
2087 if (out->allocated < out->used + len)
2088 return -2;
2089 font->get_metrics (font, in, from, to);
2090 memcpy (out->glyphs + out->used, in->glyphs + from,
2091 sizeof (MFLTGlyph) * len);
2092 out->used += len;
2093 return to;
2096 static int
2097 ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2098 MFLTGlyphString *in, int from, int to)
2100 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2103 #else /* not M17N_FLT_USE_NEW_FEATURE */
2105 static int
2106 ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2107 int from, int to,
2108 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2110 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2111 FT_Face ft_face = flt_font_ft->ft_face;
2112 OTF *otf = flt_font_ft->otf;
2113 int len = to - from;
2114 int i, j, gidx;
2115 OTF_Glyph *otfg;
2116 char script[5], *langsys = NULL;
2117 char *gsub_features = NULL, *gpos_features = NULL;
2119 if (len == 0)
2120 return from;
2121 OTF_tag_name (spec->script, script);
2122 if (spec->langsys)
2124 langsys = alloca (5);
2125 OTF_tag_name (spec->langsys, langsys);
2127 for (i = 0; i < 2; i++)
2129 char *p;
2131 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2133 for (j = 0; spec->features[i][j]; j++);
2134 if (i == 0)
2135 p = gsub_features = alloca (6 * j);
2136 else
2137 p = gpos_features = alloca (6 * j);
2138 for (j = 0; spec->features[i][j]; j++)
2140 if (spec->features[i][j] == 0xFFFFFFFF)
2141 *p++ = '*', *p++ = ',';
2142 else
2144 OTF_tag_name (spec->features[i][j], p);
2145 p[4] = ',';
2146 p += 5;
2149 *--p = '\0';
2153 setup_otf_gstring (len);
2154 for (i = 0; i < len; i++)
2156 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2157 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2160 OTF_drive_gdef (otf, &otf_gstring);
2161 gidx = out->used;
2163 if (gsub_features)
2165 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2166 < 0)
2167 goto simple_copy;
2168 if (out->allocated < out->used + otf_gstring.used)
2169 return -2;
2170 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
2172 MFLTGlyph *g;
2173 int min_from, max_to;
2174 int j;
2176 g = out->glyphs + out->used;
2177 *g = in->glyphs[from + otfg->f.index.from];
2178 if (g->code != otfg->glyph_id)
2180 g->c = 0;
2181 g->code = otfg->glyph_id;
2182 g->measured = 0;
2184 out->used++;
2185 min_from = g->from;
2186 max_to = g->to;
2187 if (otfg->f.index.from < otfg->f.index.to)
2189 /* OTFG substitutes multiple glyphs in IN. */
2190 for (j = from + otfg->f.index.from + 1;
2191 j <= from + otfg->f.index.to; j++)
2193 if (min_from > in->glyphs[j].from)
2194 min_from = in->glyphs[j].from;
2195 if (max_to < in->glyphs[j].to)
2196 max_to = in->glyphs[j].to;
2198 g->from = min_from;
2199 g->to = max_to;
2201 for (i++, otfg++; (i < otf_gstring.used
2202 && otfg->f.index.from == otfg[-1].f.index.from);
2203 i++, otfg++)
2205 g = out->glyphs + out->used;
2206 *g = in->glyphs[from + otfg->f.index.to];
2207 if (g->code != otfg->glyph_id)
2209 g->c = 0;
2210 g->code = otfg->glyph_id;
2211 g->measured = 0;
2213 out->used++;
2217 else
2219 if (out->allocated < out->used + len)
2220 return -2;
2221 for (i = 0; i < len; i++)
2222 out->glyphs[out->used++] = in->glyphs[from + i];
2225 if (gpos_features)
2227 MFLTGlyph *base = NULL, *mark = NULL, *g;
2228 int x_ppem, y_ppem, x_scale, y_scale;
2230 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2231 < 0)
2232 return to;
2234 x_ppem = ft_face->size->metrics.x_ppem;
2235 y_ppem = ft_face->size->metrics.y_ppem;
2236 x_scale = ft_face->size->metrics.x_scale;
2237 y_scale = ft_face->size->metrics.y_scale;
2239 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2240 i < otf_gstring.used; i++, otfg++, g++)
2242 MFLTGlyph *prev;
2244 if (! otfg->glyph_id)
2245 continue;
2246 switch (otfg->positioning_type)
2248 case 0:
2249 break;
2250 case 1: /* Single */
2251 case 2: /* Pair */
2253 int format = otfg->f.f1.format;
2255 if (format & OTF_XPlacement)
2256 adjustment[i].xoff
2257 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2258 if (format & OTF_XPlaDevice)
2259 adjustment[i].xoff
2260 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2261 if (format & OTF_YPlacement)
2262 adjustment[i].yoff
2263 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2264 if (format & OTF_YPlaDevice)
2265 adjustment[i].yoff
2266 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2267 if (format & OTF_XAdvance)
2268 adjustment[i].xadv
2269 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2270 if (format & OTF_XAdvDevice)
2271 adjustment[i].xadv
2272 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2273 if (format & OTF_YAdvance)
2274 adjustment[i].yadv
2275 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2276 if (format & OTF_YAdvDevice)
2277 adjustment[i].yadv
2278 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2279 adjustment[i].set = 1;
2281 break;
2282 case 3: /* Cursive */
2283 /* Not yet supported. */
2284 break;
2285 case 4: /* Mark-to-Base */
2286 case 5: /* Mark-to-Ligature */
2287 if (! base)
2288 break;
2289 prev = base;
2290 goto label_adjust_anchor;
2291 default: /* i.e. case 6 Mark-to-Mark */
2292 if (! mark)
2293 break;
2294 prev = mark;
2296 label_adjust_anchor:
2298 int base_x, base_y, mark_x, mark_y;
2299 int this_from, this_to;
2301 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2302 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2303 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2304 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2306 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2307 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2308 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2309 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2310 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2311 x_ppem, y_ppem, &mark_x, &mark_y);
2312 adjustment[i].xoff = (base_x - mark_x);
2313 adjustment[i].yoff = - (base_y - mark_y);
2314 adjustment[i].back = (g - prev);
2315 adjustment[i].xadv = 0;
2316 adjustment[i].advance_is_absolute = 1;
2317 adjustment[i].set = 1;
2318 this_from = g->from;
2319 this_to = g->to;
2320 for (j = 0; prev + j < g; j++)
2322 if (this_from > prev[j].from)
2323 this_from = prev[j].from;
2324 if (this_to < prev[j].to)
2325 this_to = prev[j].to;
2327 for (; prev <= g; prev++)
2329 prev->from = this_from;
2330 prev->to = this_to;
2334 if (otfg->GlyphClass == OTF_GlyphClass0)
2335 base = mark = g;
2336 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2337 mark = g;
2338 else
2339 base = g;
2342 return to;
2344 simple_copy:
2345 if (out->allocated < out->used + len)
2346 return -2;
2347 font->get_metrics (font, in, from, to);
2348 memcpy (out->glyphs + out->used, in->glyphs + from,
2349 sizeof (MFLTGlyph) * len);
2350 out->used += len;
2351 return to;
2354 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2356 static MFLTGlyphString gstring;
2358 static int m17n_flt_initialized;
2360 static Lisp_Object
2361 ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2362 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
2364 EMACS_UINT len = LGSTRING_GLYPH_LEN (lgstring);
2365 EMACS_UINT i;
2366 struct MFLTFontFT flt_font_ft;
2367 MFLT *flt = NULL;
2368 int with_variation_selector = 0;
2370 if (! m17n_flt_initialized)
2372 M17N_INIT ();
2373 #ifdef M17N_FLT_USE_NEW_FEATURE
2374 mflt_enable_new_feature = 1;
2375 mflt_try_otf = ftfont_try_otf;
2376 #endif /* M17N_FLT_USE_NEW_FEATURE */
2377 m17n_flt_initialized = 1;
2380 for (i = 0; i < len; i++)
2382 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2383 int c;
2385 if (NILP (g))
2386 break;
2387 c = LGLYPH_CHAR (g);
2388 if (CHAR_VARIATION_SELECTOR_P (c))
2389 with_variation_selector++;
2391 len = i;
2392 if (with_variation_selector)
2394 setup_otf_gstring (len);
2395 for (i = 0; i < len; i++)
2397 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2399 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2400 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2401 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2403 OTF_drive_cmap (otf, &otf_gstring);
2404 for (i = 0; i < otf_gstring.used; i++)
2406 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2407 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2408 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2410 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2411 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2412 LGSTRING_SET_GLYPH (lgstring, i, g0);
2414 if (len > otf_gstring.used)
2416 len = otf_gstring.used;
2417 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2421 if (gstring.allocated == 0)
2423 gstring.allocated = len * 2;
2424 gstring.glyph_size = sizeof (MFLTGlyph);
2425 gstring.glyphs = xmalloc (sizeof (MFLTGlyph) * gstring.allocated);
2427 else if (gstring.allocated < len * 2)
2429 gstring.allocated = len * 2;
2430 gstring.glyphs = xrealloc (gstring.glyphs,
2431 sizeof (MFLTGlyph) * gstring.allocated);
2433 memset (gstring.glyphs, 0, sizeof (MFLTGlyph) * len);
2434 for (i = 0; i < len; i++)
2436 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2438 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2439 if (with_variation_selector)
2441 gstring.glyphs[i].code = LGLYPH_CODE (g);
2442 gstring.glyphs[i].encoded = 1;
2446 gstring.used = len;
2447 gstring.r2l = 0;
2450 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2452 if (NILP (family))
2453 flt_font_ft.flt_font.family = Mnil;
2454 else
2455 flt_font_ft.flt_font.family
2456 = msymbol ((char *) SDATA (Fdowncase (SYMBOL_NAME (family))));
2458 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2459 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2460 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2461 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2462 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2463 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2464 flt_font_ft.flt_font.internal = NULL;
2465 flt_font_ft.font = font;
2466 flt_font_ft.ft_face = ft_face;
2467 flt_font_ft.otf = otf;
2468 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
2469 if (len > 1
2470 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
2471 /* A little bit ad hoc. Perhaps, shaper must get script and
2472 language information, and select a proper flt for them
2473 here. */
2474 flt = mflt_get (msymbol ("combining"));
2475 for (i = 0; i < 3; i++)
2477 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
2478 if (result != -2)
2479 break;
2480 gstring.allocated += gstring.allocated;
2481 gstring.glyphs = xrealloc (gstring.glyphs,
2482 sizeof (MFLTGlyph) * gstring.allocated);
2484 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
2485 return Qnil;
2486 for (i = 0; i < gstring.used; i++)
2488 MFLTGlyph *g = gstring.glyphs + i;
2490 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2491 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2494 for (i = 0; i < gstring.used; i++)
2496 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2497 MFLTGlyph *g = gstring.glyphs + i;
2499 if (NILP (lglyph))
2501 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2502 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2504 LGLYPH_SET_FROM (lglyph, g->from);
2505 LGLYPH_SET_TO (lglyph, g->to);
2506 LGLYPH_SET_CHAR (lglyph, g->c);
2507 LGLYPH_SET_CODE (lglyph, g->code);
2508 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2509 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2510 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2511 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2512 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2513 if (g->adjusted)
2515 Lisp_Object vec;
2517 vec = Fmake_vector (make_number (3), Qnil);
2518 ASET (vec, 0, make_number (g->xoff >> 6));
2519 ASET (vec, 1, make_number (g->yoff >> 6));
2520 ASET (vec, 2, make_number (g->xadv >> 6));
2521 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2524 return make_number (i);
2527 Lisp_Object
2528 ftfont_shape (Lisp_Object lgstring)
2530 struct font *font;
2531 struct ftfont_info *ftfont_info;
2532 OTF *otf;
2534 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2535 ftfont_info = (struct ftfont_info *) font;
2536 otf = ftfont_get_otf (ftfont_info);
2537 if (! otf)
2538 return make_number (0);
2539 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2540 &ftfont_info->matrix);
2543 #endif /* HAVE_M17N_FLT */
2545 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2547 static int
2548 ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2550 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2551 OTF *otf = ftfont_get_otf (ftfont_info);
2553 if (! otf)
2554 return 0;
2555 return OTF_get_variation_glyphs (otf, c, variations);
2558 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2559 #endif /* HAVE_LIBOTF */
2561 Lisp_Object
2562 ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
2564 FcChar8 *str;
2566 #ifdef FC_FONTFORMAT
2567 if (pattern)
2569 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2570 return Qnil;
2571 if (strcmp ((char *) str, "TrueType") == 0)
2572 return intern ("truetype");
2573 if (strcmp ((char *) str, "Type 1") == 0)
2574 return intern ("type1");
2575 if (strcmp ((char *) str, "PCF") == 0)
2576 return intern ("pcf");
2577 if (strcmp ((char *) str, "BDF") == 0)
2578 return intern ("bdf");
2580 #endif /* FC_FONTFORMAT */
2581 if (STRINGP (filename))
2583 int len = SBYTES (filename);
2585 if (len >= 4)
2587 str = (FcChar8 *) (SDATA (filename) + len - 4);
2588 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2589 return intern ("truetype");
2590 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2591 return intern ("type1");
2592 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2593 return intern ("pcf");
2594 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2595 return intern ("bdf");
2598 return intern ("unknown");
2601 static const char *ftfont_booleans [] = {
2602 ":antialias",
2603 ":hinting",
2604 ":verticallayout",
2605 ":autohint",
2606 ":globaladvance",
2607 ":outline",
2608 ":scalable",
2609 ":minspace",
2610 ":embolden",
2611 NULL,
2614 static const char *ftfont_non_booleans [] = {
2615 ":family",
2616 ":familylang",
2617 ":style",
2618 ":stylelang",
2619 ":fullname",
2620 ":fullnamelang",
2621 ":slant",
2622 ":weight",
2623 ":size",
2624 ":width",
2625 ":aspect",
2626 ":pixelsize",
2627 ":spacing",
2628 ":foundry",
2629 ":hintstyle",
2630 ":file",
2631 ":index",
2632 ":ftface",
2633 ":rasterizer",
2634 ":scale",
2635 ":dpi",
2636 ":rgba",
2637 ":lcdfilter",
2638 ":charset",
2639 ":lang",
2640 ":fontversion",
2641 ":capability",
2642 NULL,
2645 static void
2646 ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
2648 Lisp_Object it;
2649 int i;
2651 /* Set boolean values to Qt or Qnil */
2652 for (i = 0; ftfont_booleans[i] != NULL; ++i)
2653 for (it = alist; ! NILP (it); it = XCDR (it))
2655 Lisp_Object key = XCAR (XCAR (it));
2656 Lisp_Object val = XCDR (XCAR (it));
2657 char *keystr = SDATA (SYMBOL_NAME (key));
2659 if (strcmp (ftfont_booleans[i], keystr) == 0)
2661 const char *str = SYMBOLP (val) ? SDATA (SYMBOL_NAME (val)) : NULL;
2662 if (INTEGERP (val)) str = XINT (val) != 0 ? "true" : "false";
2663 if (str == NULL) str = "true";
2665 val = Qt;
2666 if (strcmp ("false", str) == 0 || strcmp ("False", str) == 0
2667 || strcmp ("FALSE", str) == 0 || strcmp ("FcFalse", str) == 0
2668 || strcmp ("off", str) == 0 || strcmp ("OFF", str) == 0
2669 || strcmp ("Off", str) == 0)
2670 val = Qnil;
2671 Ffont_put (font, key, val);
2675 for (i = 0; ftfont_non_booleans[i] != NULL; ++i)
2676 for (it = alist; ! NILP (it); it = XCDR (it))
2678 Lisp_Object key = XCAR (XCAR (it));
2679 Lisp_Object val = XCDR (XCAR (it));
2680 char *keystr = SDATA (SYMBOL_NAME (key));
2681 if (strcmp (ftfont_non_booleans[i], keystr) == 0)
2682 Ffont_put (font, key, val);
2687 void
2688 syms_of_ftfont (void)
2690 DEFSYM (Qfreetype, "freetype");
2691 DEFSYM (Qmonospace, "monospace");
2692 DEFSYM (Qsans_serif, "sans-serif");
2693 DEFSYM (Qserif, "serif");
2694 DEFSYM (Qmono, "mono");
2695 DEFSYM (Qsans, "sans");
2696 DEFSYM (Qsans__serif, "sans serif");
2698 staticpro (&freetype_font_cache);
2699 freetype_font_cache = Fcons (Qt, Qnil);
2701 staticpro (&ftfont_generic_family_list);
2702 ftfont_generic_family_list
2703 = Fcons (Fcons (Qmonospace, Qt),
2704 Fcons (Fcons (Qsans_serif, Qt),
2705 Fcons (Fcons (Qsans, Qt), Qnil)));
2707 staticpro (&ft_face_cache);
2708 ft_face_cache = Qnil;
2710 ftfont_driver.type = Qfreetype;
2711 register_font_driver (&ftfont_driver, NULL);
2714 /* arch-tag: 7cfa432c-33a6-4988-83d2-a82ed8604aca
2715 (do not change this comment) */