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