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