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