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