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