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