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