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