Format GPG errors (bug#9255).
[bpt/emacs.git] / src / ftfont.c
CommitLineData
c2f5bfd6 1/* ftfont.c -- FreeType font driver.
73b0cd50 2 Copyright (C) 2006-2011 Free Software Foundation, Inc.
5df4f04c 3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
c2f5bfd6
KH
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
6
7This file is part of GNU Emacs.
8
9ec0b715 9GNU Emacs is free software: you can redistribute it and/or modify
c2f5bfd6 10it under the terms of the GNU General Public License as published by
9ec0b715
GM
11the Free Software Foundation, either version 3 of the License, or
12(at your option) any later version.
c2f5bfd6
KH
13
14GNU Emacs is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
9ec0b715 20along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
c2f5bfd6
KH
21
22#include <config.h>
23#include <stdio.h>
d7306fe6 24#include <setjmp.h>
c2f5bfd6 25
c2f5bfd6
KH
26#include <fontconfig/fontconfig.h>
27#include <fontconfig/fcfreetype.h>
28
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"
89a95b7c 36#include "composite.h"
c2f5bfd6
KH
37#include "fontset.h"
38#include "font.h"
de023c40 39#include "ftfont.h"
c2f5bfd6 40
c2801c99 41/* Symbolic type of this font-driver. */
955cbe7b 42static Lisp_Object Qfreetype;
c2f5bfd6 43
706b6995
KH
44/* Fontconfig's generic families and their aliases. */
45static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
46
2a46904e 47/* Flag to tell if FcInit is already called or not. */
c2f5bfd6 48static int fc_initialized;
c2801c99
KH
49
50/* Handle to a FreeType library instance. */
c2f5bfd6
KH
51static FT_Library ft_library;
52
c2801c99 53/* Cache for FreeType fonts. */
c2f5bfd6
KH
54static Lisp_Object freetype_font_cache;
55
e302a291 56/* Cache for FT_Face and FcCharSet. */
21988a08 57static Lisp_Object ft_face_cache;
c2f5bfd6
KH
58
59/* The actual structure for FreeType font that can be casted to struct
60 font. */
61
62struct ftfont_info
63{
64 struct font font;
de023c40 65#ifdef HAVE_LIBOTF
7179ce7b 66 /* The following four members must be here in this order to be
e302a291 67 compatible with struct xftfont_info (in xftfont.c). */
de023c40
KH
68 int maybe_otf; /* Flag to tell if this may be OTF or not. */
69 OTF *otf;
70#endif /* HAVE_LIBOTF */
e302a291
KH
71 FT_Size ft_size;
72 int index;
d0db2ec8 73 FT_Matrix matrix;
c2f5bfd6
KH
74};
75
d7782105
KH
76enum ftfont_cache_for
77 {
78 FTFONT_CACHE_FOR_FACE,
79 FTFONT_CACHE_FOR_CHARSET,
80 FTFONT_CACHE_FOR_ENTITY
81 };
82
f57e2426 83static Lisp_Object ftfont_pattern_entity (FcPattern *, Lisp_Object);
21988a08 84
f57e2426
J
85static Lisp_Object ftfont_resolve_generic_family (Lisp_Object,
86 FcPattern *);
87static Lisp_Object ftfont_lookup_cache (Lisp_Object,
88 enum ftfont_cache_for);
e302a291 89
f57e2426 90static void ftfont_filter_properties (Lisp_Object font, Lisp_Object alist);
9fa82824 91
f57e2426 92Lisp_Object ftfont_font_format (FcPattern *, Lisp_Object);
706b6995
KH
93
94#define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
95
21988a08 96static struct
c2f5bfd6 97{
e302a291 98 /* registry name */
675e2c69 99 const char *name;
21988a08
KH
100 /* characters to distinguish the charset from the others */
101 int uniquifier[6];
7d7ad10e 102 /* additional constraint by language */
675e2c69 103 const char *lang;
21988a08
KH
104 /* set on demand */
105 FcCharSet *fc_charset;
106} fc_charset_table[] =
d7782105 107 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
e302a291
KH
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"},
7d7ad10e
KH
140 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
141 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
e302a291 142 { "mulelao-1", { 0x0E81 }, "lo"},
7b649478 143 { "unicode-sip", { 0x20000 }},
21988a08
KH
144 { NULL }
145 };
c2f5bfd6 146
99c4d65d
KH
147/* Dirty hack for handing ADSTYLE property.
148
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).
156
157 Unfortunately this behavior is not documented, so the following
158 code may fail if FreeType changes the behavior in the future. */
159
160static Lisp_Object
161get_adstyle_property (FcPattern *p)
162{
dae0cd48
PE
163 FcChar8 *fcstr;
164 char *str, *end;
99c4d65d
KH
165 Lisp_Object adstyle;
166
dae0cd48 167 if (FcPatternGetString (p, FC_STYLE, 0, &fcstr) != FcResultMatch)
99c4d65d 168 return Qnil;
dae0cd48 169 str = (char *) fcstr;
99c4d65d
KH
170 for (end = str; *end && *end != ' '; end++);
171 if (*end)
172 {
49eaafba
PE
173 char *newstr = alloca (end - str + 1);
174 memcpy (newstr, str, end - str);
175 newstr[end - str] = '\0';
176 end = newstr + (end - str);
177 str = newstr;
99c4d65d
KH
178 }
179 if (xstrcasecmp (str, "Regular") == 0
180 || xstrcasecmp (str, "Bold") == 0
181 || xstrcasecmp (str, "Oblique") == 0
182 || xstrcasecmp (str, "Italic") == 0)
183 return Qnil;
42d4a64f 184 adstyle = font_intern_prop (str, end - str, 1);
99c4d65d
KH
185 if (font_style_to_value (FONT_WIDTH_INDEX, adstyle, 0) >= 0)
186 return Qnil;
187 return adstyle;
188}
189
706b6995 190static Lisp_Object
971de7fb 191ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
c2801c99 192{
d7782105 193 Lisp_Object key, cache, entity;
dae0cd48
PE
194 FcChar8 *str;
195 char *file;
49eaafba 196 int idx;
c2801c99
KH
197 int numeric;
198 double dbl;
42984a74 199 FcBool b;
c2801c99 200
dae0cd48 201 if (FcPatternGetString (p, FC_FILE, 0, &str) != FcResultMatch)
c2801c99 202 return Qnil;
49eaafba 203 if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
e302a291 204 return Qnil;
c2801c99 205
dae0cd48
PE
206 file = (char *) str;
207 key = Fcons (make_unibyte_string (file, strlen (file)), make_number (idx));
d7782105
KH
208 cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
209 entity = XCAR (cache);
210 if (! NILP (entity))
b50504f5
KH
211 {
212 Lisp_Object val = font_make_entity ();
213 int i;
214
215 for (i = 0; i < FONT_OBJLIST_INDEX; i++)
216 ASET (val, i, AREF (entity, i));
217 return val;
218 }
42984a74 219 entity = font_make_entity ();
d7782105 220 XSETCAR (cache, entity);
c2801c99
KH
221
222 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
e302a291 223 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
c2801c99 224
dae0cd48
PE
225 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch)
226 {
227 char *s = (char *) str;
228 ASET (entity, FONT_FOUNDRY_INDEX, font_intern_prop (s, strlen (s), 1));
229 }
230 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch)
231 {
232 char *s = (char *) str;
233 ASET (entity, FONT_FAMILY_INDEX, font_intern_prop (s, strlen (s), 1));
234 }
c2801c99 235 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
f63d54dc 236 {
42984a74
KH
237 if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
238 numeric = FC_WEIGHT_MEDIUM;
239 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
f63d54dc 240 }
c2801c99 241 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
42984a74
KH
242 {
243 numeric += 100;
244 FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
245 }
c2801c99 246 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
42984a74
KH
247 {
248 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
249 }
c2801c99 250 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
99c4d65d 251 {
99c4d65d 252 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
99c4d65d 253 }
c2801c99
KH
254 else
255 ASET (entity, FONT_SIZE_INDEX, make_number (0));
42984a74
KH
256 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
257 ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
258 if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
259 {
260 int dpi = dbl;
261 ASET (entity, FONT_DPI_INDEX, make_number (dpi));
262 }
263 if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
264 && b == FcTrue)
d7782105
KH
265 {
266 ASET (entity, FONT_SIZE_INDEX, make_number (0));
267 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
268 }
269 else
270 {
271 /* As this font is not scalable, parhaps this is a BDF or PCF
9fa82824 272 font. */
d7782105
KH
273 FT_Face ft_face;
274
275 ASET (entity, FONT_ADSTYLE_INDEX, get_adstyle_property (p));
276 if ((ft_library || FT_Init_FreeType (&ft_library) == 0)
49eaafba 277 && FT_New_Face (ft_library, file, idx, &ft_face) == 0)
d7782105
KH
278 {
279 BDF_PropertyRec rec;
280
281 if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
282 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
283 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
284 FT_Done_Face (ft_face);
285 }
286 }
c2801c99 287
4ffe34a4 288 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
d7782105 289 font_put_extra (entity, QCfont_entity, key);
c2801c99
KH
290 return entity;
291}
292
42984a74 293
706b6995
KH
294static Lisp_Object ftfont_generic_family_list;
295
296static Lisp_Object
971de7fb 297ftfont_resolve_generic_family (Lisp_Object family, FcPattern *pattern)
706b6995 298{
318548be 299 Lisp_Object slot;
7d7ad10e 300 FcPattern *match;
318548be 301 FcResult result;
89a95b7c 302 FcLangSet *langset;
706b6995 303
318548be 304 family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
706b6995
KH
305 if (EQ (family, Qmono))
306 family = Qmonospace;
307 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
308 family = Qsans_serif;
309 slot = assq_no_quit (family, ftfont_generic_family_list);
310 if (! CONSP (slot))
42984a74 311 return Qnil;
318548be
KH
312 if (! EQ (XCDR (slot), Qt))
313 return XCDR (slot);
7d7ad10e 314 pattern = FcPatternDuplicate (pattern);
42984a74
KH
315 if (! pattern)
316 goto err;
bb658864 317 FcPatternDel (pattern, FC_FOUNDRY);
7d7ad10e
KH
318 FcPatternDel (pattern, FC_FAMILY);
319 FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
89a95b7c
KH
320 if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
321 {
322 /* This is to avoid the effect of locale. */
8ff096c1 323 static const FcChar8 lang[] = "en";
89a95b7c 324 langset = FcLangSetCreate ();
8ff096c1 325 FcLangSetAdd (langset, lang);
89a95b7c
KH
326 FcPatternAddLangSet (pattern, FC_LANG, langset);
327 FcLangSetDestroy (langset);
328 }
42984a74 329 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
318548be
KH
330 FcDefaultSubstitute (pattern);
331 match = FcFontMatch (NULL, pattern, &result);
332 if (match)
706b6995 333 {
318548be
KH
334 FcChar8 *fam;
335
336 if (FcPatternGetString (match, FC_FAMILY, 0, &fam) == FcResultMatch)
337 family = intern ((char *) fam);
706b6995 338 }
318548be
KH
339 else
340 family = Qnil;
341 XSETCDR (slot, family);
318548be 342 if (match) FcPatternDestroy (match);
bf39cdd8 343 err:
42984a74 344 if (pattern) FcPatternDestroy (pattern);
318548be 345 return family;
706b6995
KH
346}
347
e302a291
KH
348struct ftfont_cache_data
349{
350 FT_Face ft_face;
351 FcCharSet *fc_charset;
352};
353
354static Lisp_Object
971de7fb 355ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
21988a08 356{
99c4d65d 357 Lisp_Object cache, val, entity;
e302a291 358 struct ftfont_cache_data *cache_data;
21988a08 359
99c4d65d
KH
360 if (FONT_ENTITY_P (key))
361 {
362 entity = key;
363 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
364 xassert (CONSP (val));
365 key = XCDR (val);
366 }
367 else
368 entity = Qnil;
369
d7782105
KH
370 if (NILP (ft_face_cache))
371 cache = Qnil;
372 else
373 cache = Fgethash (key, ft_face_cache, Qnil);
21988a08
KH
374 if (NILP (cache))
375 {
d7782105
KH
376 if (NILP (ft_face_cache))
377 {
378 Lisp_Object args[2];
379
380 args[0] = QCtest;
381 args[1] = Qequal;
382 ft_face_cache = Fmake_hash_table (2, args);
383 }
e302a291
KH
384 cache_data = xmalloc (sizeof (struct ftfont_cache_data));
385 cache_data->ft_face = NULL;
386 cache_data->fc_charset = NULL;
21988a08 387 val = make_save_value (NULL, 0);
e302a291
KH
388 XSAVE_VALUE (val)->integer = 0;
389 XSAVE_VALUE (val)->pointer = cache_data;
d7782105
KH
390 cache = Fcons (Qnil, val);
391 Fputhash (key, cache, ft_face_cache);
21988a08
KH
392 }
393 else
21988a08 394 {
e302a291
KH
395 val = XCDR (cache);
396 cache_data = XSAVE_VALUE (val)->pointer;
397 }
d7782105
KH
398
399 if (cache_for == FTFONT_CACHE_FOR_ENTITY)
400 return cache;
401
402 if (cache_for == FTFONT_CACHE_FOR_FACE
403 ? ! cache_data->ft_face : ! cache_data->fc_charset)
e302a291 404 {
51b59d79 405 char *filename = SSDATA (XCAR (key));
49eaafba 406 int idx = XINT (XCDR (key));
21988a08 407
d7782105 408 if (cache_for == FTFONT_CACHE_FOR_FACE)
e302a291
KH
409 {
410 if (! ft_library
411 && FT_Init_FreeType (&ft_library) != 0)
412 return Qnil;
49eaafba 413 if (FT_New_Face (ft_library, filename, idx, &cache_data->ft_face)
e302a291
KH
414 != 0)
415 return Qnil;
416 }
417 else
418 {
99c4d65d
KH
419 FcPattern *pat = NULL;
420 FcFontSet *fontset = NULL;
421 FcObjectSet *objset = NULL;
422 FcCharSet *charset = NULL;
e302a291
KH
423
424 pat = FcPatternBuild (0, FC_FILE, FcTypeString, (FcChar8 *) filename,
49eaafba 425 FC_INDEX, FcTypeInteger, idx, NULL);
99c4d65d
KH
426 if (! pat)
427 goto finish;
428 objset = FcObjectSetBuild (FC_CHARSET, FC_STYLE, NULL);
429 if (! objset)
430 goto finish;
e302a291 431 fontset = FcFontList (NULL, pat, objset);
99c4d65d
KH
432 if (! fontset)
433 goto finish;
d7782105
KH
434 if (fontset && fontset->nfont > 0
435 && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
1c0db158 436 &charset)
d7782105
KH
437 == FcResultMatch))
438 cache_data->fc_charset = FcCharSetCopy (charset);
e302a291
KH
439 else
440 cache_data->fc_charset = FcCharSetCreate ();
99c4d65d
KH
441
442 finish:
443 if (fontset)
444 FcFontSetDestroy (fontset);
445 if (objset)
446 FcObjectSetDestroy (objset);
447 if (pat)
448 FcPatternDestroy (pat);
e302a291 449 }
21988a08
KH
450 }
451 return cache;
452}
453
e302a291 454FcCharSet *
971de7fb 455ftfont_get_fc_charset (Lisp_Object entity)
e302a291
KH
456{
457 Lisp_Object val, cache;
458 struct ftfont_cache_data *cache_data;
459
d7782105 460 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
e302a291
KH
461 val = XCDR (cache);
462 cache_data = XSAVE_VALUE (val)->pointer;
463 return cache_data->fc_charset;
464}
465
466#ifdef HAVE_LIBOTF
467static OTF *
d5a3eaaf 468ftfont_get_otf (struct ftfont_info *ftfont_info)
e302a291
KH
469{
470 OTF *otf;
471
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)
478 {
479 if (otf)
480 OTF_close (otf);
481 ftfont_info->maybe_otf = 0;
482 return NULL;
483 }
484 ftfont_info->otf = otf;
485 return otf;
486}
487#endif /* HAVE_LIBOTF */
488
f57e2426
J
489static Lisp_Object ftfont_get_cache (FRAME_PTR);
490static Lisp_Object ftfont_list (Lisp_Object, Lisp_Object);
491static Lisp_Object ftfont_match (Lisp_Object, Lisp_Object);
492static Lisp_Object ftfont_list_family (Lisp_Object);
493static Lisp_Object ftfont_open (FRAME_PTR, Lisp_Object, int);
494static void ftfont_close (FRAME_PTR, struct font *);
495static int ftfont_has_char (Lisp_Object, int);
496static unsigned ftfont_encode_char (struct font *, int);
497static int ftfont_text_extents (struct font *, unsigned *, int,
498 struct font_metrics *);
499static int ftfont_get_bitmap (struct font *, unsigned,
500 struct font_bitmap *, int);
501static int ftfont_anchor_point (struct font *, unsigned, int,
502 int *, int *);
a00924bb 503#ifdef HAVE_LIBOTF
f57e2426 504static Lisp_Object ftfont_otf_capability (struct font *);
a00924bb 505# ifdef HAVE_M17N_FLT
f57e2426 506static Lisp_Object ftfont_shape (Lisp_Object);
a00924bb
PE
507# endif
508#endif
3ce80cbe 509
3ce80cbe 510#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
f57e2426
J
511static int ftfont_variation_glyphs (struct font *, int c,
512 unsigned variations[256]);
3ce80cbe 513#endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
c2f5bfd6
KH
514
515struct font_driver ftfont_driver =
516 {
09a56ce4 517 0, /* Qfreetype */
42984a74 518 0, /* case insensitive */
c2f5bfd6 519 ftfont_get_cache,
c2f5bfd6 520 ftfont_list,
8daf5667 521 ftfont_match,
c2f5bfd6 522 ftfont_list_family,
2b33f1ef 523 NULL, /* free_entity */
c2f5bfd6
KH
524 ftfont_open,
525 ftfont_close,
526 /* We can't draw a text without device dependent functions. */
2b33f1ef
KH
527 NULL, /* prepare_face */
528 NULL, /* done_face */
c2f5bfd6
KH
529 ftfont_has_char,
530 ftfont_encode_char,
531 ftfont_text_extents,
532 /* We can't draw a text without device dependent functions. */
2b33f1ef 533 NULL, /* draw */
c2f5bfd6 534 ftfont_get_bitmap,
2b33f1ef
KH
535 NULL, /* get_bitmap */
536 NULL, /* free_bitmap */
537 NULL, /* get_outline */
c2f5bfd6 538 ftfont_anchor_point,
e302a291
KH
539#ifdef HAVE_LIBOTF
540 ftfont_otf_capability,
541#else /* not HAVE_LIBOTF */
c2f5bfd6 542 NULL,
e302a291 543#endif /* not HAVE_LIBOTF */
2b33f1ef
KH
544 NULL, /* otf_drive */
545 NULL, /* start_for_frame */
546 NULL, /* end_for_frame */
637ac44c 547#if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
2b33f1ef 548 ftfont_shape,
637ac44c 549#else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
2b33f1ef 550 NULL,
637ac44c 551#endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
2b33f1ef 552 NULL, /* check */
3ce80cbe 553
e3869731 554#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
637fa988 555 ftfont_variation_glyphs,
2b33f1ef 556#else
637fa988 557 NULL,
2b33f1ef 558#endif
637fa988
JD
559
560 ftfont_filter_properties, /* filter_properties */
c2f5bfd6
KH
561 };
562
c2f5bfd6 563static Lisp_Object
971de7fb 564ftfont_get_cache (FRAME_PTR f)
c2f5bfd6 565{
c2f5bfd6
KH
566 return freetype_font_cache;
567}
568
21988a08 569static int
971de7fb 570ftfont_get_charset (Lisp_Object registry)
21988a08 571{
51b59d79 572 char *str = SSDATA (SYMBOL_NAME (registry));
e302a291
KH
573 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
574 Lisp_Object regexp;
21988a08
KH
575 int i, j;
576
e302a291
KH
577 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
578 {
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] = '.';
586 }
587 re[j] = '\0';
588 regexp = make_unibyte_string (re, j);
21988a08 589 for (i = 0; fc_charset_table[i].name; i++)
e302a291 590 if (fast_c_string_match_ignore_case (regexp, fc_charset_table[i].name) >= 0)
21988a08
KH
591 break;
592 if (! fc_charset_table[i].name)
593 return -1;
594 if (! fc_charset_table[i].fc_charset)
595 {
d7782105
KH
596 FcCharSet *charset = FcCharSetCreate ();
597 int *uniquifier = fc_charset_table[i].uniquifier;
21988a08 598
d7782105
KH
599 if (! charset)
600 return -1;
601 for (j = 0; uniquifier[j]; j++)
602 if (! FcCharSetAddChar (charset, uniquifier[j]))
603 {
604 FcCharSetDestroy (charset);
21988a08 605 return -1;
d7782105
KH
606 }
607 fc_charset_table[i].fc_charset = charset;
21988a08
KH
608 }
609 return i;
610}
611
cc63eaf9
KH
612struct OpenTypeSpec
613{
16963817
KH
614 Lisp_Object script;
615 unsigned int script_tag, langsys_tag;
cc63eaf9
KH
616 int nfeatures[2];
617 unsigned int *features[2];
618};
619
7eb5d3d7 620#define OTF_SYM_TAG(SYM, TAG) \
cc63eaf9 621 do { \
7eb5d3d7
KH
622 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
623 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
cc63eaf9
KH
624 } while (0)
625
7eb5d3d7 626#define OTF_TAG_STR(TAG, P) \
cc63eaf9 627 do { \
7eb5d3d7
KH
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); \
16963817 632 (P)[4] = '\0'; \
cc63eaf9
KH
633 } while (0)
634
a00924bb 635#ifdef HAVE_LIBOTF
e302a291
KH
636#define OTF_TAG_SYM(SYM, TAG) \
637 do { \
638 char str[5]; \
639 \
640 OTF_TAG_STR (TAG, str); \
641 (SYM) = font_intern_prop (str, 4, 1); \
642 } while (0)
a00924bb 643#endif
e302a291
KH
644
645
cc63eaf9
KH
646static struct OpenTypeSpec *
647ftfont_get_open_type_spec (Lisp_Object otf_spec)
648{
649 struct OpenTypeSpec *spec = malloc (sizeof (struct OpenTypeSpec));
650 Lisp_Object val;
651 int i, j, negative;
652
653 if (! spec)
654 return NULL;
16963817 655 spec->script = XCAR (otf_spec);
43f4f91c 656 if (! NILP (spec->script))
16963817
KH
657 {
658 OTF_SYM_TAG (spec->script, spec->script_tag);
659 val = assq_no_quit (spec->script, Votf_script_alist);
660 if (CONSP (val) && SYMBOLP (XCDR (val)))
661 spec->script = XCDR (val);
662 else
663 spec->script = Qnil;
664 }
cc63eaf9 665 else
16963817 666 spec->script_tag = 0x44464C54; /* "DFLT" */
cc63eaf9 667 otf_spec = XCDR (otf_spec);
f88cc4d6
KH
668 spec->langsys_tag = 0;
669 if (! NILP (otf_spec))
670 {
671 val = XCAR (otf_spec);
672 if (! NILP (val))
673 OTF_SYM_TAG (val, spec->langsys_tag);
674 otf_spec = XCDR (otf_spec);
675 }
cc63eaf9 676 spec->nfeatures[0] = spec->nfeatures[1] = 0;
f88cc4d6 677 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
cc63eaf9
KH
678 {
679 Lisp_Object len;
680
cc63eaf9
KH
681 val = XCAR (otf_spec);
682 if (NILP (val))
683 continue;
684 len = Flength (val);
685 spec->features[i] = malloc (sizeof (int) * XINT (len));
686 if (! spec->features[i])
687 {
688 if (i > 0 && spec->features[0])
689 free (spec->features[0]);
690 free (spec);
691 return NULL;
692 }
693 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
694 {
695 if (NILP (XCAR (val)))
696 negative = 1;
697 else
698 {
699 unsigned int tag;
700
701 OTF_SYM_TAG (XCAR (val), tag);
702 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
703 }
704 }
705 spec->nfeatures[i] = j;
706 }
707 return spec;
708}
709
42984a74 710static FcPattern *
675e2c69 711ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
c2f5bfd6 712{
21988a08 713 Lisp_Object tmp, extra;
c2f5bfd6
KH
714 FcPattern *pattern = NULL;
715 FcCharSet *charset = NULL;
716 FcLangSet *langset = NULL;
42984a74
KH
717 int n;
718 int dpi = -1;
bc9a2afe 719 int scalable = -1;
42984a74 720 Lisp_Object script = Qnil;
21988a08 721 Lisp_Object registry;
e302a291 722 int fc_charset_idx;
c2f5bfd6 723
42984a74
KH
724 if ((n = FONT_SLANT_NUMERIC (spec)) >= 0
725 && n < 100)
63565713 726 /* Fontconfig doesn't support reverse-italic/obligue. */
42984a74
KH
727 return NULL;
728
729 if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
730 dpi = XINT (AREF (spec, FONT_DPI_INDEX));
42984a74
KH
731 if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
732 && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
733 scalable = 1;
63565713 734
21988a08
KH
735 registry = AREF (spec, FONT_REGISTRY_INDEX);
736 if (NILP (registry)
770835fd 737 || EQ (registry, Qascii_0)
21988a08 738 || EQ (registry, Qiso10646_1)
7b649478 739 || EQ (registry, Qunicode_bmp))
e302a291 740 fc_charset_idx = -1;
21988a08 741 else
c2f5bfd6 742 {
7d7ad10e
KH
743 FcChar8 *lang;
744
e302a291
KH
745 fc_charset_idx = ftfont_get_charset (registry);
746 if (fc_charset_idx < 0)
42984a74 747 return NULL;
e302a291 748 charset = fc_charset_table[fc_charset_idx].fc_charset;
497e54d8
KH
749 *langname = fc_charset_table[fc_charset_idx].lang;
750 lang = (FcChar8 *) *langname;
7d7ad10e
KH
751 if (lang)
752 {
753 langset = FcLangSetCreate ();
754 if (! langset)
755 goto err;
756 FcLangSetAdd (langset, lang);
757 }
c2f5bfd6
KH
758 }
759
cc63eaf9 760 otlayout[0] = '\0';
8daf5667
KH
761 for (extra = AREF (spec, FONT_EXTRA_INDEX);
762 CONSP (extra); extra = XCDR (extra))
c2f5bfd6 763 {
8daf5667
KH
764 Lisp_Object key, val;
765
42984a74
KH
766 key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
767 if (EQ (key, QCdpi))
9e269017
KH
768 {
769 if (INTEGERP (val))
770 dpi = XINT (val);
771 }
42984a74 772 else if (EQ (key, QClang))
c2f5bfd6 773 {
7d7ad10e
KH
774 if (! langset)
775 langset = FcLangSetCreate ();
c2f5bfd6
KH
776 if (! langset)
777 goto err;
8daf5667 778 if (SYMBOLP (val))
c2f5bfd6 779 {
8daf5667 780 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
c2f5bfd6
KH
781 goto err;
782 }
783 else
8daf5667
KH
784 for (; CONSP (val); val = XCDR (val))
785 if (SYMBOLP (XCAR (val))
786 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
787 goto err;
c2f5bfd6 788 }
42984a74
KH
789 else if (EQ (key, QCotf))
790 {
9e269017
KH
791 if (CONSP (val))
792 {
793 *otspec = ftfont_get_open_type_spec (val);
794 if (! *otspec)
795 return NULL;
796 strcat (otlayout, "otlayout:");
797 OTF_TAG_STR ((*otspec)->script_tag, otlayout + 9);
798 script = (*otspec)->script;
799 }
42984a74 800 }
8daf5667
KH
801 else if (EQ (key, QCscript))
802 script = val;
8daf5667
KH
803 else if (EQ (key, QCscalable))
804 scalable = ! NILP (val);
805 }
c2f5bfd6 806
8daf5667
KH
807 if (! NILP (script) && ! charset)
808 {
809 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
810
7c4bd58d 811 if (CONSP (chars) && CONSP (CDR (chars)))
8daf5667
KH
812 {
813 charset = FcCharSetCreate ();
814 if (! charset)
815 goto err;
816 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
817 if (CHARACTERP (XCAR (chars))
ccd9a01a 818 && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
8daf5667 819 goto err;
c2f5bfd6
KH
820 }
821 }
822
4ffe34a4 823 pattern = FcPatternCreate ();
706b6995
KH
824 if (! pattern)
825 goto err;
706b6995 826 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
42984a74 827 if (! NILP (tmp)
706b6995
KH
828 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
829 goto err;
318548be
KH
830 tmp = AREF (spec, FONT_FAMILY_INDEX);
831 if (! NILP (tmp)
832 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
833 goto err;
c2f5bfd6
KH
834 if (charset
835 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
836 goto err;
837 if (langset
838 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
839 goto err;
bc9a2afe
KH
840 if (dpi >= 0
841 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
842 goto err;
bc9a2afe 843 if (scalable >= 0
25a5d05b 844 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
bc9a2afe 845 goto err;
7d7ad10e 846
42984a74 847 goto finish;
c2f5bfd6 848
42984a74
KH
849 err:
850 /* We come here because of unexpected error in fontconfig API call
851 (usually insufficient memory). */
852 if (pattern)
853 {
854 FcPatternDestroy (pattern);
855 pattern = NULL;
856 }
857 if (*otspec)
858 {
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;
865 }
866
867 finish:
42984a74 868 if (langset) FcLangSetDestroy (langset);
e302a291 869 if (charset && fc_charset_idx < 0) FcCharSetDestroy (charset);
42984a74
KH
870 return pattern;
871}
872
873static Lisp_Object
971de7fb 874ftfont_list (Lisp_Object frame, Lisp_Object spec)
42984a74 875{
99c4d65d 876 Lisp_Object val = Qnil, family, adstyle;
42984a74
KH
877 int i;
878 FcPattern *pattern;
879 FcFontSet *fontset = NULL;
880 FcObjectSet *objset = NULL;
7c4bd58d
KH
881 FcCharSet *charset;
882 Lisp_Object chars = Qnil;
42984a74
KH
883 char otlayout[15]; /* For "otlayout:XXXX" */
884 struct OpenTypeSpec *otspec = NULL;
5d376f74 885 int spacing = -1;
675e2c69 886 const char *langname = NULL;
2a46904e 887
42984a74
KH
888 if (! fc_initialized)
889 {
890 FcInit ();
891 fc_initialized = 1;
892 }
893
497e54d8 894 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
42984a74
KH
895 if (! pattern)
896 return Qnil;
7c4bd58d
KH
897 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
898 {
899 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
900 if (! NILP (val))
901 {
902 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
903 if (CONSP (val) && VECTORP (XCDR (val)))
904 chars = XCDR (val);
905 }
906 val = Qnil;
907 }
5d376f74
KH
908 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
909 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
318548be
KH
910 family = AREF (spec, FONT_FAMILY_INDEX);
911 if (! NILP (family))
912 {
913 Lisp_Object resolved;
914
7d7ad10e 915 resolved = ftfont_resolve_generic_family (family, pattern);
318548be
KH
916 if (! NILP (resolved))
917 {
918 FcPatternDel (pattern, FC_FAMILY);
919 if (! FcPatternAddString (pattern, FC_FAMILY,
920 SYMBOL_FcChar8 (resolved)))
921 goto err;
922 }
923 }
99c4d65d
KH
924 adstyle = AREF (spec, FONT_ADSTYLE_INDEX);
925 if (! NILP (adstyle) && SBYTES (SYMBOL_NAME (adstyle)) == 0)
926 adstyle = Qnil;
706b6995 927 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
42984a74 928 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, FC_SCALABLE,
99c4d65d 929 FC_STYLE, FC_FILE, FC_INDEX,
42984a74
KH
930#ifdef FC_CAPABILITY
931 FC_CAPABILITY,
932#endif /* FC_CAPABILITY */
4ffe34a4
KH
933#ifdef FC_FONTFORMAT
934 FC_FONTFORMAT,
935#endif
e907d979 936 NULL);
706b6995
KH
937 if (! objset)
938 goto err;
7c4bd58d
KH
939 if (! NILP (chars))
940 FcObjectSetAdd (objset, FC_CHARSET);
42984a74 941
318548be 942 fontset = FcFontList (NULL, pattern, objset);
7c4bd58d
KH
943 if (! fontset || fontset->nfont == 0)
944 goto finish;
770835fd
KH
945#if 0
946 /* Need fix because this finds any fonts. */
947 if (fontset->nfont == 0 && ! NILP (family))
948 {
949 /* Try maching with configuration. For instance, the
950 configuration may specify "Nimbus Mono L" as an alias of
951 "Courier". */
952 FcPattern *pat = FcPatternBuild (0, FC_FAMILY, FcTypeString,
953 SYMBOL_FcChar8 (family), NULL);
954 FcChar8 *fam;
955
956 if (FcConfigSubstitute (NULL, pat, FcMatchPattern) == FcTrue)
957 {
958 for (i = 0;
959 FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
960 i++)
961 {
962 FcPatternDel (pattern, FC_FAMILY);
963 FcPatternAddString (pattern, FC_FAMILY, fam);
964 FcFontSetDestroy (fontset);
965 fontset = FcFontList (NULL, pattern, objset);
1c0db158 966 if (fontset && fontset->nfont > 0)
770835fd
KH
967 break;
968 }
969 }
970 }
971#endif
318548be 972 for (i = 0; i < fontset->nfont; i++)
bc5f6c42 973 {
318548be 974 Lisp_Object entity;
f63d54dc 975
5d376f74
KH
976 if (spacing >= 0)
977 {
978 int this;
979
980 if ((FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &this)
981 == FcResultMatch)
982 && spacing != this)
983 continue;
984 }
985
bc5f6c42 986#ifdef FC_CAPABILITY
318548be
KH
987 if (otlayout[0])
988 {
989 FcChar8 *this;
a85f724a 990
7c4bd58d
KH
991 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
992 != FcResultMatch
318548be
KH
993 || ! strstr ((char *) this, otlayout))
994 continue;
995 }
bc5f6c42 996#endif /* FC_CAPABILITY */
cc63eaf9 997#ifdef HAVE_LIBOTF
318548be
KH
998 if (otspec)
999 {
1000 FcChar8 *file;
1001 OTF *otf;
1002
1003 if (FcPatternGetString (fontset->fonts[i], FC_FILE, 0, &file)
1004 != FcResultMatch)
1005 continue;
1006 otf = OTF_open ((char *) file);
1007 if (! otf)
1008 continue;
1009 if (OTF_check_features (otf, 1,
1010 otspec->script_tag, otspec->langsys_tag,
1011 otspec->features[0],
1012 otspec->nfeatures[0]) != 1
1013 || OTF_check_features (otf, 0,
1014 otspec->script_tag, otspec->langsys_tag,
1015 otspec->features[1],
1016 otspec->nfeatures[1]) != 1)
1017 continue;
c2f5bfd6 1018 }
318548be 1019#endif /* HAVE_LIBOTF */
7c4bd58d
KH
1020 if (VECTORP (chars))
1021 {
1022 int j;
1023
1024 if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
1025 != FcResultMatch)
1026 continue;
1027 for (j = 0; j < ASIZE (chars); j++)
1028 if (NATNUMP (AREF (chars, j))
1029 && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
1030 break;
1031 if (j == ASIZE (chars))
1032 continue;
1033 }
497e54d8 1034 if (! NILP (adstyle) || langname)
99c4d65d
KH
1035 {
1036 Lisp_Object this_adstyle = get_adstyle_property (fontset->fonts[i]);
1037
497e54d8
KH
1038 if (! NILP (adstyle)
1039 && (NILP (this_adstyle)
25a48bd0
PE
1040 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle)),
1041 SSDATA (SYMBOL_NAME (this_adstyle))) != 0))
497e54d8
KH
1042 continue;
1043 if (langname
1044 && ! NILP (this_adstyle)
25a48bd0 1045 && xstrcasecmp (langname, SSDATA (SYMBOL_NAME (this_adstyle))))
99c4d65d
KH
1046 continue;
1047 }
e302a291
KH
1048 entity = ftfont_pattern_entity (fontset->fonts[i],
1049 AREF (spec, FONT_EXTRA_INDEX));
318548be
KH
1050 if (! NILP (entity))
1051 val = Fcons (entity, val);
c2f5bfd6 1052 }
7c4bd58d 1053 val = Fnreverse (val);
c2f5bfd6
KH
1054 goto finish;
1055
1056 err:
1057 /* We come here because of unexpected error in fontconfig API call
706b6995 1058 (usually insufficient memory). */
c2f5bfd6
KH
1059 val = Qnil;
1060
1061 finish:
678dca3d 1062 FONT_ADD_LOG ("ftfont-list", spec, val);
c2f5bfd6
KH
1063 if (objset) FcObjectSetDestroy (objset);
1064 if (fontset) FcFontSetDestroy (fontset);
c2f5bfd6 1065 if (pattern) FcPatternDestroy (pattern);
c2f5bfd6
KH
1066 return val;
1067}
1068
8daf5667 1069static Lisp_Object
971de7fb 1070ftfont_match (Lisp_Object frame, Lisp_Object spec)
8daf5667 1071{
a3c15670 1072 Lisp_Object entity = Qnil;
42984a74 1073 FcPattern *pattern, *match = NULL;
8daf5667 1074 FcResult result;
42984a74
KH
1075 char otlayout[15]; /* For "otlayout:XXXX" */
1076 struct OpenTypeSpec *otspec = NULL;
675e2c69 1077 const char *langname = NULL;
8daf5667
KH
1078
1079 if (! fc_initialized)
1080 {
1081 FcInit ();
1082 fc_initialized = 1;
1083 }
1084
497e54d8 1085 pattern = ftfont_spec_pattern (spec, otlayout, &otspec, &langname);
42984a74 1086 if (! pattern)
8daf5667
KH
1087 return Qnil;
1088
42984a74 1089 if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
8daf5667 1090 {
42984a74 1091 FcValue value;
55082642 1092
42984a74
KH
1093 value.type = FcTypeDouble;
1094 value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
1095 FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
1096 }
1097 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
1098 {
1099 FcDefaultSubstitute (pattern);
1100 match = FcFontMatch (NULL, pattern, &result);
1101 if (match)
8daf5667 1102 {
e302a291 1103 entity = ftfont_pattern_entity (match, AREF (spec, FONT_EXTRA_INDEX));
42984a74
KH
1104 FcPatternDestroy (match);
1105 if (! NILP (AREF (spec, FONT_FAMILY_INDEX))
1106 && NILP (assq_no_quit (AREF (spec, FONT_FAMILY_INDEX),
1107 ftfont_generic_family_list))
1108 && NILP (Fstring_equal (AREF (spec, FONT_FAMILY_INDEX),
1109 AREF (entity, FONT_FAMILY_INDEX))))
1110 entity = Qnil;
8daf5667 1111 }
8daf5667 1112 }
42984a74 1113 FcPatternDestroy (pattern);
8daf5667 1114
678dca3d 1115 FONT_ADD_LOG ("ftfont-match", spec, entity);
8daf5667
KH
1116 return entity;
1117}
1118
c2f5bfd6 1119static Lisp_Object
971de7fb 1120ftfont_list_family (Lisp_Object frame)
c2f5bfd6 1121{
76d126ec 1122 Lisp_Object list = Qnil;
c2f5bfd6
KH
1123 FcPattern *pattern = NULL;
1124 FcFontSet *fontset = NULL;
1125 FcObjectSet *objset = NULL;
1126 int i;
1127
1128 if (! fc_initialized)
1129 {
1130 FcInit ();
1131 fc_initialized = 1;
1132 }
1133
1134 pattern = FcPatternCreate ();
1135 if (! pattern)
1136 goto finish;
706b6995 1137 objset = FcObjectSetBuild (FC_FAMILY, NULL);
c2f5bfd6
KH
1138 if (! objset)
1139 goto finish;
1140 fontset = FcFontList (NULL, pattern, objset);
1141 if (! fontset)
1142 goto finish;
1143
c2f5bfd6
KH
1144 for (i = 0; i < fontset->nfont; i++)
1145 {
1146 FcPattern *pat = fontset->fonts[i];
1147 FcChar8 *str;
1148
1149 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
42984a74 1150 list = Fcons (intern ((char *) str), list);
c2f5bfd6
KH
1151 }
1152
1153 finish:
1154 if (objset) FcObjectSetDestroy (objset);
1155 if (fontset) FcFontSetDestroy (fontset);
1156 if (pattern) FcPatternDestroy (pattern);
1157
1158 return list;
1159}
1160
1161
42984a74 1162static Lisp_Object
971de7fb 1163ftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
c2f5bfd6
KH
1164{
1165 struct ftfont_info *ftfont_info;
1166 struct font *font;
e302a291 1167 struct ftfont_cache_data *cache_data;
c2f5bfd6
KH
1168 FT_Face ft_face;
1169 FT_Size ft_size;
1170 FT_UInt size;
49eaafba 1171 Lisp_Object val, filename, idx, cache, font_object;
21988a08 1172 int scalable;
c2f5bfd6 1173 int spacing;
42984a74
KH
1174 char name[256];
1175 int i, len;
1176 int upEM;
c2f5bfd6 1177
42984a74
KH
1178 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
1179 if (! CONSP (val))
1180 return Qnil;
1181 val = XCDR (val);
d7782105 1182 cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_FACE);
21988a08
KH
1183 if (NILP (cache))
1184 return Qnil;
e302a291 1185 filename = XCAR (val);
49eaafba 1186 idx = XCDR (val);
21988a08 1187 val = XCDR (cache);
e302a291
KH
1188 cache_data = XSAVE_VALUE (XCDR (cache))->pointer;
1189 ft_face = cache_data->ft_face;
21988a08 1190 if (XSAVE_VALUE (val)->integer > 0)
c2f5bfd6 1191 {
21988a08 1192 /* FT_Face in this cache is already used by the different size. */
c2f5bfd6 1193 if (FT_New_Size (ft_face, &ft_size) != 0)
42984a74 1194 return Qnil;
c2f5bfd6
KH
1195 if (FT_Activate_Size (ft_size) != 0)
1196 {
1197 FT_Done_Size (ft_size);
42984a74 1198 return Qnil;
c2f5bfd6 1199 }
21988a08
KH
1200 }
1201 XSAVE_VALUE (val)->integer++;
c2f5bfd6
KH
1202 size = XINT (AREF (entity, FONT_SIZE_INDEX));
1203 if (size == 0)
1204 size = pixel_size;
1205 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
1206 {
1207 if (XSAVE_VALUE (val)->integer == 0)
1208 FT_Done_Face (ft_face);
42984a74 1209 return Qnil;
c2f5bfd6
KH
1210 }
1211
e302a291 1212 font_object = font_make_object (VECSIZE (struct ftfont_info), entity, size);
42984a74 1213 ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
42984a74
KH
1214 len = font_unparse_xlfd (entity, size, name, 256);
1215 if (len > 0)
3299c552 1216 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
42984a74
KH
1217 len = font_unparse_fcname (entity, size, name, 256);
1218 if (len > 0)
3299c552 1219 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
42984a74
KH
1220 else
1221 ASET (font_object, FONT_FULLNAME_INDEX,
1222 AREF (font_object, FONT_NAME_INDEX));
21988a08 1223 ASET (font_object, FONT_FILE_INDEX, filename);
7d7ad10e 1224 ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (NULL, filename));
42984a74
KH
1225 font = XFONT_OBJECT (font_object);
1226 ftfont_info = (struct ftfont_info *) font;
21988a08 1227 ftfont_info->ft_size = ft_face->size;
49eaafba 1228 ftfont_info->index = XINT (idx);
0d674a05 1229#ifdef HAVE_LIBOTF
de023c40
KH
1230 ftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
1231 ftfont_info->otf = NULL;
0d674a05 1232#endif /* HAVE_LIBOTF */
d0db2ec8
KH
1233 /* This means that there's no need of transformation. */
1234 ftfont_info->matrix.xx = 0;
c2f5bfd6
KH
1235 font->pixel_size = size;
1236 font->driver = &ftfont_driver;
42984a74 1237 font->encoding_charset = font->repertory_charset = -1;
c9c0c429 1238
42984a74 1239 upEM = ft_face->units_per_EM;
21988a08
KH
1240 scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
1241 && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
42984a74
KH
1242 if (scalable)
1243 {
1244 font->ascent = ft_face->ascender * size / upEM;
1245 font->descent = - ft_face->descender * size / upEM;
1246 font->height = ft_face->height * size / upEM;
1247 }
1248 else
1249 {
1250 font->ascent = ft_face->size->metrics.ascender >> 6;
1251 font->descent = - ft_face->size->metrics.descender >> 6;
1252 font->height = ft_face->size->metrics.height >> 6;
c9c0c429 1253 }
21988a08
KH
1254 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
1255 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
1256 else
c9c0c429 1257 spacing = FC_PROPORTIONAL;
ea2460a0
KH
1258 if (spacing != FC_PROPORTIONAL
1259#ifdef FC_DUAL
1260 && spacing != FC_DUAL
1261#endif /* FC_DUAL */
1262 )
42984a74
KH
1263 font->min_width = font->average_width = font->space_width
1264 = (scalable ? ft_face->max_advance_width * size / upEM
1265 : ft_face->size->metrics.max_advance >> 6);
c2f5bfd6
KH
1266 else
1267 {
42984a74 1268 int n;
c2f5bfd6 1269
42984a74
KH
1270 font->min_width = font->average_width = font->space_width = 0;
1271 for (i = 32, n = 0; i < 127; i++)
0c26f026 1272 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
42984a74
KH
1273 {
1274 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1275
1276 if (this_width > 0
1277 && (! font->min_width || font->min_width > this_width))
1278 font->min_width = this_width;
1279 if (i == 32)
1280 font->space_width = this_width;
1281 font->average_width += this_width;
1282 n++;
1283 }
1284 if (n > 0)
1285 font->average_width /= n;
c2f5bfd6
KH
1286 }
1287
42984a74
KH
1288 font->baseline_offset = 0;
1289 font->relative_compose = 0;
1290 font->default_ascent = 0;
1291 font->vertical_centering = 0;
1292 if (scalable)
1293 {
1294 font->underline_position = -ft_face->underline_position * size / upEM;
0c26f026 1295 font->underline_thickness = ft_face->underline_thickness * size / upEM;
42984a74
KH
1296 }
1297 else
1298 {
1299 font->underline_position = -1;
1300 font->underline_thickness = 0;
1301 }
c2f5bfd6 1302
42984a74 1303 return font_object;
c2f5bfd6
KH
1304}
1305
1306static void
971de7fb 1307ftfont_close (FRAME_PTR f, struct font *font)
c2f5bfd6
KH
1308{
1309 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
21988a08 1310 Lisp_Object val, cache;
c2f5bfd6 1311
e302a291 1312 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
d7782105 1313 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
e302a291 1314 xassert (CONSP (cache));
21988a08 1315 val = XCDR (cache);
c2f5bfd6
KH
1316 (XSAVE_VALUE (val)->integer)--;
1317 if (XSAVE_VALUE (val)->integer == 0)
de023c40 1318 {
e302a291 1319 struct ftfont_cache_data *cache_data = XSAVE_VALUE (val)->pointer;
21988a08 1320
e302a291 1321 FT_Done_Face (cache_data->ft_face);
de023c40
KH
1322#ifdef HAVE_LIBOTF
1323 if (ftfont_info->otf)
1324 OTF_close (ftfont_info->otf);
1325#endif
e302a291 1326 cache_data->ft_face = NULL;
de023c40 1327 }
c2f5bfd6
KH
1328 else
1329 FT_Done_Size (ftfont_info->ft_size);
c2f5bfd6
KH
1330}
1331
2a46904e 1332static int
971de7fb 1333ftfont_has_char (Lisp_Object font, int c)
c2f5bfd6 1334{
d7782105
KH
1335 struct charset *cs = NULL;
1336
1337 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1338 && charset_jisx0208 >= 0)
1339 cs = CHARSET_FROM_ID (charset_jisx0208);
1340 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1341 && charset_ksc5601 >= 0)
1342 cs = CHARSET_FROM_ID (charset_ksc5601);
1343 if (cs)
1344 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1345
7179ce7b
KH
1346 if (FONT_ENTITY_P (font))
1347 {
1348 FcCharSet *charset = ftfont_get_fc_charset (font);
c2f5bfd6 1349
7179ce7b
KH
1350 return (FcCharSetHasChar (charset, c) == FcTrue);
1351 }
1352 else
1353 {
1354 struct ftfont_info *ftfont_info;
1355
1356 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1357 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1358 != 0);
1359 }
c2f5bfd6
KH
1360}
1361
1362static unsigned
971de7fb 1363ftfont_encode_char (struct font *font, int c)
c2f5bfd6
KH
1364{
1365 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1366 FT_Face ft_face = ftfont_info->ft_size->face;
1367 FT_ULong charcode = c;
1368 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1369
4cec6061 1370 return (code > 0 ? code : FONT_INVALID_CODE);
c2f5bfd6
KH
1371}
1372
1373static int
971de7fb 1374ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
c2f5bfd6
KH
1375{
1376 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1377 FT_Face ft_face = ftfont_info->ft_size->face;
1378 int width = 0;
e5d05978 1379 int i, first;
c2f5bfd6
KH
1380
1381 if (ftfont_info->ft_size != ft_face->size)
1382 FT_Activate_Size (ftfont_info->ft_size);
1383 if (metrics)
72af86bd 1384 memset (metrics, 0, sizeof (struct font_metrics));
e5d05978 1385 for (i = 0, first = 1; i < nglyphs; i++)
c2f5bfd6
KH
1386 {
1387 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1388 {
1389 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1390
e5d05978
KH
1391 if (first)
1392 {
1393 if (metrics)
1394 {
1395 metrics->lbearing = m->horiBearingX >> 6;
1396 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1397 metrics->ascent = m->horiBearingY >> 6;
57d3b93b 1398 metrics->descent = (m->height - m->horiBearingY) >> 6;
e5d05978
KH
1399 }
1400 first = 0;
1401 }
c2f5bfd6
KH
1402 if (metrics)
1403 {
1404 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1405 metrics->lbearing = width + (m->horiBearingX >> 6);
1406 if (metrics->rbearing
1407 < width + ((m->horiBearingX + m->width) >> 6))
1408 metrics->rbearing
1409 = width + ((m->horiBearingX + m->width) >> 6);
1410 if (metrics->ascent < (m->horiBearingY >> 6))
1411 metrics->ascent = m->horiBearingY >> 6;
57d3b93b
KH
1412 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1413 metrics->descent = (m->height - m->horiBearingY) >> 6;
c2f5bfd6
KH
1414 }
1415 width += m->horiAdvance >> 6;
1416 }
1417 else
1418 {
42984a74 1419 width += font->space_width;
c2f5bfd6
KH
1420 }
1421 }
1422 if (metrics)
1423 metrics->width = width;
1424
1425 return width;
1426}
1427
1428static int
971de7fb 1429ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
c2f5bfd6
KH
1430{
1431 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1432 FT_Face ft_face = ftfont_info->ft_size->face;
1433 FT_Int32 load_flags = FT_LOAD_RENDER;
1434
1435 if (ftfont_info->ft_size != ft_face->size)
1436 FT_Activate_Size (ftfont_info->ft_size);
1437 if (bits_per_pixel == 1)
1438 {
1439#ifdef FT_LOAD_TARGET_MONO
1440 load_flags |= FT_LOAD_TARGET_MONO;
1441#else
1442 load_flags |= FT_LOAD_MONOCHROME;
1443#endif
1444 }
1445 else if (bits_per_pixel != 8)
1446 /* We don't support such a rendering. */
1447 return -1;
1448
1449 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1450 return -1;
b51e5112
KH
1451 bitmap->bits_per_pixel
1452 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1453 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1454 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1455 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1456 : -1);
1457 if (bitmap->bits_per_pixel < 0)
1458 /* We don't suport that kind of pixel mode. */
1459 return -1;
c2f5bfd6
KH
1460 bitmap->rows = ft_face->glyph->bitmap.rows;
1461 bitmap->width = ft_face->glyph->bitmap.width;
1462 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1463 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1464 bitmap->left = ft_face->glyph->bitmap_left;
1465 bitmap->top = ft_face->glyph->bitmap_top;
1466 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1467 bitmap->extra = NULL;
1468
1469 return 0;
1470}
1471
1472static int
49eaafba
PE
1473ftfont_anchor_point (struct font *font, unsigned int code, int idx,
1474 int *x, int *y)
c2f5bfd6
KH
1475{
1476 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1477 FT_Face ft_face = ftfont_info->ft_size->face;
1478
1479 if (ftfont_info->ft_size != ft_face->size)
1480 FT_Activate_Size (ftfont_info->ft_size);
1481 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1482 return -1;
1483 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1484 return -1;
49eaafba 1485 if (idx >= ft_face->glyph->outline.n_points)
c2f5bfd6 1486 return -1;
49eaafba
PE
1487 *x = ft_face->glyph->outline.points[idx].x;
1488 *y = ft_face->glyph->outline.points[idx].y;
c2f5bfd6
KH
1489 return 0;
1490}
1491
de023c40 1492#ifdef HAVE_LIBOTF
e302a291
KH
1493
1494static Lisp_Object
d5a3eaaf 1495ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
e302a291
KH
1496{
1497 Lisp_Object scripts, langsyses, features, sym;
39356621 1498 int i, j, k, l;
e302a291
KH
1499
1500 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1501 {
1502 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1503
1504 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1505 {
1506 OTF_LangSys *otf_langsys;
1507
1508 if (j >= 0)
1509 otf_langsys = otf_script->LangSys + j;
1510 else if (otf_script->DefaultLangSysOffset)
1511 otf_langsys = &otf_script->DefaultLangSys;
1512 else
1513 break;
1514
1515 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1516 {
39356621 1517 l = otf_langsys->FeatureIndex[k];
064766f2 1518 if (l >= gsub_gpos->FeatureList.FeatureCount)
39356621
KH
1519 continue;
1520 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
e302a291
KH
1521 features = Fcons (sym, features);
1522 }
1523 if (j >= 0)
1524 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1525 else
1526 sym = Qnil;
1527 langsyses = Fcons (Fcons (sym, features), langsyses);
1528 }
8510724d 1529
e302a291
KH
1530 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1531 scripts = Fcons (Fcons (sym, langsyses), scripts);
1532 }
1533 return scripts;
1534
1535}
1536
1537
1538static Lisp_Object
d5a3eaaf 1539ftfont_otf_capability (struct font *font)
e302a291
KH
1540{
1541 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1542 OTF *otf = ftfont_get_otf (ftfont_info);
1543 Lisp_Object gsub_gpos;
1544
1545 if (! otf)
1546 return Qnil;
1547 gsub_gpos = Fcons (Qnil, Qnil);
064766f2
KH
1548 if (OTF_get_table (otf, "GSUB") == 0
1549 && otf->gsub->FeatureList.FeatureCount > 0)
e302a291 1550 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
064766f2
KH
1551 if (OTF_get_table (otf, "GPOS") == 0
1552 && otf->gpos->FeatureList.FeatureCount > 0)
e302a291
KH
1553 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1554 return gsub_gpos;
1555}
1556
de023c40
KH
1557#ifdef HAVE_M17N_FLT
1558
c90ca7b7
KH
1559#if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1560 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
c4170e32
KH
1561/* We can use the new feature of libotf and m17n-flt to handle the
1562 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1563 some Agian scripts. */
1564#define M17N_FLT_USE_NEW_FEATURE
1565#endif
1566
de023c40
KH
1567struct MFLTFontFT
1568{
1569 MFLTFont flt_font;
1570 struct font *font;
1571 FT_Face ft_face;
1572 OTF *otf;
d0db2ec8 1573 FT_Matrix *matrix;
de023c40
KH
1574};
1575
1576static int
d5a3eaaf
AS
1577ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1578 int from, int to)
de023c40
KH
1579{
1580 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1581 FT_Face ft_face = flt_font_ft->ft_face;
1582 MFLTGlyph *g;
1583
1584 for (g = gstring->glyphs + from; from < to; g++, from++)
1585 if (! g->encoded)
1586 {
1587 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1588
1589 g->code = code > 0 ? code : FONT_INVALID_CODE;
1590 g->encoded = 1;
1591 }
1592 return 0;
1593}
1594
d0db2ec8
KH
1595/* Operators for 26.6 fixed fractional pixel format */
1596
1597#define FLOOR(x) ((x) & -64)
1598#define CEIL(x) (((x)+63) & -64)
1599#define ROUND(x) (((x)+32) & -64)
1600
de023c40 1601static int
d5a3eaaf
AS
1602ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1603 int from, int to)
de023c40
KH
1604{
1605 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1606 FT_Face ft_face = flt_font_ft->ft_face;
1607 MFLTGlyph *g;
1608
1609 for (g = gstring->glyphs + from; from < to; g++, from++)
1610 if (! g->measured)
1611 {
1612 if (g->code != FONT_INVALID_CODE)
1613 {
1614 FT_Glyph_Metrics *m;
1615
1616 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1617 abort ();
1618 m = &ft_face->glyph->metrics;
d0db2ec8
KH
1619 if (flt_font_ft->matrix)
1620 {
1621 FT_Vector v[4];
1622 int i;
1623
1624 v[0].x = v[1].x = m->horiBearingX;
1625 v[2].x = v[3].x = m->horiBearingX + m->width;
1626 v[0].y = v[2].y = m->horiBearingY;
1627 v[1].y = v[3].y = m->horiBearingY - m->height;
1628 for (i = 0; i < 4; i++)
1629 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1630 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1631 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1632 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1633 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1634 }
1635 else
1636 {
1637 g->lbearing = FLOOR (m->horiBearingX);
1638 g->rbearing = CEIL (m->horiBearingX + m->width);
1639 g->ascent = CEIL (m->horiBearingY);
1640 g->descent = - FLOOR (m->horiBearingY - m->height);
1641 }
1642 g->xadv = ROUND (ft_face->glyph->advance.x);
de023c40
KH
1643 }
1644 else
1645 {
1646 g->lbearing = 0;
42984a74 1647 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
de023c40
KH
1648 g->ascent = flt_font_ft->font->ascent << 6;
1649 g->descent = flt_font_ft->font->descent << 6;
1650 }
1651 g->yadv = 0;
1652 g->measured = 1;
1653 }
1654 return 0;
1655}
1656
2a46904e 1657static int
de023c40
KH
1658ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1659{
78a21772
KH
1660#define FEATURE_NONE(IDX) (! spec->features[IDX])
1661
1662#define FEATURE_ANY(IDX) \
1663 (spec->features[IDX] \
1664 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1665
de023c40
KH
1666 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1667 OTF *otf = flt_font_ft->otf;
1668 OTF_Tag *tags;
1669 int i, n, negative;
1670
78a21772 1671 if (FEATURE_ANY (0) && FEATURE_ANY (1))
fa3f6039
KH
1672 /* Return 1 iff any of GSUB or GPOS support the script (and language). */
1673 return (otf
1674 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1675 NULL, 0) > 0
1676 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1677 NULL, 0) > 0));
1678
de023c40 1679 for (i = 0; i < 2; i++)
78a21772 1680 if (! FEATURE_ANY (i))
fa3f6039 1681 {
78a21772 1682 if (FEATURE_NONE (i))
fa3f6039 1683 {
78a21772
KH
1684 if (otf
1685 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1686 NULL, 0) > 0)
1687 return 0;
1688 continue;
fa3f6039
KH
1689 }
1690 if (spec->features[i][0] == 0xFFFFFFFF)
1691 {
78a21772
KH
1692 if (! otf
1693 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1694 NULL, 0) <= 0)
fa3f6039
KH
1695 continue;
1696 }
78a21772 1697 else if (! otf)
fa3f6039 1698 return 0;
fa3f6039
KH
1699 for (n = 1; spec->features[i][n]; n++);
1700 tags = alloca (sizeof (OTF_Tag) * n);
1701 for (n = 0, negative = 0; spec->features[i][n]; n++)
1702 {
1703 if (spec->features[i][n] == 0xFFFFFFFF)
1704 negative = 1;
1705 else if (negative)
1706 tags[n - 1] = spec->features[i][n] | 0x80000000;
1707 else
1708 tags[n] = spec->features[i][n];
1709 }
c4170e32 1710#ifdef M17N_FLT_USE_NEW_FEATURE
fa3f6039
KH
1711 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1712 tags, n - negative) != 1)
1713 return 0;
c4170e32 1714#else /* not M17N_FLT_USE_NEW_FEATURE */
fa3f6039
KH
1715 if (n - negative > 0
1716 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1717 tags, n - negative) != 1)
1718 return 0;
c4170e32 1719#endif /* not M17N_FLT_USE_NEW_FEATURE */
fa3f6039 1720 }
de023c40 1721 return 1;
78a21772
KH
1722#undef FEATURE_NONE
1723#undef FEATURE_ANY
de023c40
KH
1724}
1725
1726#define DEVICE_DELTA(table, size) \
1727 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1728 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1729 : 0)
1730
1731static void
1732adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1733 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1734{
1735 if (anchor->AnchorFormat == 2)
1736 {
1737 FT_Outline *outline;
1738 int ap = anchor->f.f1.AnchorPoint;
1739
1740 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1741 outline = &ft_face->glyph->outline;
1742 if (ap < outline->n_points)
1743 {
1744 *x = outline->points[ap].x << 6;
1745 *y = outline->points[ap].y << 6;
1746 }
1747 }
1748 else if (anchor->AnchorFormat == 3)
1749 {
d90bfd1c
KH
1750 if (anchor->f.f2.XDeviceTable.offset
1751 && anchor->f.f2.XDeviceTable.DeltaValue)
de023c40 1752 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
d90bfd1c
KH
1753 if (anchor->f.f2.YDeviceTable.offset
1754 && anchor->f.f2.YDeviceTable.DeltaValue)
de023c40
KH
1755 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1756 }
1757}
1758
1759static OTF_GlyphString otf_gstring;
1760
2b33f1ef
KH
1761static void
1762setup_otf_gstring (int size)
1763{
1764 if (otf_gstring.size == 0)
1765 {
c6da7cd2 1766 otf_gstring.glyphs = (OTF_Glyph *) xmalloc (sizeof (OTF_Glyph) * size);
2b33f1ef
KH
1767 otf_gstring.size = size;
1768 }
1769 else if (otf_gstring.size < size)
1770 {
c6da7cd2
JM
1771 otf_gstring.glyphs = xrealloc (otf_gstring.glyphs,
1772 sizeof (OTF_Glyph) * size);
2b33f1ef
KH
1773 otf_gstring.size = size;
1774 }
1775 otf_gstring.used = size;
1776 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1777}
1778
c4170e32
KH
1779#ifdef M17N_FLT_USE_NEW_FEATURE
1780
1781/* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1782#define PACK_OTF_TAG(TAG) \
1783 ((((TAG) & 0x7F000000) >> 3) \
1784 | (((TAG) & 0x7F0000) >> 2) \
1785 | (((TAG) & 0x7F00) >> 1) \
1786 | ((TAG) & 0x7F))
1787
1788/* Assuming that FONT is an OpenType font, apply OpenType features
1789 specified in SPEC on glyphs between FROM and TO of IN, and record
1790 the lastly applied feature in each glyph of IN. If OUT is not
1791 NULL, append the resulting glyphs to OUT while storing glyph
1792 position adjustment information in ADJUSTMENT. */
1793
1794static int
ef1b0ba7
SM
1795ftfont_drive_otf (MFLTFont *font,
1796 MFLTOtfSpec *spec,
1797 MFLTGlyphString *in,
1798 int from,
1799 int to,
1800 MFLTGlyphString *out,
1801 MFLTGlyphAdjustment *adjustment)
c4170e32
KH
1802{
1803 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1804 FT_Face ft_face = flt_font_ft->ft_face;
1805 OTF *otf = flt_font_ft->otf;
1806 int len = to - from;
1807 int i, j, gidx;
1808 OTF_Glyph *otfg;
1809 char script[5], *langsys = NULL;
1810 char *gsub_features = NULL, *gpos_features = NULL;
1811 OTF_Feature *features;
1812
1813 if (len == 0)
1814 return from;
1815 OTF_tag_name (spec->script, script);
1816 if (spec->langsys)
1817 {
1818 langsys = alloca (5);
1819 OTF_tag_name (spec->langsys, langsys);
1820 }
1821 for (i = 0; i < 2; i++)
1822 {
1823 char *p;
1824
1825 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1826 {
1827 for (j = 0; spec->features[i][j]; j++);
1828 if (i == 0)
1829 p = gsub_features = alloca (6 * j);
1830 else
1831 p = gpos_features = alloca (6 * j);
1832 for (j = 0; spec->features[i][j]; j++)
1833 {
1834 if (spec->features[i][j] == 0xFFFFFFFF)
1835 *p++ = '*', *p++ = ',';
1836 else
1837 {
1838 OTF_tag_name (spec->features[i][j], p);
1839 p[4] = ',';
1840 p += 5;
1841 }
1842 }
1843 *--p = '\0';
1844 }
1845 }
1846
1847 setup_otf_gstring (len);
1848 for (i = 0; i < len; i++)
1849 {
1850 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
1851 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1852 }
1853
1854 OTF_drive_gdef (otf, &otf_gstring);
1855 gidx = out ? out->used : from;
1856
1857 if (gsub_features && out)
1858 {
1859 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1860 gsub_features) < 0)
1861 goto simple_copy;
1862 if (out->allocated < out->used + otf_gstring.used)
1863 return -2;
1864 features = otf->gsub->FeatureList.Feature;
1865 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1866 {
1867 MFLTGlyph *g;
1868 int min_from, max_to;
c4170e32
KH
1869 int feature_idx = otfg->positioning_type >> 4;
1870
1871 g = out->glyphs + out->used;
1872 *g = in->glyphs[from + otfg->f.index.from];
1873 if (g->code != otfg->glyph_id)
1874 {
1875 g->c = 0;
1876 g->code = otfg->glyph_id;
1877 g->measured = 0;
1878 }
1879 out->used++;
1880 min_from = g->from;
1881 max_to = g->to;
1882 if (otfg->f.index.from < otfg->f.index.to)
1883 {
1884 /* OTFG substitutes multiple glyphs in IN. */
1885 for (j = from + otfg->f.index.from + 1;
1886 j <= from + otfg->f.index.to; j++)
1887 {
1888 if (min_from > in->glyphs[j].from)
1889 min_from = in->glyphs[j].from;
1890 if (max_to < in->glyphs[j].to)
1891 max_to = in->glyphs[j].to;
1892 }
1893 g->from = min_from;
1894 g->to = max_to;
1895 }
1896 if (feature_idx)
1897 {
1898 unsigned int tag = features[feature_idx - 1].FeatureTag;
1899 tag = PACK_OTF_TAG (tag);
1900 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1901 }
1902 for (i++, otfg++; (i < otf_gstring.used
1903 && otfg->f.index.from == otfg[-1].f.index.from);
1904 i++, otfg++)
1905 {
1906 g = out->glyphs + out->used;
1907 *g = in->glyphs[from + otfg->f.index.to];
1908 if (g->code != otfg->glyph_id)
1909 {
1910 g->c = 0;
1911 g->code = otfg->glyph_id;
1912 g->measured = 0;
1913 }
1914 feature_idx = otfg->positioning_type >> 4;
1915 if (feature_idx)
1916 {
1917 unsigned int tag = features[feature_idx - 1].FeatureTag;
1918 tag = PACK_OTF_TAG (tag);
1919 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1920 }
1921 out->used++;
1922 }
1923 }
1924 }
1925 else if (gsub_features)
1926 {
1927 /* Just for checking which features will be applied. */
1928 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1929 gsub_features) < 0)
1930 goto simple_copy;
1931 features = otf->gsub->FeatureList.Feature;
1932 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1933 otfg++)
1934 {
1935 int feature_idx = otfg->positioning_type >> 4;
1936
1937 if (feature_idx)
1938 {
1939 unsigned int tag = features[feature_idx - 1].FeatureTag;
1940 tag = PACK_OTF_TAG (tag);
1941 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1942 {
1943 MFLTGlyph *g = in->glyphs + (from + j);
1944 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1945 }
1946 }
1947 }
1948 }
1949 else if (out)
1950 {
1951 if (out->allocated < out->used + len)
1952 return -2;
1953 for (i = 0; i < len; i++)
1954 out->glyphs[out->used++] = in->glyphs[from + i];
1955 }
1956
1957 if (gpos_features && out)
1958 {
1959 MFLTGlyph *base = NULL, *mark = NULL, *g;
1960 int x_ppem, y_ppem, x_scale, y_scale;
1961
1962 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1963 gpos_features) < 0)
1964 return to;
1965 features = otf->gpos->FeatureList.Feature;
1966 x_ppem = ft_face->size->metrics.x_ppem;
1967 y_ppem = ft_face->size->metrics.y_ppem;
1968 x_scale = ft_face->size->metrics.x_scale;
1969 y_scale = ft_face->size->metrics.y_scale;
1970
1971 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1972 i < otf_gstring.used; i++, otfg++, g++)
1973 {
1974 MFLTGlyph *prev;
1975 int feature_idx = otfg->positioning_type >> 4;
1976
1977 if (feature_idx)
1978 {
1979 unsigned int tag = features[feature_idx - 1].FeatureTag;
1980 tag = PACK_OTF_TAG (tag);
1981 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1982 }
1983
1984 if (! otfg->glyph_id)
1985 continue;
1986 switch (otfg->positioning_type & 0xF)
1987 {
1988 case 0:
1989 break;
1990 case 1: /* Single */
1991 case 2: /* Pair */
1992 {
1993 int format = otfg->f.f1.format;
1994
1995 if (format & OTF_XPlacement)
1996 adjustment[i].xoff
1997 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
1998 if (format & OTF_XPlaDevice)
1999 adjustment[i].xoff
2000 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2001 if (format & OTF_YPlacement)
2002 adjustment[i].yoff
2003 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2004 if (format & OTF_YPlaDevice)
2005 adjustment[i].yoff
2006 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2007 if (format & OTF_XAdvance)
2008 adjustment[i].xadv
2009 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2010 if (format & OTF_XAdvDevice)
2011 adjustment[i].xadv
2012 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2013 if (format & OTF_YAdvance)
2014 adjustment[i].yadv
2015 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2016 if (format & OTF_YAdvDevice)
2017 adjustment[i].yadv
2018 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2019 adjustment[i].set = 1;
2020 }
2021 break;
2022 case 3: /* Cursive */
2023 /* Not yet supported. */
2024 break;
2025 case 4: /* Mark-to-Base */
2026 case 5: /* Mark-to-Ligature */
2027 if (! base)
2028 break;
2029 prev = base;
2030 goto label_adjust_anchor;
2031 default: /* i.e. case 6 Mark-to-Mark */
2032 if (! mark)
2033 break;
2034 prev = mark;
2035
2036 label_adjust_anchor:
2037 {
2038 int base_x, base_y, mark_x, mark_y;
2039 int this_from, this_to;
2040
2041 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2042 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2043 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2044 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2045
2046 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2047 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2048 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2049 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2050 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2051 x_ppem, y_ppem, &mark_x, &mark_y);
2052 adjustment[i].xoff = (base_x - mark_x);
2053 adjustment[i].yoff = - (base_y - mark_y);
2054 adjustment[i].back = (g - prev);
2055 adjustment[i].xadv = 0;
2056 adjustment[i].advance_is_absolute = 1;
2057 adjustment[i].set = 1;
2058 this_from = g->from;
2059 this_to = g->to;
2060 for (j = 0; prev + j < g; j++)
2061 {
2062 if (this_from > prev[j].from)
2063 this_from = prev[j].from;
2064 if (this_to < prev[j].to)
2065 this_to = prev[j].to;
2066 }
2067 for (; prev <= g; prev++)
2068 {
2069 prev->from = this_from;
2070 prev->to = this_to;
2071 }
2072 }
2073 }
2074 if (otfg->GlyphClass == OTF_GlyphClass0)
2075 base = mark = g;
2076 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2077 mark = g;
2078 else
2079 base = g;
2080 }
2081 }
2082 else if (gpos_features)
2083 {
2084 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2085 gpos_features) < 0)
2086 return to;
2087 features = otf->gpos->FeatureList.Feature;
2088 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2089 i++, otfg++)
2090 if (otfg->positioning_type & 0xF)
2091 {
2092 int feature_idx = otfg->positioning_type >> 4;
2093
2094 if (feature_idx)
2095 {
2096 unsigned int tag = features[feature_idx - 1].FeatureTag;
2097 tag = PACK_OTF_TAG (tag);
2098 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2099 {
2100 MFLTGlyph *g = in->glyphs + (from + j);
2101 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2102 }
2103 }
2104 }
2105 }
2106 return to;
2107
2108 simple_copy:
2109 if (! out)
2110 return to;
2111 if (out->allocated < out->used + len)
2112 return -2;
2113 font->get_metrics (font, in, from, to);
2114 memcpy (out->glyphs + out->used, in->glyphs + from,
2115 sizeof (MFLTGlyph) * len);
2116 out->used += len;
2117 return to;
2118}
2119
9fa82824 2120static int
c4170e32
KH
2121ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2122 MFLTGlyphString *in, int from, int to)
2123{
2124 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2125}
2126
2127#else /* not M17N_FLT_USE_NEW_FEATURE */
2b33f1ef 2128
2a46904e 2129static int
d5a3eaaf
AS
2130ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2131 int from, int to,
2132 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
de023c40
KH
2133{
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;
2142
2143 if (len == 0)
2144 return from;
2145 OTF_tag_name (spec->script, script);
2146 if (spec->langsys)
2147 {
2148 langsys = alloca (5);
2149 OTF_tag_name (spec->langsys, langsys);
2150 }
2151 for (i = 0; i < 2; i++)
2152 {
2153 char *p;
2154
2155 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2156 {
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++)
2163 {
2164 if (spec->features[i][j] == 0xFFFFFFFF)
2165 *p++ = '*', *p++ = ',';
2166 else
2167 {
2168 OTF_tag_name (spec->features[i][j], p);
2169 p[4] = ',';
2170 p += 5;
2171 }
2172 }
2173 *--p = '\0';
2174 }
2175 }
2176
2b33f1ef 2177 setup_otf_gstring (len);
de023c40
KH
2178 for (i = 0; i < len; i++)
2179 {
2180 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2181 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2182 }
2183
2184 OTF_drive_gdef (otf, &otf_gstring);
2185 gidx = out->used;
2186
2187 if (gsub_features)
2188 {
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;
7d2fd545 2194 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
de023c40 2195 {
7d2fd545
KH
2196 MFLTGlyph *g;
2197 int min_from, max_to;
de023c40
KH
2198 int j;
2199
7d2fd545 2200 g = out->glyphs + out->used;
de023c40 2201 *g = in->glyphs[from + otfg->f.index.from];
de023c40
KH
2202 if (g->code != otfg->glyph_id)
2203 {
7d2fd545 2204 g->c = 0;
de023c40
KH
2205 g->code = otfg->glyph_id;
2206 g->measured = 0;
2207 }
2208 out->used++;
7d2fd545
KH
2209 min_from = g->from;
2210 max_to = g->to;
2211 if (otfg->f.index.from < otfg->f.index.to)
2212 {
2213 /* OTFG substitutes multiple glyphs in IN. */
2214 for (j = from + otfg->f.index.from + 1;
2215 j <= from + otfg->f.index.to; j++)
2216 {
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;
2221 }
2222 g->from = min_from;
2223 g->to = max_to;
2224 }
2225 for (i++, otfg++; (i < otf_gstring.used
2226 && otfg->f.index.from == otfg[-1].f.index.from);
2227 i++, otfg++)
2228 {
2229 g = out->glyphs + out->used;
2230 *g = in->glyphs[from + otfg->f.index.to];
2231 if (g->code != otfg->glyph_id)
2232 {
2233 g->c = 0;
2234 g->code = otfg->glyph_id;
2235 g->measured = 0;
2236 }
2237 out->used++;
2238 }
de023c40
KH
2239 }
2240 }
2241 else
2242 {
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];
2247 }
2248
2249 if (gpos_features)
2250 {
2251 MFLTGlyph *base = NULL, *mark = NULL, *g;
2252 int x_ppem, y_ppem, x_scale, y_scale;
2253
2254 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2255 < 0)
2256 return to;
2257
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;
2262
2263 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2264 i < otf_gstring.used; i++, otfg++, g++)
2265 {
2266 MFLTGlyph *prev;
2267
2268 if (! otfg->glyph_id)
2269 continue;
2270 switch (otfg->positioning_type)
2271 {
2272 case 0:
2273 break;
2274 case 1: /* Single */
2275 case 2: /* Pair */
2276 {
2277 int format = otfg->f.f1.format;
2278
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;
2304 }
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;
2319
2320 label_adjust_anchor:
2321 {
2322 int base_x, base_y, mark_x, mark_y;
2323 int this_from, this_to;
2324
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;
8510724d 2328 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
de023c40
KH
2329
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++)
2345 {
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;
2350 }
2351 for (; prev <= g; prev++)
2352 {
2353 prev->from = this_from;
2354 prev->to = this_to;
2355 }
2356 }
2357 }
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;
2364 }
2365 }
2366 return to;
2367
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;
2376}
2377
c4170e32
KH
2378#endif /* not M17N_FLT_USE_NEW_FEATURE */
2379
de023c40
KH
2380static MFLTGlyphString gstring;
2381
2382static int m17n_flt_initialized;
2383
990a73f0 2384static Lisp_Object
d5a3eaaf
AS
2385ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2386 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
de023c40 2387{
b02c740e
PE
2388 EMACS_INT len = LGSTRING_GLYPH_LEN (lgstring);
2389 EMACS_INT i;
de023c40 2390 struct MFLTFontFT flt_font_ft;
da2cf488 2391 MFLT *flt = NULL;
2b33f1ef 2392 int with_variation_selector = 0;
de023c40
KH
2393
2394 if (! m17n_flt_initialized)
2395 {
2396 M17N_INIT ();
c4170e32
KH
2397#ifdef M17N_FLT_USE_NEW_FEATURE
2398 mflt_enable_new_feature = 1;
2399 mflt_try_otf = ftfont_try_otf;
2400#endif /* M17N_FLT_USE_NEW_FEATURE */
de023c40
KH
2401 m17n_flt_initialized = 1;
2402 }
2403
2404 for (i = 0; i < len; i++)
2b33f1ef
KH
2405 {
2406 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2407 int c;
2408
2409 if (NILP (g))
2410 break;
2411 c = LGLYPH_CHAR (g);
2412 if (CHAR_VARIATION_SELECTOR_P (c))
2413 with_variation_selector++;
2414 }
f2ed8a70 2415
de023c40 2416 len = i;
f2ed8a70
PE
2417 lint_assume (len <= TYPE_MAXIMUM (EMACS_INT) - 2);
2418
2b33f1ef
KH
2419 if (with_variation_selector)
2420 {
2421 setup_otf_gstring (len);
2422 for (i = 0; i < len; i++)
2423 {
2424 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2425
2426 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2427 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2428 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2429 }
2430 OTF_drive_cmap (otf, &otf_gstring);
2431 for (i = 0; i < otf_gstring.used; i++)
2432 {
2433 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2434 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2435 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2436
2437 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2438 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2439 LGSTRING_SET_GLYPH (lgstring, i, g0);
2440 }
2441 if (len > otf_gstring.used)
2442 {
2443 len = otf_gstring.used;
2444 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2445 }
2446 }
de023c40
KH
2447
2448 if (gstring.allocated == 0)
2449 {
2450 gstring.allocated = len * 2;
2451 gstring.glyph_size = sizeof (MFLTGlyph);
c6da7cd2 2452 gstring.glyphs = xmalloc (sizeof (MFLTGlyph) * gstring.allocated);
de023c40
KH
2453 }
2454 else if (gstring.allocated < len * 2)
2455 {
2456 gstring.allocated = len * 2;
c6da7cd2
JM
2457 gstring.glyphs = xrealloc (gstring.glyphs,
2458 sizeof (MFLTGlyph) * gstring.allocated);
de023c40 2459 }
2b33f1ef 2460 memset (gstring.glyphs, 0, sizeof (MFLTGlyph) * len);
de023c40 2461 for (i = 0; i < len; i++)
2b33f1ef
KH
2462 {
2463 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2464
2465 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2466 if (with_variation_selector)
2467 {
2468 gstring.glyphs[i].code = LGLYPH_CODE (g);
2469 gstring.glyphs[i].encoded = 1;
2470 }
2471 }
2472
de023c40
KH
2473 gstring.used = len;
2474 gstring.r2l = 0;
2475
2476 {
2477 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2478
2479 if (NILP (family))
2480 flt_font_ft.flt_font.family = Mnil;
2481 else
21988a08 2482 flt_font_ft.flt_font.family
51b59d79 2483 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
de023c40
KH
2484 }
2485 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2486 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2487 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2488 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2489 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2490 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2491 flt_font_ft.flt_font.internal = NULL;
2492 flt_font_ft.font = font;
2493 flt_font_ft.ft_face = ft_face;
2494 flt_font_ft.otf = otf;
d0db2ec8 2495 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
7bf1bb21
KH
2496 if (len > 1
2497 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
da2cf488
KH
2498 /* A little bit ad hoc. Perhaps, shaper must get script and
2499 language information, and select a proper flt for them
2500 here. */
2501 flt = mflt_get (msymbol ("combining"));
de023c40
KH
2502 for (i = 0; i < 3; i++)
2503 {
da2cf488 2504 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
de023c40
KH
2505 if (result != -2)
2506 break;
2507 gstring.allocated += gstring.allocated;
c6da7cd2
JM
2508 gstring.glyphs = xrealloc (gstring.glyphs,
2509 sizeof (MFLTGlyph) * gstring.allocated);
de023c40 2510 }
89a95b7c 2511 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
de023c40
KH
2512 return Qnil;
2513 for (i = 0; i < gstring.used; i++)
2514 {
2515 MFLTGlyph *g = gstring.glyphs + i;
2516
2517 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2518 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2519 }
2520
2521 for (i = 0; i < gstring.used; i++)
2522 {
2523 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2524 MFLTGlyph *g = gstring.glyphs + i;
2525
4cec6061
KH
2526 if (NILP (lglyph))
2527 {
2528 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2529 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2530 }
de023c40
KH
2531 LGLYPH_SET_FROM (lglyph, g->from);
2532 LGLYPH_SET_TO (lglyph, g->to);
2533 LGLYPH_SET_CHAR (lglyph, g->c);
2534 LGLYPH_SET_CODE (lglyph, g->code);
2535 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2536 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2537 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2538 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2539 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2540 if (g->adjusted)
2541 {
2542 Lisp_Object vec;
2543
2544 vec = Fmake_vector (make_number (3), Qnil);
2545 ASET (vec, 0, make_number (g->xoff >> 6));
2546 ASET (vec, 1, make_number (g->yoff >> 6));
2547 ASET (vec, 2, make_number (g->xadv >> 6));
2548 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2549 }
2550 }
2551 return make_number (i);
2552}
2553
2554Lisp_Object
d5a3eaaf 2555ftfont_shape (Lisp_Object lgstring)
de023c40
KH
2556{
2557 struct font *font;
2558 struct ftfont_info *ftfont_info;
e302a291 2559 OTF *otf;
de023c40
KH
2560
2561 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2562 ftfont_info = (struct ftfont_info *) font;
e302a291
KH
2563 otf = ftfont_get_otf (ftfont_info);
2564 if (! otf)
4cc1c806 2565 return make_number (0);
d0db2ec8
KH
2566 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2567 &ftfont_info->matrix);
de023c40
KH
2568}
2569
e3869731
KH
2570#endif /* HAVE_M17N_FLT */
2571
2b33f1ef
KH
2572#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2573
2574static int
d5a3eaaf 2575ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2b33f1ef
KH
2576{
2577 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2578 OTF *otf = ftfont_get_otf (ftfont_info);
2579
2580 if (! otf)
2581 return 0;
2582 return OTF_get_variation_glyphs (otf, c, variations);
2583}
2584
2585#endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
de023c40
KH
2586#endif /* HAVE_LIBOTF */
2587
0b966021 2588Lisp_Object
7d7ad10e 2589ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
0b966021 2590{
e907d979 2591 FcChar8 *str;
0b966021 2592
e907d979 2593#ifdef FC_FONTFORMAT
7d7ad10e 2594 if (pattern)
719b3d63 2595 {
7d7ad10e
KH
2596 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2597 return Qnil;
2598 if (strcmp ((char *) str, "TrueType") == 0)
719b3d63 2599 return intern ("truetype");
7d7ad10e 2600 if (strcmp ((char *) str, "Type 1") == 0)
719b3d63 2601 return intern ("type1");
7d7ad10e 2602 if (strcmp ((char *) str, "PCF") == 0)
719b3d63 2603 return intern ("pcf");
7d7ad10e 2604 if (strcmp ((char *) str, "BDF") == 0)
719b3d63
KH
2605 return intern ("bdf");
2606 }
7d7ad10e
KH
2607#endif /* FC_FONTFORMAT */
2608 if (STRINGP (filename))
2609 {
2610 int len = SBYTES (filename);
2611
2612 if (len >= 4)
2613 {
2614 str = (FcChar8 *) (SDATA (filename) + len - 4);
2615 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2616 return intern ("truetype");
2617 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2618 return intern ("type1");
2619 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2620 return intern ("pcf");
2621 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2622 return intern ("bdf");
2623 }
2624 }
0b966021
KH
2625 return intern ("unknown");
2626}
2627
3106121c 2628static const char *const ftfont_booleans [] = {
637fa988
JD
2629 ":antialias",
2630 ":hinting",
2631 ":verticallayout",
2632 ":autohint",
2633 ":globaladvance",
2634 ":outline",
2635 ":scalable",
2636 ":minspace",
2637 ":embolden",
2638 NULL,
2639};
2640
3106121c 2641static const char *const ftfont_non_booleans [] = {
637fa988
JD
2642 ":family",
2643 ":familylang",
2644 ":style",
2645 ":stylelang",
2646 ":fullname",
2647 ":fullnamelang",
2648 ":slant",
2649 ":weight",
2650 ":size",
2651 ":width",
2652 ":aspect",
2653 ":pixelsize",
2654 ":spacing",
2655 ":foundry",
2656 ":hintstyle",
2657 ":file",
2658 ":index",
2659 ":ftface",
2660 ":rasterizer",
2661 ":scale",
2662 ":dpi",
2663 ":rgba",
2664 ":lcdfilter",
2665 ":charset",
2666 ":lang",
2667 ":fontversion",
2668 ":capability",
2669 NULL,
2670};
2671
2672static void
971de7fb 2673ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
637fa988 2674{
9fa82824 2675 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
637fa988
JD
2676}
2677
2678
c2f5bfd6 2679void
971de7fb 2680syms_of_ftfont (void)
c2f5bfd6 2681{
706b6995
KH
2682 DEFSYM (Qfreetype, "freetype");
2683 DEFSYM (Qmonospace, "monospace");
2684 DEFSYM (Qsans_serif, "sans-serif");
2685 DEFSYM (Qserif, "serif");
2686 DEFSYM (Qmono, "mono");
2687 DEFSYM (Qsans, "sans");
2688 DEFSYM (Qsans__serif, "sans serif");
2689
c2f5bfd6 2690 staticpro (&freetype_font_cache);
c2801c99 2691 freetype_font_cache = Fcons (Qt, Qnil);
c2f5bfd6 2692
706b6995
KH
2693 staticpro (&ftfont_generic_family_list);
2694 ftfont_generic_family_list
2695 = Fcons (Fcons (Qmonospace, Qt),
2696 Fcons (Fcons (Qsans_serif, Qt),
2697 Fcons (Fcons (Qsans, Qt), Qnil)));
c2f5bfd6 2698
21988a08
KH
2699 staticpro (&ft_face_cache);
2700 ft_face_cache = Qnil;
2701
c2f5bfd6
KH
2702 ftfont_driver.type = Qfreetype;
2703 register_font_driver (&ftfont_driver, NULL);
2704}