Merge: * charset.c: conform to C89 pointer rules
[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)
1025 || xstrcasecmp (SDATA (SYMBOL_NAME (adstyle)),
1026 SDATA (SYMBOL_NAME (this_adstyle))) != 0))
1027 continue;
1028 if (langname
1029 && ! NILP (this_adstyle)
1030 && xstrcasecmp (langname, SDATA (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;
769e9d47 1243 if (spacing != FC_PROPORTIONAL && spacing != FC_DUAL)
42984a74
KH
1244 font->min_width = font->average_width = font->space_width
1245 = (scalable ? ft_face->max_advance_width * size / upEM
1246 : ft_face->size->metrics.max_advance >> 6);
c2f5bfd6
KH
1247 else
1248 {
42984a74 1249 int n;
c2f5bfd6 1250
42984a74
KH
1251 font->min_width = font->average_width = font->space_width = 0;
1252 for (i = 32, n = 0; i < 127; i++)
0c26f026 1253 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) == 0)
42984a74
KH
1254 {
1255 int this_width = ft_face->glyph->metrics.horiAdvance >> 6;
1256
1257 if (this_width > 0
1258 && (! font->min_width || font->min_width > this_width))
1259 font->min_width = this_width;
1260 if (i == 32)
1261 font->space_width = this_width;
1262 font->average_width += this_width;
1263 n++;
1264 }
1265 if (n > 0)
1266 font->average_width /= n;
c2f5bfd6
KH
1267 }
1268
42984a74
KH
1269 font->baseline_offset = 0;
1270 font->relative_compose = 0;
1271 font->default_ascent = 0;
1272 font->vertical_centering = 0;
1273 if (scalable)
1274 {
1275 font->underline_position = -ft_face->underline_position * size / upEM;
0c26f026 1276 font->underline_thickness = ft_face->underline_thickness * size / upEM;
42984a74
KH
1277 }
1278 else
1279 {
1280 font->underline_position = -1;
1281 font->underline_thickness = 0;
1282 }
c2f5bfd6 1283
42984a74 1284 return font_object;
c2f5bfd6
KH
1285}
1286
1287static void
971de7fb 1288ftfont_close (FRAME_PTR f, struct font *font)
c2f5bfd6
KH
1289{
1290 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
21988a08 1291 Lisp_Object val, cache;
c2f5bfd6 1292
e302a291 1293 val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
d7782105 1294 cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
e302a291 1295 xassert (CONSP (cache));
21988a08 1296 val = XCDR (cache);
c2f5bfd6
KH
1297 (XSAVE_VALUE (val)->integer)--;
1298 if (XSAVE_VALUE (val)->integer == 0)
de023c40 1299 {
e302a291 1300 struct ftfont_cache_data *cache_data = XSAVE_VALUE (val)->pointer;
21988a08 1301
e302a291 1302 FT_Done_Face (cache_data->ft_face);
de023c40
KH
1303#ifdef HAVE_LIBOTF
1304 if (ftfont_info->otf)
1305 OTF_close (ftfont_info->otf);
1306#endif
e302a291 1307 cache_data->ft_face = NULL;
de023c40 1308 }
c2f5bfd6
KH
1309 else
1310 FT_Done_Size (ftfont_info->ft_size);
c2f5bfd6
KH
1311}
1312
2a46904e 1313static int
971de7fb 1314ftfont_has_char (Lisp_Object font, int c)
c2f5bfd6 1315{
d7782105
KH
1316 struct charset *cs = NULL;
1317
1318 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
1319 && charset_jisx0208 >= 0)
1320 cs = CHARSET_FROM_ID (charset_jisx0208);
1321 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
1322 && charset_ksc5601 >= 0)
1323 cs = CHARSET_FROM_ID (charset_ksc5601);
1324 if (cs)
1325 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
1326
7179ce7b
KH
1327 if (FONT_ENTITY_P (font))
1328 {
1329 FcCharSet *charset = ftfont_get_fc_charset (font);
c2f5bfd6 1330
7179ce7b
KH
1331 return (FcCharSetHasChar (charset, c) == FcTrue);
1332 }
1333 else
1334 {
1335 struct ftfont_info *ftfont_info;
1336
1337 ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
1338 return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
1339 != 0);
1340 }
c2f5bfd6
KH
1341}
1342
1343static unsigned
971de7fb 1344ftfont_encode_char (struct font *font, int c)
c2f5bfd6
KH
1345{
1346 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1347 FT_Face ft_face = ftfont_info->ft_size->face;
1348 FT_ULong charcode = c;
1349 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
1350
4cec6061 1351 return (code > 0 ? code : FONT_INVALID_CODE);
c2f5bfd6
KH
1352}
1353
1354static int
971de7fb 1355ftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
c2f5bfd6
KH
1356{
1357 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1358 FT_Face ft_face = ftfont_info->ft_size->face;
1359 int width = 0;
e5d05978 1360 int i, first;
c2f5bfd6
KH
1361
1362 if (ftfont_info->ft_size != ft_face->size)
1363 FT_Activate_Size (ftfont_info->ft_size);
1364 if (metrics)
72af86bd 1365 memset (metrics, 0, sizeof (struct font_metrics));
e5d05978 1366 for (i = 0, first = 1; i < nglyphs; i++)
c2f5bfd6
KH
1367 {
1368 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
1369 {
1370 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
1371
e5d05978
KH
1372 if (first)
1373 {
1374 if (metrics)
1375 {
1376 metrics->lbearing = m->horiBearingX >> 6;
1377 metrics->rbearing = (m->horiBearingX + m->width) >> 6;
1378 metrics->ascent = m->horiBearingY >> 6;
57d3b93b 1379 metrics->descent = (m->height - m->horiBearingY) >> 6;
e5d05978
KH
1380 }
1381 first = 0;
1382 }
c2f5bfd6
KH
1383 if (metrics)
1384 {
1385 if (metrics->lbearing > width + (m->horiBearingX >> 6))
1386 metrics->lbearing = width + (m->horiBearingX >> 6);
1387 if (metrics->rbearing
1388 < width + ((m->horiBearingX + m->width) >> 6))
1389 metrics->rbearing
1390 = width + ((m->horiBearingX + m->width) >> 6);
1391 if (metrics->ascent < (m->horiBearingY >> 6))
1392 metrics->ascent = m->horiBearingY >> 6;
57d3b93b
KH
1393 if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
1394 metrics->descent = (m->height - m->horiBearingY) >> 6;
c2f5bfd6
KH
1395 }
1396 width += m->horiAdvance >> 6;
1397 }
1398 else
1399 {
42984a74 1400 width += font->space_width;
c2f5bfd6
KH
1401 }
1402 }
1403 if (metrics)
1404 metrics->width = width;
1405
1406 return width;
1407}
1408
1409static int
971de7fb 1410ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
c2f5bfd6
KH
1411{
1412 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1413 FT_Face ft_face = ftfont_info->ft_size->face;
1414 FT_Int32 load_flags = FT_LOAD_RENDER;
1415
1416 if (ftfont_info->ft_size != ft_face->size)
1417 FT_Activate_Size (ftfont_info->ft_size);
1418 if (bits_per_pixel == 1)
1419 {
1420#ifdef FT_LOAD_TARGET_MONO
1421 load_flags |= FT_LOAD_TARGET_MONO;
1422#else
1423 load_flags |= FT_LOAD_MONOCHROME;
1424#endif
1425 }
1426 else if (bits_per_pixel != 8)
1427 /* We don't support such a rendering. */
1428 return -1;
1429
1430 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
1431 return -1;
b51e5112
KH
1432 bitmap->bits_per_pixel
1433 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
1434 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
1435 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
1436 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
1437 : -1);
1438 if (bitmap->bits_per_pixel < 0)
1439 /* We don't suport that kind of pixel mode. */
1440 return -1;
c2f5bfd6
KH
1441 bitmap->rows = ft_face->glyph->bitmap.rows;
1442 bitmap->width = ft_face->glyph->bitmap.width;
1443 bitmap->pitch = ft_face->glyph->bitmap.pitch;
1444 bitmap->buffer = ft_face->glyph->bitmap.buffer;
1445 bitmap->left = ft_face->glyph->bitmap_left;
1446 bitmap->top = ft_face->glyph->bitmap_top;
1447 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
1448 bitmap->extra = NULL;
1449
1450 return 0;
1451}
1452
1453static int
971de7fb 1454ftfont_anchor_point (struct font *font, unsigned int code, int index, int *x, int *y)
c2f5bfd6
KH
1455{
1456 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1457 FT_Face ft_face = ftfont_info->ft_size->face;
1458
1459 if (ftfont_info->ft_size != ft_face->size)
1460 FT_Activate_Size (ftfont_info->ft_size);
1461 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
1462 return -1;
1463 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
1464 return -1;
1465 if (index >= ft_face->glyph->outline.n_points)
1466 return -1;
1467 *x = ft_face->glyph->outline.points[index].x;
1468 *y = ft_face->glyph->outline.points[index].y;
1469 return 0;
1470}
1471
de023c40 1472#ifdef HAVE_LIBOTF
e302a291
KH
1473
1474static Lisp_Object
d5a3eaaf 1475ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
e302a291
KH
1476{
1477 Lisp_Object scripts, langsyses, features, sym;
39356621 1478 int i, j, k, l;
e302a291
KH
1479
1480 for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
1481 {
1482 OTF_Script *otf_script = gsub_gpos->ScriptList.Script + i;
1483
1484 for (langsyses = Qnil, j = otf_script->LangSysCount - 1; j >= -1; j--)
1485 {
1486 OTF_LangSys *otf_langsys;
1487
1488 if (j >= 0)
1489 otf_langsys = otf_script->LangSys + j;
1490 else if (otf_script->DefaultLangSysOffset)
1491 otf_langsys = &otf_script->DefaultLangSys;
1492 else
1493 break;
1494
1495 for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
1496 {
39356621 1497 l = otf_langsys->FeatureIndex[k];
064766f2 1498 if (l >= gsub_gpos->FeatureList.FeatureCount)
39356621
KH
1499 continue;
1500 OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
e302a291
KH
1501 features = Fcons (sym, features);
1502 }
1503 if (j >= 0)
1504 OTF_TAG_SYM (sym, otf_script->LangSysRecord[j].LangSysTag);
1505 else
1506 sym = Qnil;
1507 langsyses = Fcons (Fcons (sym, features), langsyses);
1508 }
8510724d 1509
e302a291
KH
1510 OTF_TAG_SYM (sym, gsub_gpos->ScriptList.Script[i].ScriptTag);
1511 scripts = Fcons (Fcons (sym, langsyses), scripts);
1512 }
1513 return scripts;
1514
1515}
1516
1517
1518static Lisp_Object
d5a3eaaf 1519ftfont_otf_capability (struct font *font)
e302a291
KH
1520{
1521 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
1522 OTF *otf = ftfont_get_otf (ftfont_info);
1523 Lisp_Object gsub_gpos;
1524
1525 if (! otf)
1526 return Qnil;
1527 gsub_gpos = Fcons (Qnil, Qnil);
064766f2
KH
1528 if (OTF_get_table (otf, "GSUB") == 0
1529 && otf->gsub->FeatureList.FeatureCount > 0)
e302a291 1530 XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
064766f2
KH
1531 if (OTF_get_table (otf, "GPOS") == 0
1532 && otf->gpos->FeatureList.FeatureCount > 0)
e302a291
KH
1533 XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
1534 return gsub_gpos;
1535}
1536
de023c40
KH
1537#ifdef HAVE_M17N_FLT
1538
c90ca7b7
KH
1539#if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1540 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
c4170e32
KH
1541/* We can use the new feature of libotf and m17n-flt to handle the
1542 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1543 some Agian scripts. */
1544#define M17N_FLT_USE_NEW_FEATURE
1545#endif
1546
de023c40
KH
1547struct MFLTFontFT
1548{
1549 MFLTFont flt_font;
1550 struct font *font;
1551 FT_Face ft_face;
1552 OTF *otf;
d0db2ec8 1553 FT_Matrix *matrix;
de023c40
KH
1554};
1555
1556static int
d5a3eaaf
AS
1557ftfont_get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring,
1558 int from, int to)
de023c40
KH
1559{
1560 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1561 FT_Face ft_face = flt_font_ft->ft_face;
1562 MFLTGlyph *g;
1563
1564 for (g = gstring->glyphs + from; from < to; g++, from++)
1565 if (! g->encoded)
1566 {
1567 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1568
1569 g->code = code > 0 ? code : FONT_INVALID_CODE;
1570 g->encoded = 1;
1571 }
1572 return 0;
1573}
1574
d0db2ec8
KH
1575/* Operators for 26.6 fixed fractional pixel format */
1576
1577#define FLOOR(x) ((x) & -64)
1578#define CEIL(x) (((x)+63) & -64)
1579#define ROUND(x) (((x)+32) & -64)
1580
de023c40 1581static int
d5a3eaaf
AS
1582ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring,
1583 int from, int to)
de023c40
KH
1584{
1585 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1586 FT_Face ft_face = flt_font_ft->ft_face;
1587 MFLTGlyph *g;
1588
1589 for (g = gstring->glyphs + from; from < to; g++, from++)
1590 if (! g->measured)
1591 {
1592 if (g->code != FONT_INVALID_CODE)
1593 {
1594 FT_Glyph_Metrics *m;
d0db2ec8 1595 int lbearing, rbearing, ascent, descent, xadv;
de023c40
KH
1596
1597 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1598 abort ();
1599 m = &ft_face->glyph->metrics;
d0db2ec8
KH
1600 if (flt_font_ft->matrix)
1601 {
1602 FT_Vector v[4];
1603 int i;
1604
1605 v[0].x = v[1].x = m->horiBearingX;
1606 v[2].x = v[3].x = m->horiBearingX + m->width;
1607 v[0].y = v[2].y = m->horiBearingY;
1608 v[1].y = v[3].y = m->horiBearingY - m->height;
1609 for (i = 0; i < 4; i++)
1610 FT_Vector_Transform (v + i, flt_font_ft->matrix);
1611 g->lbearing = v[0].x < v[1].x ? FLOOR (v[0].x) : FLOOR (v[1].x);
1612 g->rbearing = v[2].x > v[3].x ? CEIL (v[2].x) : CEIL (v[3].x);
1613 g->ascent = v[0].y > v[2].y ? CEIL (v[0].y) : CEIL (v[2].y);
1614 g->descent = v[1].y < v[3].y ? - FLOOR (v[1].y) : - FLOOR (v[3].y);
1615 }
1616 else
1617 {
1618 g->lbearing = FLOOR (m->horiBearingX);
1619 g->rbearing = CEIL (m->horiBearingX + m->width);
1620 g->ascent = CEIL (m->horiBearingY);
1621 g->descent = - FLOOR (m->horiBearingY - m->height);
1622 }
1623 g->xadv = ROUND (ft_face->glyph->advance.x);
de023c40
KH
1624 }
1625 else
1626 {
1627 g->lbearing = 0;
42984a74 1628 g->rbearing = g->xadv = flt_font_ft->font->space_width << 6;
de023c40
KH
1629 g->ascent = flt_font_ft->font->ascent << 6;
1630 g->descent = flt_font_ft->font->descent << 6;
1631 }
1632 g->yadv = 0;
1633 g->measured = 1;
1634 }
1635 return 0;
1636}
1637
2a46904e 1638static int
de023c40
KH
1639ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1640{
78a21772
KH
1641#define FEATURE_NONE(IDX) (! spec->features[IDX])
1642
1643#define FEATURE_ANY(IDX) \
1644 (spec->features[IDX] \
1645 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1646
de023c40
KH
1647 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1648 OTF *otf = flt_font_ft->otf;
1649 OTF_Tag *tags;
1650 int i, n, negative;
1651
78a21772 1652 if (FEATURE_ANY (0) && FEATURE_ANY (1))
fa3f6039
KH
1653 /* Return 1 iff any of GSUB or GPOS support the script (and language). */
1654 return (otf
1655 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
1656 NULL, 0) > 0
1657 || OTF_check_features (otf, 1, spec->script, spec->langsys,
1658 NULL, 0) > 0));
1659
de023c40 1660 for (i = 0; i < 2; i++)
78a21772 1661 if (! FEATURE_ANY (i))
fa3f6039 1662 {
78a21772 1663 if (FEATURE_NONE (i))
fa3f6039 1664 {
78a21772
KH
1665 if (otf
1666 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1667 NULL, 0) > 0)
1668 return 0;
1669 continue;
fa3f6039
KH
1670 }
1671 if (spec->features[i][0] == 0xFFFFFFFF)
1672 {
78a21772
KH
1673 if (! otf
1674 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1675 NULL, 0) <= 0)
fa3f6039
KH
1676 continue;
1677 }
78a21772 1678 else if (! otf)
fa3f6039 1679 return 0;
fa3f6039
KH
1680 for (n = 1; spec->features[i][n]; n++);
1681 tags = alloca (sizeof (OTF_Tag) * n);
1682 for (n = 0, negative = 0; spec->features[i][n]; n++)
1683 {
1684 if (spec->features[i][n] == 0xFFFFFFFF)
1685 negative = 1;
1686 else if (negative)
1687 tags[n - 1] = spec->features[i][n] | 0x80000000;
1688 else
1689 tags[n] = spec->features[i][n];
1690 }
c4170e32 1691#ifdef M17N_FLT_USE_NEW_FEATURE
fa3f6039
KH
1692 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1693 tags, n - negative) != 1)
1694 return 0;
c4170e32 1695#else /* not M17N_FLT_USE_NEW_FEATURE */
fa3f6039
KH
1696 if (n - negative > 0
1697 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1698 tags, n - negative) != 1)
1699 return 0;
c4170e32 1700#endif /* not M17N_FLT_USE_NEW_FEATURE */
fa3f6039 1701 }
de023c40 1702 return 1;
78a21772
KH
1703#undef FEATURE_NONE
1704#undef FEATURE_ANY
de023c40
KH
1705}
1706
1707#define DEVICE_DELTA(table, size) \
1708 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1709 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1710 : 0)
1711
1712static void
1713adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1714 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1715{
1716 if (anchor->AnchorFormat == 2)
1717 {
1718 FT_Outline *outline;
1719 int ap = anchor->f.f1.AnchorPoint;
1720
1721 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1722 outline = &ft_face->glyph->outline;
1723 if (ap < outline->n_points)
1724 {
1725 *x = outline->points[ap].x << 6;
1726 *y = outline->points[ap].y << 6;
1727 }
1728 }
1729 else if (anchor->AnchorFormat == 3)
1730 {
d90bfd1c
KH
1731 if (anchor->f.f2.XDeviceTable.offset
1732 && anchor->f.f2.XDeviceTable.DeltaValue)
de023c40 1733 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
d90bfd1c
KH
1734 if (anchor->f.f2.YDeviceTable.offset
1735 && anchor->f.f2.YDeviceTable.DeltaValue)
de023c40
KH
1736 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1737 }
1738}
1739
1740static OTF_GlyphString otf_gstring;
1741
2b33f1ef
KH
1742static void
1743setup_otf_gstring (int size)
1744{
1745 if (otf_gstring.size == 0)
1746 {
c6da7cd2 1747 otf_gstring.glyphs = (OTF_Glyph *) xmalloc (sizeof (OTF_Glyph) * size);
2b33f1ef
KH
1748 otf_gstring.size = size;
1749 }
1750 else if (otf_gstring.size < size)
1751 {
c6da7cd2
JM
1752 otf_gstring.glyphs = xrealloc (otf_gstring.glyphs,
1753 sizeof (OTF_Glyph) * size);
2b33f1ef
KH
1754 otf_gstring.size = size;
1755 }
1756 otf_gstring.used = size;
1757 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
1758}
1759
c4170e32
KH
1760#ifdef M17N_FLT_USE_NEW_FEATURE
1761
1762/* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1763#define PACK_OTF_TAG(TAG) \
1764 ((((TAG) & 0x7F000000) >> 3) \
1765 | (((TAG) & 0x7F0000) >> 2) \
1766 | (((TAG) & 0x7F00) >> 1) \
1767 | ((TAG) & 0x7F))
1768
1769/* Assuming that FONT is an OpenType font, apply OpenType features
1770 specified in SPEC on glyphs between FROM and TO of IN, and record
1771 the lastly applied feature in each glyph of IN. If OUT is not
1772 NULL, append the resulting glyphs to OUT while storing glyph
1773 position adjustment information in ADJUSTMENT. */
1774
1775static int
ef1b0ba7
SM
1776ftfont_drive_otf (MFLTFont *font,
1777 MFLTOtfSpec *spec,
1778 MFLTGlyphString *in,
1779 int from,
1780 int to,
1781 MFLTGlyphString *out,
1782 MFLTGlyphAdjustment *adjustment)
c4170e32
KH
1783{
1784 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1785 FT_Face ft_face = flt_font_ft->ft_face;
1786 OTF *otf = flt_font_ft->otf;
1787 int len = to - from;
1788 int i, j, gidx;
1789 OTF_Glyph *otfg;
1790 char script[5], *langsys = NULL;
1791 char *gsub_features = NULL, *gpos_features = NULL;
1792 OTF_Feature *features;
1793
1794 if (len == 0)
1795 return from;
1796 OTF_tag_name (spec->script, script);
1797 if (spec->langsys)
1798 {
1799 langsys = alloca (5);
1800 OTF_tag_name (spec->langsys, langsys);
1801 }
1802 for (i = 0; i < 2; i++)
1803 {
1804 char *p;
1805
1806 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1807 {
1808 for (j = 0; spec->features[i][j]; j++);
1809 if (i == 0)
1810 p = gsub_features = alloca (6 * j);
1811 else
1812 p = gpos_features = alloca (6 * j);
1813 for (j = 0; spec->features[i][j]; j++)
1814 {
1815 if (spec->features[i][j] == 0xFFFFFFFF)
1816 *p++ = '*', *p++ = ',';
1817 else
1818 {
1819 OTF_tag_name (spec->features[i][j], p);
1820 p[4] = ',';
1821 p += 5;
1822 }
1823 }
1824 *--p = '\0';
1825 }
1826 }
1827
1828 setup_otf_gstring (len);
1829 for (i = 0; i < len; i++)
1830 {
1831 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
1832 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1833 }
1834
1835 OTF_drive_gdef (otf, &otf_gstring);
1836 gidx = out ? out->used : from;
1837
1838 if (gsub_features && out)
1839 {
1840 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1841 gsub_features) < 0)
1842 goto simple_copy;
1843 if (out->allocated < out->used + otf_gstring.used)
1844 return -2;
1845 features = otf->gsub->FeatureList.Feature;
1846 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
1847 {
1848 MFLTGlyph *g;
1849 int min_from, max_to;
1850 int j;
1851 int feature_idx = otfg->positioning_type >> 4;
1852
1853 g = out->glyphs + out->used;
1854 *g = in->glyphs[from + otfg->f.index.from];
1855 if (g->code != otfg->glyph_id)
1856 {
1857 g->c = 0;
1858 g->code = otfg->glyph_id;
1859 g->measured = 0;
1860 }
1861 out->used++;
1862 min_from = g->from;
1863 max_to = g->to;
1864 if (otfg->f.index.from < otfg->f.index.to)
1865 {
1866 /* OTFG substitutes multiple glyphs in IN. */
1867 for (j = from + otfg->f.index.from + 1;
1868 j <= from + otfg->f.index.to; j++)
1869 {
1870 if (min_from > in->glyphs[j].from)
1871 min_from = in->glyphs[j].from;
1872 if (max_to < in->glyphs[j].to)
1873 max_to = in->glyphs[j].to;
1874 }
1875 g->from = min_from;
1876 g->to = max_to;
1877 }
1878 if (feature_idx)
1879 {
1880 unsigned int tag = features[feature_idx - 1].FeatureTag;
1881 tag = PACK_OTF_TAG (tag);
1882 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1883 }
1884 for (i++, otfg++; (i < otf_gstring.used
1885 && otfg->f.index.from == otfg[-1].f.index.from);
1886 i++, otfg++)
1887 {
1888 g = out->glyphs + out->used;
1889 *g = in->glyphs[from + otfg->f.index.to];
1890 if (g->code != otfg->glyph_id)
1891 {
1892 g->c = 0;
1893 g->code = otfg->glyph_id;
1894 g->measured = 0;
1895 }
1896 feature_idx = otfg->positioning_type >> 4;
1897 if (feature_idx)
1898 {
1899 unsigned int tag = features[feature_idx - 1].FeatureTag;
1900 tag = PACK_OTF_TAG (tag);
1901 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1902 }
1903 out->used++;
1904 }
1905 }
1906 }
1907 else if (gsub_features)
1908 {
1909 /* Just for checking which features will be applied. */
1910 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
1911 gsub_features) < 0)
1912 goto simple_copy;
1913 features = otf->gsub->FeatureList.Feature;
1914 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++,
1915 otfg++)
1916 {
1917 int feature_idx = otfg->positioning_type >> 4;
1918
1919 if (feature_idx)
1920 {
1921 unsigned int tag = features[feature_idx - 1].FeatureTag;
1922 tag = PACK_OTF_TAG (tag);
1923 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
1924 {
1925 MFLTGlyph *g = in->glyphs + (from + j);
1926 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1927 }
1928 }
1929 }
1930 }
1931 else if (out)
1932 {
1933 if (out->allocated < out->used + len)
1934 return -2;
1935 for (i = 0; i < len; i++)
1936 out->glyphs[out->used++] = in->glyphs[from + i];
1937 }
1938
1939 if (gpos_features && out)
1940 {
1941 MFLTGlyph *base = NULL, *mark = NULL, *g;
1942 int x_ppem, y_ppem, x_scale, y_scale;
1943
1944 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
1945 gpos_features) < 0)
1946 return to;
1947 features = otf->gpos->FeatureList.Feature;
1948 x_ppem = ft_face->size->metrics.x_ppem;
1949 y_ppem = ft_face->size->metrics.y_ppem;
1950 x_scale = ft_face->size->metrics.x_scale;
1951 y_scale = ft_face->size->metrics.y_scale;
1952
1953 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1954 i < otf_gstring.used; i++, otfg++, g++)
1955 {
1956 MFLTGlyph *prev;
1957 int feature_idx = otfg->positioning_type >> 4;
1958
1959 if (feature_idx)
1960 {
1961 unsigned int tag = features[feature_idx - 1].FeatureTag;
1962 tag = PACK_OTF_TAG (tag);
1963 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
1964 }
1965
1966 if (! otfg->glyph_id)
1967 continue;
1968 switch (otfg->positioning_type & 0xF)
1969 {
1970 case 0:
1971 break;
1972 case 1: /* Single */
1973 case 2: /* Pair */
1974 {
1975 int format = otfg->f.f1.format;
1976
1977 if (format & OTF_XPlacement)
1978 adjustment[i].xoff
1979 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
1980 if (format & OTF_XPlaDevice)
1981 adjustment[i].xoff
1982 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
1983 if (format & OTF_YPlacement)
1984 adjustment[i].yoff
1985 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
1986 if (format & OTF_YPlaDevice)
1987 adjustment[i].yoff
1988 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
1989 if (format & OTF_XAdvance)
1990 adjustment[i].xadv
1991 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
1992 if (format & OTF_XAdvDevice)
1993 adjustment[i].xadv
1994 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
1995 if (format & OTF_YAdvance)
1996 adjustment[i].yadv
1997 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
1998 if (format & OTF_YAdvDevice)
1999 adjustment[i].yadv
2000 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2001 adjustment[i].set = 1;
2002 }
2003 break;
2004 case 3: /* Cursive */
2005 /* Not yet supported. */
2006 break;
2007 case 4: /* Mark-to-Base */
2008 case 5: /* Mark-to-Ligature */
2009 if (! base)
2010 break;
2011 prev = base;
2012 goto label_adjust_anchor;
2013 default: /* i.e. case 6 Mark-to-Mark */
2014 if (! mark)
2015 break;
2016 prev = mark;
2017
2018 label_adjust_anchor:
2019 {
2020 int base_x, base_y, mark_x, mark_y;
2021 int this_from, this_to;
2022
2023 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2024 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2025 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2026 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
2027
2028 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2029 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2030 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2031 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2032 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2033 x_ppem, y_ppem, &mark_x, &mark_y);
2034 adjustment[i].xoff = (base_x - mark_x);
2035 adjustment[i].yoff = - (base_y - mark_y);
2036 adjustment[i].back = (g - prev);
2037 adjustment[i].xadv = 0;
2038 adjustment[i].advance_is_absolute = 1;
2039 adjustment[i].set = 1;
2040 this_from = g->from;
2041 this_to = g->to;
2042 for (j = 0; prev + j < g; j++)
2043 {
2044 if (this_from > prev[j].from)
2045 this_from = prev[j].from;
2046 if (this_to < prev[j].to)
2047 this_to = prev[j].to;
2048 }
2049 for (; prev <= g; prev++)
2050 {
2051 prev->from = this_from;
2052 prev->to = this_to;
2053 }
2054 }
2055 }
2056 if (otfg->GlyphClass == OTF_GlyphClass0)
2057 base = mark = g;
2058 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2059 mark = g;
2060 else
2061 base = g;
2062 }
2063 }
2064 else if (gpos_features)
2065 {
2066 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2067 gpos_features) < 0)
2068 return to;
2069 features = otf->gpos->FeatureList.Feature;
2070 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2071 i++, otfg++)
2072 if (otfg->positioning_type & 0xF)
2073 {
2074 int feature_idx = otfg->positioning_type >> 4;
2075
2076 if (feature_idx)
2077 {
2078 unsigned int tag = features[feature_idx - 1].FeatureTag;
2079 tag = PACK_OTF_TAG (tag);
2080 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2081 {
2082 MFLTGlyph *g = in->glyphs + (from + j);
2083 g->internal = (g->internal & ~0x1FFFFFFF) | tag;
2084 }
2085 }
2086 }
2087 }
2088 return to;
2089
2090 simple_copy:
2091 if (! out)
2092 return to;
2093 if (out->allocated < out->used + len)
2094 return -2;
2095 font->get_metrics (font, in, from, to);
2096 memcpy (out->glyphs + out->used, in->glyphs + from,
2097 sizeof (MFLTGlyph) * len);
2098 out->used += len;
2099 return to;
2100}
2101
9fa82824 2102static int
c4170e32
KH
2103ftfont_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2104 MFLTGlyphString *in, int from, int to)
2105{
2106 return ftfont_drive_otf (font, spec, in, from, to, NULL, NULL);
2107}
2108
2109#else /* not M17N_FLT_USE_NEW_FEATURE */
2b33f1ef 2110
2a46904e 2111static int
d5a3eaaf
AS
2112ftfont_drive_otf (MFLTFont *font, MFLTOtfSpec *spec, MFLTGlyphString *in,
2113 int from, int to,
2114 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
de023c40
KH
2115{
2116 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
2117 FT_Face ft_face = flt_font_ft->ft_face;
2118 OTF *otf = flt_font_ft->otf;
2119 int len = to - from;
2120 int i, j, gidx;
2121 OTF_Glyph *otfg;
2122 char script[5], *langsys = NULL;
2123 char *gsub_features = NULL, *gpos_features = NULL;
2124
2125 if (len == 0)
2126 return from;
2127 OTF_tag_name (spec->script, script);
2128 if (spec->langsys)
2129 {
2130 langsys = alloca (5);
2131 OTF_tag_name (spec->langsys, langsys);
2132 }
2133 for (i = 0; i < 2; i++)
2134 {
2135 char *p;
2136
2137 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2138 {
2139 for (j = 0; spec->features[i][j]; j++);
2140 if (i == 0)
2141 p = gsub_features = alloca (6 * j);
2142 else
2143 p = gpos_features = alloca (6 * j);
2144 for (j = 0; spec->features[i][j]; j++)
2145 {
2146 if (spec->features[i][j] == 0xFFFFFFFF)
2147 *p++ = '*', *p++ = ',';
2148 else
2149 {
2150 OTF_tag_name (spec->features[i][j], p);
2151 p[4] = ',';
2152 p += 5;
2153 }
2154 }
2155 *--p = '\0';
2156 }
2157 }
2158
2b33f1ef 2159 setup_otf_gstring (len);
de023c40
KH
2160 for (i = 0; i < len; i++)
2161 {
2162 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
2163 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
2164 }
2165
2166 OTF_drive_gdef (otf, &otf_gstring);
2167 gidx = out->used;
2168
2169 if (gsub_features)
2170 {
2171 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2172 < 0)
2173 goto simple_copy;
2174 if (out->allocated < out->used + otf_gstring.used)
2175 return -2;
7d2fd545 2176 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; )
de023c40 2177 {
7d2fd545
KH
2178 MFLTGlyph *g;
2179 int min_from, max_to;
de023c40
KH
2180 int j;
2181
7d2fd545 2182 g = out->glyphs + out->used;
de023c40 2183 *g = in->glyphs[from + otfg->f.index.from];
de023c40
KH
2184 if (g->code != otfg->glyph_id)
2185 {
7d2fd545 2186 g->c = 0;
de023c40
KH
2187 g->code = otfg->glyph_id;
2188 g->measured = 0;
2189 }
2190 out->used++;
7d2fd545
KH
2191 min_from = g->from;
2192 max_to = g->to;
2193 if (otfg->f.index.from < otfg->f.index.to)
2194 {
2195 /* OTFG substitutes multiple glyphs in IN. */
2196 for (j = from + otfg->f.index.from + 1;
2197 j <= from + otfg->f.index.to; j++)
2198 {
2199 if (min_from > in->glyphs[j].from)
2200 min_from = in->glyphs[j].from;
2201 if (max_to < in->glyphs[j].to)
2202 max_to = in->glyphs[j].to;
2203 }
2204 g->from = min_from;
2205 g->to = max_to;
2206 }
2207 for (i++, otfg++; (i < otf_gstring.used
2208 && otfg->f.index.from == otfg[-1].f.index.from);
2209 i++, otfg++)
2210 {
2211 g = out->glyphs + out->used;
2212 *g = in->glyphs[from + otfg->f.index.to];
2213 if (g->code != otfg->glyph_id)
2214 {
2215 g->c = 0;
2216 g->code = otfg->glyph_id;
2217 g->measured = 0;
2218 }
2219 out->used++;
2220 }
de023c40
KH
2221 }
2222 }
2223 else
2224 {
2225 if (out->allocated < out->used + len)
2226 return -2;
2227 for (i = 0; i < len; i++)
2228 out->glyphs[out->used++] = in->glyphs[from + i];
2229 }
2230
2231 if (gpos_features)
2232 {
2233 MFLTGlyph *base = NULL, *mark = NULL, *g;
2234 int x_ppem, y_ppem, x_scale, y_scale;
2235
2236 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2237 < 0)
2238 return to;
2239
2240 x_ppem = ft_face->size->metrics.x_ppem;
2241 y_ppem = ft_face->size->metrics.y_ppem;
2242 x_scale = ft_face->size->metrics.x_scale;
2243 y_scale = ft_face->size->metrics.y_scale;
2244
2245 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
2246 i < otf_gstring.used; i++, otfg++, g++)
2247 {
2248 MFLTGlyph *prev;
2249
2250 if (! otfg->glyph_id)
2251 continue;
2252 switch (otfg->positioning_type)
2253 {
2254 case 0:
2255 break;
2256 case 1: /* Single */
2257 case 2: /* Pair */
2258 {
2259 int format = otfg->f.f1.format;
2260
2261 if (format & OTF_XPlacement)
2262 adjustment[i].xoff
2263 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2264 if (format & OTF_XPlaDevice)
2265 adjustment[i].xoff
2266 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2267 if (format & OTF_YPlacement)
2268 adjustment[i].yoff
2269 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2270 if (format & OTF_YPlaDevice)
2271 adjustment[i].yoff
2272 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2273 if (format & OTF_XAdvance)
2274 adjustment[i].xadv
2275 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2276 if (format & OTF_XAdvDevice)
2277 adjustment[i].xadv
2278 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2279 if (format & OTF_YAdvance)
2280 adjustment[i].yadv
2281 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2282 if (format & OTF_YAdvDevice)
2283 adjustment[i].yadv
2284 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2285 adjustment[i].set = 1;
2286 }
2287 break;
2288 case 3: /* Cursive */
2289 /* Not yet supported. */
2290 break;
2291 case 4: /* Mark-to-Base */
2292 case 5: /* Mark-to-Ligature */
2293 if (! base)
2294 break;
2295 prev = base;
2296 goto label_adjust_anchor;
2297 default: /* i.e. case 6 Mark-to-Mark */
2298 if (! mark)
2299 break;
2300 prev = mark;
2301
2302 label_adjust_anchor:
2303 {
2304 int base_x, base_y, mark_x, mark_y;
2305 int this_from, this_to;
2306
2307 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2308 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2309 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
8510724d 2310 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;
de023c40
KH
2311
2312 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2313 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
2314 prev->code, x_ppem, y_ppem, &base_x, &base_y);
2315 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2316 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
2317 x_ppem, y_ppem, &mark_x, &mark_y);
2318 adjustment[i].xoff = (base_x - mark_x);
2319 adjustment[i].yoff = - (base_y - mark_y);
2320 adjustment[i].back = (g - prev);
2321 adjustment[i].xadv = 0;
2322 adjustment[i].advance_is_absolute = 1;
2323 adjustment[i].set = 1;
2324 this_from = g->from;
2325 this_to = g->to;
2326 for (j = 0; prev + j < g; j++)
2327 {
2328 if (this_from > prev[j].from)
2329 this_from = prev[j].from;
2330 if (this_to < prev[j].to)
2331 this_to = prev[j].to;
2332 }
2333 for (; prev <= g; prev++)
2334 {
2335 prev->from = this_from;
2336 prev->to = this_to;
2337 }
2338 }
2339 }
2340 if (otfg->GlyphClass == OTF_GlyphClass0)
2341 base = mark = g;
2342 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2343 mark = g;
2344 else
2345 base = g;
2346 }
2347 }
2348 return to;
2349
2350 simple_copy:
2351 if (out->allocated < out->used + len)
2352 return -2;
2353 font->get_metrics (font, in, from, to);
2354 memcpy (out->glyphs + out->used, in->glyphs + from,
2355 sizeof (MFLTGlyph) * len);
2356 out->used += len;
2357 return to;
2358}
2359
c4170e32
KH
2360#endif /* not M17N_FLT_USE_NEW_FEATURE */
2361
de023c40
KH
2362static MFLTGlyphString gstring;
2363
2364static int m17n_flt_initialized;
2365
990a73f0 2366static Lisp_Object
d5a3eaaf
AS
2367ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
2368 FT_Face ft_face, OTF *otf, FT_Matrix *matrix)
de023c40 2369{
89a95b7c 2370 EMACS_UINT len = LGSTRING_GLYPH_LEN (lgstring);
de023c40
KH
2371 EMACS_UINT i;
2372 struct MFLTFontFT flt_font_ft;
da2cf488 2373 MFLT *flt = NULL;
2b33f1ef 2374 int with_variation_selector = 0;
de023c40
KH
2375
2376 if (! m17n_flt_initialized)
2377 {
2378 M17N_INIT ();
c4170e32
KH
2379#ifdef M17N_FLT_USE_NEW_FEATURE
2380 mflt_enable_new_feature = 1;
2381 mflt_try_otf = ftfont_try_otf;
2382#endif /* M17N_FLT_USE_NEW_FEATURE */
de023c40
KH
2383 m17n_flt_initialized = 1;
2384 }
2385
2386 for (i = 0; i < len; i++)
2b33f1ef
KH
2387 {
2388 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2389 int c;
2390
2391 if (NILP (g))
2392 break;
2393 c = LGLYPH_CHAR (g);
2394 if (CHAR_VARIATION_SELECTOR_P (c))
2395 with_variation_selector++;
2396 }
de023c40 2397 len = i;
2b33f1ef
KH
2398 if (with_variation_selector)
2399 {
2400 setup_otf_gstring (len);
2401 for (i = 0; i < len; i++)
2402 {
2403 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2404
2405 otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
2406 otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
2407 otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
2408 }
2409 OTF_drive_cmap (otf, &otf_gstring);
2410 for (i = 0; i < otf_gstring.used; i++)
2411 {
2412 OTF_Glyph *otfg = otf_gstring.glyphs + i;
2413 Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
2414 Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
2415
2416 LGLYPH_SET_CODE (g0, otfg->glyph_id);
2417 LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
2418 LGSTRING_SET_GLYPH (lgstring, i, g0);
2419 }
2420 if (len > otf_gstring.used)
2421 {
2422 len = otf_gstring.used;
2423 LGSTRING_SET_GLYPH (lgstring, len, Qnil);
2424 }
2425 }
de023c40
KH
2426
2427 if (gstring.allocated == 0)
2428 {
2429 gstring.allocated = len * 2;
2430 gstring.glyph_size = sizeof (MFLTGlyph);
c6da7cd2 2431 gstring.glyphs = xmalloc (sizeof (MFLTGlyph) * gstring.allocated);
de023c40
KH
2432 }
2433 else if (gstring.allocated < len * 2)
2434 {
2435 gstring.allocated = len * 2;
c6da7cd2
JM
2436 gstring.glyphs = xrealloc (gstring.glyphs,
2437 sizeof (MFLTGlyph) * gstring.allocated);
de023c40 2438 }
2b33f1ef 2439 memset (gstring.glyphs, 0, sizeof (MFLTGlyph) * len);
de023c40 2440 for (i = 0; i < len; i++)
2b33f1ef
KH
2441 {
2442 Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
2443
2444 gstring.glyphs[i].c = LGLYPH_CHAR (g);
2445 if (with_variation_selector)
2446 {
2447 gstring.glyphs[i].code = LGLYPH_CODE (g);
2448 gstring.glyphs[i].encoded = 1;
2449 }
2450 }
2451
de023c40
KH
2452 gstring.used = len;
2453 gstring.r2l = 0;
2454
2455 {
2456 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
2457
2458 if (NILP (family))
2459 flt_font_ft.flt_font.family = Mnil;
2460 else
21988a08 2461 flt_font_ft.flt_font.family
51b59d79 2462 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family))));
de023c40
KH
2463 }
2464 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
2465 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
2466 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
2467 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
2468 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
2469 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
2470 flt_font_ft.flt_font.internal = NULL;
2471 flt_font_ft.font = font;
2472 flt_font_ft.ft_face = ft_face;
2473 flt_font_ft.otf = otf;
d0db2ec8 2474 flt_font_ft.matrix = matrix->xx != 0 ? matrix : 0;
7bf1bb21
KH
2475 if (len > 1
2476 && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
da2cf488
KH
2477 /* A little bit ad hoc. Perhaps, shaper must get script and
2478 language information, and select a proper flt for them
2479 here. */
2480 flt = mflt_get (msymbol ("combining"));
de023c40
KH
2481 for (i = 0; i < 3; i++)
2482 {
da2cf488 2483 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
de023c40
KH
2484 if (result != -2)
2485 break;
2486 gstring.allocated += gstring.allocated;
c6da7cd2
JM
2487 gstring.glyphs = xrealloc (gstring.glyphs,
2488 sizeof (MFLTGlyph) * gstring.allocated);
de023c40 2489 }
89a95b7c 2490 if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
de023c40
KH
2491 return Qnil;
2492 for (i = 0; i < gstring.used; i++)
2493 {
2494 MFLTGlyph *g = gstring.glyphs + i;
2495
2496 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
2497 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
2498 }
2499
2500 for (i = 0; i < gstring.used; i++)
2501 {
2502 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2503 MFLTGlyph *g = gstring.glyphs + i;
2504
4cec6061
KH
2505 if (NILP (lglyph))
2506 {
2507 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2508 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2509 }
de023c40
KH
2510 LGLYPH_SET_FROM (lglyph, g->from);
2511 LGLYPH_SET_TO (lglyph, g->to);
2512 LGLYPH_SET_CHAR (lglyph, g->c);
2513 LGLYPH_SET_CODE (lglyph, g->code);
2514 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
2515 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
2516 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
2517 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
2518 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
2519 if (g->adjusted)
2520 {
2521 Lisp_Object vec;
2522
2523 vec = Fmake_vector (make_number (3), Qnil);
2524 ASET (vec, 0, make_number (g->xoff >> 6));
2525 ASET (vec, 1, make_number (g->yoff >> 6));
2526 ASET (vec, 2, make_number (g->xadv >> 6));
2527 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2528 }
2529 }
2530 return make_number (i);
2531}
2532
2533Lisp_Object
d5a3eaaf 2534ftfont_shape (Lisp_Object lgstring)
de023c40
KH
2535{
2536 struct font *font;
2537 struct ftfont_info *ftfont_info;
e302a291 2538 OTF *otf;
de023c40
KH
2539
2540 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2541 ftfont_info = (struct ftfont_info *) font;
e302a291
KH
2542 otf = ftfont_get_otf (ftfont_info);
2543 if (! otf)
4cc1c806 2544 return make_number (0);
d0db2ec8
KH
2545 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
2546 &ftfont_info->matrix);
de023c40
KH
2547}
2548
e3869731
KH
2549#endif /* HAVE_M17N_FLT */
2550
2b33f1ef
KH
2551#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2552
2553static int
d5a3eaaf 2554ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
2b33f1ef
KH
2555{
2556 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
2557 OTF *otf = ftfont_get_otf (ftfont_info);
2558
2559 if (! otf)
2560 return 0;
2561 return OTF_get_variation_glyphs (otf, c, variations);
2562}
2563
2564#endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
de023c40
KH
2565#endif /* HAVE_LIBOTF */
2566
0b966021 2567Lisp_Object
7d7ad10e 2568ftfont_font_format (FcPattern *pattern, Lisp_Object filename)
0b966021 2569{
e907d979 2570 FcChar8 *str;
0b966021 2571
e907d979 2572#ifdef FC_FONTFORMAT
7d7ad10e 2573 if (pattern)
719b3d63 2574 {
7d7ad10e
KH
2575 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
2576 return Qnil;
2577 if (strcmp ((char *) str, "TrueType") == 0)
719b3d63 2578 return intern ("truetype");
7d7ad10e 2579 if (strcmp ((char *) str, "Type 1") == 0)
719b3d63 2580 return intern ("type1");
7d7ad10e 2581 if (strcmp ((char *) str, "PCF") == 0)
719b3d63 2582 return intern ("pcf");
7d7ad10e 2583 if (strcmp ((char *) str, "BDF") == 0)
719b3d63
KH
2584 return intern ("bdf");
2585 }
7d7ad10e
KH
2586#endif /* FC_FONTFORMAT */
2587 if (STRINGP (filename))
2588 {
2589 int len = SBYTES (filename);
2590
2591 if (len >= 4)
2592 {
2593 str = (FcChar8 *) (SDATA (filename) + len - 4);
2594 if (xstrcasecmp ((char *) str, ".ttf") == 0)
2595 return intern ("truetype");
2596 if (xstrcasecmp ((char *) str, ".pfb") == 0)
2597 return intern ("type1");
2598 if (xstrcasecmp ((char *) str, ".pcf") == 0)
2599 return intern ("pcf");
2600 if (xstrcasecmp ((char *) str, ".bdf") == 0)
2601 return intern ("bdf");
2602 }
2603 }
0b966021
KH
2604 return intern ("unknown");
2605}
2606
3106121c 2607static const char *const ftfont_booleans [] = {
637fa988
JD
2608 ":antialias",
2609 ":hinting",
2610 ":verticallayout",
2611 ":autohint",
2612 ":globaladvance",
2613 ":outline",
2614 ":scalable",
2615 ":minspace",
2616 ":embolden",
2617 NULL,
2618};
2619
3106121c 2620static const char *const ftfont_non_booleans [] = {
637fa988
JD
2621 ":family",
2622 ":familylang",
2623 ":style",
2624 ":stylelang",
2625 ":fullname",
2626 ":fullnamelang",
2627 ":slant",
2628 ":weight",
2629 ":size",
2630 ":width",
2631 ":aspect",
2632 ":pixelsize",
2633 ":spacing",
2634 ":foundry",
2635 ":hintstyle",
2636 ":file",
2637 ":index",
2638 ":ftface",
2639 ":rasterizer",
2640 ":scale",
2641 ":dpi",
2642 ":rgba",
2643 ":lcdfilter",
2644 ":charset",
2645 ":lang",
2646 ":fontversion",
2647 ":capability",
2648 NULL,
2649};
2650
2651static void
971de7fb 2652ftfont_filter_properties (Lisp_Object font, Lisp_Object alist)
637fa988 2653{
9fa82824 2654 font_filter_properties (font, alist, ftfont_booleans, ftfont_non_booleans);
637fa988
JD
2655}
2656
2657
c2f5bfd6 2658void
971de7fb 2659syms_of_ftfont (void)
c2f5bfd6 2660{
706b6995
KH
2661 DEFSYM (Qfreetype, "freetype");
2662 DEFSYM (Qmonospace, "monospace");
2663 DEFSYM (Qsans_serif, "sans-serif");
2664 DEFSYM (Qserif, "serif");
2665 DEFSYM (Qmono, "mono");
2666 DEFSYM (Qsans, "sans");
2667 DEFSYM (Qsans__serif, "sans serif");
2668
c2f5bfd6 2669 staticpro (&freetype_font_cache);
c2801c99 2670 freetype_font_cache = Fcons (Qt, Qnil);
c2f5bfd6 2671
706b6995
KH
2672 staticpro (&ftfont_generic_family_list);
2673 ftfont_generic_family_list
2674 = Fcons (Fcons (Qmonospace, Qt),
2675 Fcons (Fcons (Qsans_serif, Qt),
2676 Fcons (Fcons (Qsans, Qt), Qnil)));
c2f5bfd6 2677
21988a08
KH
2678 staticpro (&ft_face_cache);
2679 ft_face_cache = Qnil;
2680
c2f5bfd6
KH
2681 ftfont_driver.type = Qfreetype;
2682 register_font_driver (&ftfont_driver, NULL);
2683}