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