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