*** empty log message ***
[bpt/emacs.git] / src / ftfont.c
CommitLineData
c2f5bfd6
KH
1/* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006 Free Software Foundation, Inc.
3 Copyright (C) 2006
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
6
7This file is part of GNU Emacs.
8
9GNU Emacs is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2, or (at your option)
12any later version.
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
20along with GNU Emacs; see the file COPYING. If not, write to
21the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22Boston, MA 02110-1301, USA. */
23
24#include <config.h>
25#include <stdio.h>
26
c2f5bfd6
KH
27#include <fontconfig/fontconfig.h>
28#include <fontconfig/fcfreetype.h>
29
30#include "lisp.h"
31#include "dispextern.h"
32#include "frame.h"
33#include "blockinput.h"
34#include "character.h"
35#include "charset.h"
36#include "coding.h"
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
c2801c99 47/* Flag to tell if FcInit is areadly 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
c2801c99
KH
56/* Fontconfig's charset used for finding fonts of registry
57 "iso8859-1". */
c2f5bfd6
KH
58static FcCharSet *cs_iso8859_1;
59
60/* The actual structure for FreeType font that can be casted to struct
61 font. */
62
63struct ftfont_info
64{
65 struct font font;
66 FT_Size ft_size;
de023c40
KH
67#ifdef HAVE_LIBOTF
68 int maybe_otf; /* Flag to tell if this may be OTF or not. */
69 OTF *otf;
70#endif /* HAVE_LIBOTF */
c2f5bfd6
KH
71};
72
706b6995
KH
73static int ftfont_build_basic_charsets P_ ((void));
74static Lisp_Object ftfont_pattern_entity P_ ((FcPattern *,
75 Lisp_Object, Lisp_Object));
76static Lisp_Object ftfont_list_generic_family P_ ((Lisp_Object, Lisp_Object,
77 Lisp_Object));
0b966021 78Lisp_Object ftfont_font_format P_ ((FcPattern *));
706b6995
KH
79
80#define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
81
c2f5bfd6
KH
82static int
83ftfont_build_basic_charsets ()
84{
85 FcChar32 c;
86
87 cs_iso8859_1 = FcCharSetCreate ();
88 if (! cs_iso8859_1)
89 return -1;
90 for (c = ' '; c < 127; c++)
91 if (! FcCharSetAddChar (cs_iso8859_1, c))
92 return -1;
260a71fb
KH
93#if 0
94 /* This part is currently disabled. Should be fixed later. */
c2f5bfd6
KH
95 for (c = 192; c < 256; c++)
96 if (! FcCharSetAddChar (cs_iso8859_1, c))
97 return -1;
260a71fb 98#endif
c2f5bfd6
KH
99 return 0;
100}
101
706b6995
KH
102static Lisp_Object
103ftfont_pattern_entity (p, frame, registry)
c2801c99 104 FcPattern *p;
706b6995 105 Lisp_Object frame, registry;
c2801c99
KH
106{
107 Lisp_Object entity;
0b966021 108 FcChar8 *file, *fontformat;
c2801c99
KH
109 FcCharSet *charset;
110 char *str;
111 int numeric;
112 double dbl;
113
114 if (FcPatternGetString (p, FC_FILE, 0, &file) != FcResultMatch)
115 return Qnil;
f0365b6f 116 if (FcPatternGetCharSet (p, FC_CHARSET, 0, &charset) != FcResultMatch)
c2801c99 117 charset = NULL;
e907d979 118#ifdef FC_FONTFORMAT
0b966021 119 if (FcPatternGetString (p, FC_FONTFORMAT, 0, &fontformat) != FcResultMatch)
e907d979 120#endif /* FC_FONTFORMAT */
0b966021 121 fontformat = NULL;
c2801c99
KH
122
123 entity = Fmake_vector (make_number (FONT_ENTITY_MAX), null_string);
124
125 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
126 ASET (entity, FONT_REGISTRY_INDEX, registry);
127 ASET (entity, FONT_FRAME_INDEX, frame);
128 ASET (entity, FONT_OBJLIST_INDEX, Qnil);
129
130 if (FcPatternGetString (p, FC_FOUNDRY, 0, (FcChar8 **) &str) == FcResultMatch)
131 ASET (entity, FONT_FOUNDRY_INDEX, intern_downcase (str, strlen (str)));
132 if (FcPatternGetString (p, FC_FAMILY, 0, (FcChar8 **) &str) == FcResultMatch)
133 ASET (entity, FONT_FAMILY_INDEX, intern_downcase (str, strlen (str)));
134 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
f63d54dc
KH
135 {
136 if (numeric == FC_WEIGHT_REGULAR)
137 numeric = 100;
138 ASET (entity, FONT_WEIGHT_INDEX, make_number (numeric));
139 }
c2801c99
KH
140 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
141 ASET (entity, FONT_SLANT_INDEX, make_number (numeric + 100));
142 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
143 ASET (entity, FONT_WIDTH_INDEX, make_number (numeric));
144 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
145 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
146 else
147 ASET (entity, FONT_SIZE_INDEX, make_number (0));
148
149 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) != FcResultMatch)
f0432f81 150 numeric = -1;
c2801c99
KH
151 file = FcStrCopy (file);
152 if (! file)
153 return Qnil;
154
155 p = FcPatternCreate ();
156 if (! p)
157 return Qnil;
158
159 if (FcPatternAddString (p, FC_FILE, file) == FcFalse
0b966021
KH
160 || (charset
161 && FcPatternAddCharSet (p, FC_CHARSET, charset) == FcFalse)
e907d979 162#ifdef FC_FONTFORMAT
0b966021
KH
163 || (fontformat
164 && FcPatternAddString (p, FC_FONTFORMAT, fontformat) == FcFalse)
e907d979 165#endif /* FC_FONTFORMAT */
f0432f81
KH
166 || (numeric >= 0
167 && FcPatternAddInteger (p, FC_SPACING, numeric) == FcFalse))
c2801c99
KH
168 {
169 FcPatternDestroy (p);
170 return Qnil;
171 }
172 ASET (entity, FONT_EXTRA_INDEX, make_save_value (p, 0));
173 return entity;
174}
175
706b6995
KH
176static Lisp_Object ftfont_generic_family_list;
177
178static Lisp_Object
179ftfont_list_generic_family (spec, frame, registry)
180 Lisp_Object spec, frame, registry;
181{
182 Lisp_Object family = AREF (spec, FONT_FAMILY_INDEX);
183 Lisp_Object slot, list, val;
184
185 if (EQ (family, Qmono))
186 family = Qmonospace;
187 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
188 family = Qsans_serif;
189 slot = assq_no_quit (family, ftfont_generic_family_list);
190 if (! CONSP (slot))
191 return null_vector;
192 list = XCDR (slot);
193 if (EQ (list, Qt))
194 {
195 /* Not yet listed. */
196 FcObjectSet *objset = NULL;
197 FcPattern *pattern = NULL, *pat = NULL;
198 FcFontSet *fontset = NULL;
199 FcChar8 *fam;
200 int i, j;
201
202 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
203 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING,
e907d979
KH
204 FC_CHARSET, FC_FILE,
205#ifdef FC_FONTFORMAT
206 FC_FONTFORMAT,
207#endif /* FC_FONTFORMAT */
208 NULL);
706b6995
KH
209 if (! objset)
210 goto err;
211 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString,
212 SYMBOL_FcChar8 (family), (char *) 0);
213 if (! pattern)
214 goto err;
215 pat = FcPatternCreate ();
216 if (! pat)
217 goto err;
218 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
219 for (i = 0, val = Qnil;
220 FcPatternGetString (pattern, FC_FAMILY, i, &fam) == FcResultMatch;
221 i++)
222 {
223 if (strcmp ((char *) fam, (char *) SYMBOL_FcChar8 (family)) == 0)
224 continue;
225 if (! FcPatternAddString (pat, FC_FAMILY, fam))
226 goto err;
227 fontset = FcFontList (NULL, pat, objset);
228 if (! fontset)
229 goto err;
230 /* Here we build the list in reverse order so that the last
231 loop in this function build a list in the correct
232 order. */
233 for (j = 0; j < fontset->nfont; j++)
234 {
235 Lisp_Object entity;
236
237 entity = ftfont_pattern_entity (fontset->fonts[j],
238 frame, registry);
239 if (! NILP (entity))
240 val = Fcons (entity, val);
241 }
242 FcFontSetDestroy (fontset);
243 fontset = NULL;
244 FcPatternDel (pat, FC_FAMILY);
245 }
246 list = val;
247 XSETCDR (slot, list);
248 err:
249 if (pat) FcPatternDestroy (pat);
250 if (pattern) FcPatternDestroy (pattern);
251 if (fontset) FcFontSetDestroy (fontset);
252 if (objset) FcObjectSetDestroy (objset);
253 if (EQ (list, Qt))
254 return Qnil;
255 }
256 ASET (spec, FONT_FAMILY_INDEX, Qnil);
257 for (val = Qnil; CONSP (list); list = XCDR (list))
258 if (font_match_p (spec, XCAR (list)))
259 val = Fcons (XCAR (list), val);
260 ASET (spec, FONT_FAMILY_INDEX, family);
261 return Fvconcat (1, &val);
262}
263
c2801c99 264
c2f5bfd6 265static Lisp_Object ftfont_get_cache P_ ((Lisp_Object));
c2f5bfd6 266static Lisp_Object ftfont_list P_ ((Lisp_Object, Lisp_Object));
8daf5667 267static Lisp_Object ftfont_match P_ ((Lisp_Object, Lisp_Object));
c2f5bfd6
KH
268static Lisp_Object ftfont_list_family P_ ((Lisp_Object));
269static void ftfont_free_entity P_ ((Lisp_Object));
270static struct font *ftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
271static void ftfont_close P_ ((FRAME_PTR, struct font *));
272static int ftfont_has_char P_ ((Lisp_Object, int));
273static unsigned ftfont_encode_char P_ ((struct font *, int));
274static int ftfont_text_extents P_ ((struct font *, unsigned *, int,
275 struct font_metrics *));
276static int ftfont_get_bitmap P_ ((struct font *, unsigned,
277 struct font_bitmap *, int));
278static int ftfont_anchor_point P_ ((struct font *, unsigned, int,
279 int *, int *));
de023c40 280static Lisp_Object ftfont_shape P_ ((Lisp_Object));
c2f5bfd6
KH
281
282struct font_driver ftfont_driver =
283 {
09a56ce4 284 0, /* Qfreetype */
c2f5bfd6 285 ftfont_get_cache,
c2f5bfd6 286 ftfont_list,
8daf5667 287 ftfont_match,
c2f5bfd6
KH
288 ftfont_list_family,
289 ftfont_free_entity,
290 ftfont_open,
291 ftfont_close,
292 /* We can't draw a text without device dependent functions. */
293 NULL,
294 NULL,
295 ftfont_has_char,
296 ftfont_encode_char,
297 ftfont_text_extents,
298 /* We can't draw a text without device dependent functions. */
299 NULL,
300 ftfont_get_bitmap,
301 NULL,
302 NULL,
303 NULL,
304 ftfont_anchor_point,
c2f5bfd6
KH
305 NULL,
306 NULL,
de023c40
KH
307 NULL,
308 NULL,
309#ifdef HAVE_M17N_FLT
310 ftfont_shape
311#else /* not HAVE_M17N_FLT */
c2f5bfd6 312 NULL
de023c40 313#endif /* not HAVE_M17N_FLT */
c2f5bfd6
KH
314 };
315
c2f5bfd6
KH
316extern Lisp_Object QCname;
317
318static Lisp_Object
319ftfont_get_cache (frame)
320 Lisp_Object frame;
321{
c2f5bfd6
KH
322 return freetype_font_cache;
323}
324
c2f5bfd6
KH
325static Lisp_Object
326ftfont_list (frame, spec)
327 Lisp_Object frame, spec;
328{
8daf5667 329 Lisp_Object val, tmp, extra;
c2f5bfd6
KH
330 int i;
331 FcPattern *pattern = NULL;
332 FcCharSet *charset = NULL;
333 FcLangSet *langset = NULL;
334 FcFontSet *fontset = NULL;
335 FcObjectSet *objset = NULL;
8daf5667 336 Lisp_Object script;
c2801c99 337 Lisp_Object registry = Qunicode_bmp;
63565713 338 int weight = 0;
bc9a2afe
KH
339 double dpi = -1;
340 int spacing = -1;
341 int scalable = -1;
a85f724a 342 char otf_script[15]; /* For "otlayout\:XXXX" */
c2f5bfd6
KH
343
344 val = null_vector;
345
346 if (! fc_initialized)
347 {
348 FcInit ();
349 fc_initialized = 1;
350 }
351
63565713
KH
352 if (! NILP (AREF (spec, FONT_ADSTYLE_INDEX))
353 && ! EQ (AREF (spec, FONT_ADSTYLE_INDEX), null_string))
c2f5bfd6 354 return val;
63565713
KH
355 if (! NILP (AREF (spec, FONT_SLANT_INDEX))
356 && XINT (AREF (spec, FONT_SLANT_INDEX)) < 100)
357 /* Fontconfig doesn't support reverse-italic/obligue. */
358 return val;
359
c2f5bfd6
KH
360 if (! NILP (AREF (spec, FONT_REGISTRY_INDEX)))
361 {
362 registry = AREF (spec, FONT_REGISTRY_INDEX);
363 if (EQ (registry, Qiso8859_1))
364 {
365 if (! cs_iso8859_1
366 && ftfont_build_basic_charsets () < 0)
706b6995 367 return Qnil;
c2f5bfd6 368 charset = cs_iso8859_1;
c2f5bfd6 369 }
e1cae3d3
KH
370 else if (! EQ (registry, Qiso10646_1)
371 && ! EQ (registry, Qunicode_bmp)
372 && ! EQ (registry, Qunicode_sip))
706b6995 373 return val;
c2f5bfd6
KH
374 }
375
a85f724a 376 otf_script[0] = '\0';
8daf5667
KH
377 script = Qnil;
378 for (extra = AREF (spec, FONT_EXTRA_INDEX);
379 CONSP (extra); extra = XCDR (extra))
c2f5bfd6 380 {
8daf5667
KH
381 Lisp_Object key, val;
382
383 tmp = XCAR (extra);
384 key = XCAR (tmp), val = XCDR (tmp);
385 if (EQ (key, QCotf))
a85f724a 386 {
de023c40
KH
387 tmp = XCAR (val);
388 if (NILP (tmp))
389 strcpy (otf_script, "otlayout:DFLT");
390 else
391 {
392 val = assq_no_quit (tmp, Votf_script_alist);
393 if (CONSP (val) && SYMBOLP (XCDR (val)))
394 {
395 sprintf (otf_script, "otlayout:%s",
396 (char *) SDATA (SYMBOL_NAME (tmp)));
397 script = XCDR (val);
398 }
399 }
a85f724a 400 }
8daf5667 401 else if (EQ (key, QClanguage))
c2f5bfd6
KH
402 {
403 langset = FcLangSetCreate ();
404 if (! langset)
405 goto err;
8daf5667 406 if (SYMBOLP (val))
c2f5bfd6 407 {
8daf5667 408 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
c2f5bfd6
KH
409 goto err;
410 }
411 else
8daf5667
KH
412 for (; CONSP (val); val = XCDR (val))
413 if (SYMBOLP (XCAR (val))
414 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
415 goto err;
c2f5bfd6 416 }
8daf5667
KH
417 else if (EQ (key, QCscript))
418 script = val;
419 else if (EQ (key, QCdpi))
420 dpi = XINT (val);
421 else if (EQ (key, QCspacing))
422 spacing = XINT (val);
423 else if (EQ (key, QCscalable))
424 scalable = ! NILP (val);
425 }
c2f5bfd6 426
8daf5667
KH
427 if (! NILP (script) && ! charset)
428 {
429 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
430
431 if (CONSP (chars))
432 {
433 charset = FcCharSetCreate ();
434 if (! charset)
435 goto err;
436 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
437 if (CHARACTERP (XCAR (chars))
438 && ! FcCharSetAddChar (charset, XUINT (XCAR (chars))))
439 goto err;
c2f5bfd6
KH
440 }
441 }
442
8daf5667 443 pattern = FcPatternCreate ();
706b6995
KH
444 if (! pattern)
445 goto err;
706b6995
KH
446 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
447 if (SYMBOLP (tmp) && ! NILP (tmp)
448 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
449 goto err;
450 tmp = AREF (spec, FONT_FAMILY_INDEX);
451 if (SYMBOLP (tmp) && ! NILP (tmp)
452 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
453 goto err;
63565713
KH
454 /* Emacs conventionally doesn't distinguish normal, regular, and
455 medium weight, but fontconfig does. So, we can't restrict font
456 listing by weight. We check it after getting a list. */
706b6995 457 tmp = AREF (spec, FONT_WEIGHT_INDEX);
63565713
KH
458 if (INTEGERP (tmp))
459 weight = XINT (tmp);
706b6995
KH
460 tmp = AREF (spec, FONT_SLANT_INDEX);
461 if (INTEGERP (tmp)
706b6995
KH
462 && ! FcPatternAddInteger (pattern, FC_SLANT, XINT (tmp) - 100))
463 goto err;
464 tmp = AREF (spec, FONT_WIDTH_INDEX);
465 if (INTEGERP (tmp)
466 && ! FcPatternAddInteger (pattern, FC_WIDTH, XINT (tmp)))
467 goto err;
c2f5bfd6
KH
468
469 if (charset
470 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
471 goto err;
472 if (langset
473 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
474 goto err;
bc9a2afe
KH
475 if (dpi >= 0
476 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
477 goto err;
478 if (spacing >= 0
479 && ! FcPatternAddInteger (pattern, FC_SPACING, spacing))
480 goto err;
481 if (scalable >= 0
25a5d05b 482 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
bc9a2afe 483 goto err;
c2f5bfd6 484
706b6995
KH
485 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
486 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING,
e907d979
KH
487 FC_CHARSET, FC_FILE,
488#ifdef FC_FONTFORMAT
489 FC_FONTFORMAT,
490#endif /* FC_FONTFORMAT */
491 NULL);
706b6995
KH
492 if (! objset)
493 goto err;
bc5f6c42
KH
494 if (otf_script[0])
495 {
496#ifndef FC_CAPABILITY
497 goto finish;
498#else /* not FC_CAPABILITY */
499 if (! FcObjectSetAdd (objset, FC_CAPABILITY))
500 goto err;
bc5f6c42 501#endif /* not FC_CAPABILITY */
5ed08958 502 }
f63d54dc 503
706b6995
KH
504 fontset = FcFontList (NULL, pattern, objset);
505 if (! fontset)
506 goto err;
c2f5bfd6 507
706b6995
KH
508 if (fontset->nfont > 0)
509 {
f63d54dc
KH
510 double pixel_size;
511
512 if (NILP (AREF (spec, FONT_SIZE_INDEX)))
513 pixel_size = 0;
514 else
515 pixel_size = XINT (AREF (spec, FONT_SIZE_INDEX));
516
706b6995 517 for (i = 0, val = Qnil; i < fontset->nfont; i++)
c2f5bfd6 518 {
f63d54dc
KH
519 Lisp_Object entity;
520
521 if (pixel_size > 0)
522 {
523 double this;
524
525 if (FcPatternGetDouble (fontset->fonts[i], FC_PIXEL_SIZE, 0,
526 &this) == FcResultMatch
63565713
KH
527 && ((this < pixel_size - FONT_PIXEL_SIZE_QUANTUM)
528 || (this > pixel_size + FONT_PIXEL_SIZE_QUANTUM)))
529 continue;
530 }
531 if (weight > 0)
532 {
533 int this;
534
535 if (FcPatternGetInteger (fontset->fonts[i], FC_WEIGHT, 0,
536 &this) != FcResultMatch
537 || (this != weight
538 && (weight != 100
539 || this < FC_WEIGHT_REGULAR
540 || this > FC_WEIGHT_MEDIUM)))
f63d54dc
KH
541 continue;
542 }
bc5f6c42 543#ifdef FC_CAPABILITY
a85f724a
KH
544 if (otf_script[0])
545 {
546 FcChar8 *this;
547
548 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0,
549 &this) != FcResultMatch
550 || ! strstr ((char *) this, otf_script))
551 continue;
552 }
bc5f6c42 553#endif /* FC_CAPABILITY */
f63d54dc 554 entity = ftfont_pattern_entity (fontset->fonts[i], frame, registry);
c2801c99
KH
555 if (! NILP (entity))
556 val = Fcons (entity, val);
c2f5bfd6 557 }
c2801c99 558 val = Fvconcat (1, &val);
c2f5bfd6 559 }
706b6995
KH
560 else if (! NILP (AREF (spec, FONT_FAMILY_INDEX)))
561 val = ftfont_list_generic_family (spec, frame, registry);
c2f5bfd6
KH
562 goto finish;
563
564 err:
565 /* We come here because of unexpected error in fontconfig API call
706b6995 566 (usually insufficient memory). */
c2f5bfd6
KH
567 val = Qnil;
568
569 finish:
570 if (charset && charset != cs_iso8859_1) FcCharSetDestroy (charset);
571 if (objset) FcObjectSetDestroy (objset);
572 if (fontset) FcFontSetDestroy (fontset);
573 if (langset) FcLangSetDestroy (langset);
574 if (pattern) FcPatternDestroy (pattern);
575
576 return val;
577}
578
8daf5667
KH
579static Lisp_Object
580ftfont_match (frame, spec)
581 Lisp_Object frame, spec;
582{
583 Lisp_Object extra, val, entity;
584 FcPattern *pattern = NULL, *match = NULL;
585 FcResult result;
586
587 if (! fc_initialized)
588 {
589 FcInit ();
590 fc_initialized = 1;
591 }
592
593 extra = AREF (spec, FONT_EXTRA_INDEX);
594 val = assq_no_quit (QCname, extra);
595 if (! CONSP (val) || ! STRINGP (XCDR (val)))
596 return Qnil;
597
598 entity = Qnil;
599 pattern = FcNameParse (SDATA (XCDR (val)));
600 if (pattern)
601 {
602 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
603 {
604 FcDefaultSubstitute (pattern);
605 match = FcFontMatch (NULL, pattern, &result);
8daf5667
KH
606 if (match)
607 {
608 entity = ftfont_pattern_entity (match, frame, Qunicode_bmp);
609 FcPatternDestroy (match);
610 }
611 }
612 FcPatternDestroy (pattern);
613 }
614
615 return entity;
616}
617
c2f5bfd6
KH
618static Lisp_Object
619ftfont_list_family (frame)
620 Lisp_Object frame;
621{
622 Lisp_Object list;
623 FcPattern *pattern = NULL;
624 FcFontSet *fontset = NULL;
625 FcObjectSet *objset = NULL;
626 int i;
627
628 if (! fc_initialized)
629 {
630 FcInit ();
631 fc_initialized = 1;
632 }
633
634 pattern = FcPatternCreate ();
635 if (! pattern)
636 goto finish;
706b6995 637 objset = FcObjectSetBuild (FC_FAMILY, NULL);
c2f5bfd6
KH
638 if (! objset)
639 goto finish;
640 fontset = FcFontList (NULL, pattern, objset);
641 if (! fontset)
642 goto finish;
643
644 list = Qnil;
645 for (i = 0; i < fontset->nfont; i++)
646 {
647 FcPattern *pat = fontset->fonts[i];
648 FcChar8 *str;
649
650 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
651 list = Fcons (intern_downcase ((char *) str, strlen ((char *) str)),
652 list);
653 }
654
655 finish:
656 if (objset) FcObjectSetDestroy (objset);
657 if (fontset) FcFontSetDestroy (fontset);
658 if (pattern) FcPatternDestroy (pattern);
659
660 return list;
661}
662
663
664static void
665ftfont_free_entity (entity)
666 Lisp_Object entity;
667{
668 Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX);
669 FcPattern *pattern = XSAVE_VALUE (val)->pointer;
670
671 FcPatternDestroy (pattern);
672}
673
674static struct font *
675ftfont_open (f, entity, pixel_size)
676 FRAME_PTR f;
677 Lisp_Object entity;
678 int pixel_size;
679{
680 struct ftfont_info *ftfont_info;
681 struct font *font;
682 FT_Face ft_face;
683 FT_Size ft_size;
684 FT_UInt size;
685 Lisp_Object val;
686 FcPattern *pattern;
687 FcChar8 *file;
688 int spacing;
c9c0c429
KH
689 char *name;
690 int len;
c2f5bfd6
KH
691
692 val = AREF (entity, FONT_EXTRA_INDEX);
693 if (XTYPE (val) != Lisp_Misc
694 || XMISCTYPE (val) != Lisp_Misc_Save_Value)
695 return NULL;
696 pattern = XSAVE_VALUE (val)->pointer;
697 if (XSAVE_VALUE (val)->integer == 0)
698 {
699 /* We have not yet created FT_Face for this font. */
700 if (! ft_library
701 && FT_Init_FreeType (&ft_library) != 0)
702 return NULL;
703 if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch)
704 return NULL;
705 if (FT_New_Face (ft_library, (char *) file, 0, &ft_face) != 0)
706 return NULL;
707 FcPatternAddFTFace (pattern, FC_FT_FACE, ft_face);
708 ft_size = ft_face->size;
709 }
710 else
711 {
712 if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
713 != FcResultMatch)
714 return NULL;
715 if (FT_New_Size (ft_face, &ft_size) != 0)
716 return NULL;
717 if (FT_Activate_Size (ft_size) != 0)
718 {
719 FT_Done_Size (ft_size);
720 return NULL;
721 }
722 }
723
724 size = XINT (AREF (entity, FONT_SIZE_INDEX));
725 if (size == 0)
726 size = pixel_size;
727 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
728 {
729 if (XSAVE_VALUE (val)->integer == 0)
730 FT_Done_Face (ft_face);
731 return NULL;
732 }
733
734 ftfont_info = malloc (sizeof (struct ftfont_info));
735 if (! ftfont_info)
736 return NULL;
737 ftfont_info->ft_size = ft_size;
de023c40
KH
738 ftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
739 ftfont_info->otf = NULL;
c2f5bfd6
KH
740
741 font = (struct font *) ftfont_info;
0b966021 742 font->format = ftfont_font_format (pattern);
c2f5bfd6
KH
743 font->entity = entity;
744 font->pixel_size = size;
745 font->driver = &ftfont_driver;
c9c0c429
KH
746 len = 96;
747 name = malloc (len);
748 while (name && font_unparse_fcname (entity, pixel_size, name, len) < 0)
749 {
750 char *new = realloc (name, len += 32);
751
752 if (! new)
753 free (name);
754 name = new;
755 }
756 font->font.full_name = font->font.name = name;
c2f5bfd6
KH
757 font->file_name = (char *) file;
758 font->font.size = ft_face->size->metrics.max_advance >> 6;
c9c0c429
KH
759 if (font->font.size <= 0)
760 font->font.size = size;
a85f724a 761 font->font.charset = font->encoding_charset = font->repertory_charset = -1;
c2f5bfd6
KH
762 font->ascent = ft_face->size->metrics.ascender >> 6;
763 font->descent = - ft_face->size->metrics.descender >> 6;
c9c0c429
KH
764 font->font.height = font->ascent + font->descent;
765 if (FcPatternGetInteger (pattern, FC_SPACING, 0, &spacing) != FcResultMatch)
766 spacing = FC_PROPORTIONAL;
767 if (spacing != FC_PROPORTIONAL)
c2f5bfd6
KH
768 font->font.average_width = font->font.space_width = font->font.size;
769 else
770 {
771 int i;
772
773 for (i = 32; i < 127; i++)
774 {
775 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) != 0)
776 break;
777 if (i == 32)
778 font->font.space_width = ft_face->glyph->metrics.horiAdvance >> 6;
779 font->font.average_width += ft_face->glyph->metrics.horiAdvance >> 6;
780 }
781 if (i == 127)
782 {
783 /* The font contains all ASCII printable characters. */
784 font->font.average_width /= 95;
785 }
786 else
787 {
788 if (i == 32)
789 font->font.space_width = font->font.size;
790 font->font.average_width = font->font.size;
791 }
792 }
793
c9c0c429
KH
794 /* Unfortunately FreeType doesn't provide a way to get minimum char
795 width. So, we use space_width instead. */
796 font->min_width = font->font.space_width;
797
c2f5bfd6
KH
798 font->font.baseline_offset = 0;
799 font->font.relative_compose = 0;
800 font->font.default_ascent = 0;
801 font->font.vertical_centering = 0;
802
803 (XSAVE_VALUE (val)->integer)++;
804
805 return font;
806}
807
808static void
809ftfont_close (f, font)
810 FRAME_PTR f;
811 struct font *font;
812{
813 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
814 Lisp_Object entity = font->entity;
815 Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX);
816
817 (XSAVE_VALUE (val)->integer)--;
818 if (XSAVE_VALUE (val)->integer == 0)
de023c40
KH
819 {
820 FT_Done_Face (ftfont_info->ft_size->face);
821#ifdef HAVE_LIBOTF
822 if (ftfont_info->otf)
823 OTF_close (ftfont_info->otf);
824#endif
825 }
c2f5bfd6
KH
826 else
827 FT_Done_Size (ftfont_info->ft_size);
828
829 free (font);
830}
831
832static int
833ftfont_has_char (entity, c)
834 Lisp_Object entity;
835 int c;
836{
837 Lisp_Object val;
838 FcPattern *pattern;
839 FcCharSet *charset;
840
841 val = AREF (entity, FONT_EXTRA_INDEX);
842 pattern = XSAVE_VALUE (val)->pointer;
c2801c99
KH
843 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
844 return -1;
c2f5bfd6
KH
845 return (FcCharSetHasChar (charset, (FcChar32) c) == FcTrue);
846}
847
848static unsigned
849ftfont_encode_char (font, c)
850 struct font *font;
851 int c;
852{
853 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
854 FT_Face ft_face = ftfont_info->ft_size->face;
855 FT_ULong charcode = c;
856 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
857
858 return (code > 0 ? code : 0xFFFFFFFF);
859}
860
861static int
862ftfont_text_extents (font, code, nglyphs, metrics)
863 struct font *font;
864 unsigned *code;
865 int nglyphs;
866 struct font_metrics *metrics;
867{
868 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
869 FT_Face ft_face = ftfont_info->ft_size->face;
870 int width = 0;
871 int i;
872
873 if (ftfont_info->ft_size != ft_face->size)
874 FT_Activate_Size (ftfont_info->ft_size);
875 if (metrics)
876 bzero (metrics, sizeof (struct font_metrics));
877 for (i = 0; i < nglyphs; i++)
878 {
879 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
880 {
881 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
882
883 if (metrics)
884 {
885 if (metrics->lbearing > width + (m->horiBearingX >> 6))
886 metrics->lbearing = width + (m->horiBearingX >> 6);
887 if (metrics->rbearing
888 < width + ((m->horiBearingX + m->width) >> 6))
889 metrics->rbearing
890 = width + ((m->horiBearingX + m->width) >> 6);
891 if (metrics->ascent < (m->horiBearingY >> 6))
892 metrics->ascent = m->horiBearingY >> 6;
893 if (metrics->descent > ((m->horiBearingY + m->height) >> 6))
894 metrics->descent = (m->horiBearingY + m->height) >> 6;
895 }
896 width += m->horiAdvance >> 6;
897 }
898 else
899 {
900 width += font->font.space_width;
901 }
902 }
903 if (metrics)
904 metrics->width = width;
905
906 return width;
907}
908
909static int
910ftfont_get_bitmap (font, code, bitmap, bits_per_pixel)
911 struct font *font;
912 unsigned code;
913 struct font_bitmap *bitmap;
914 int bits_per_pixel;
915{
916 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
917 FT_Face ft_face = ftfont_info->ft_size->face;
918 FT_Int32 load_flags = FT_LOAD_RENDER;
919
920 if (ftfont_info->ft_size != ft_face->size)
921 FT_Activate_Size (ftfont_info->ft_size);
922 if (bits_per_pixel == 1)
923 {
924#ifdef FT_LOAD_TARGET_MONO
925 load_flags |= FT_LOAD_TARGET_MONO;
926#else
927 load_flags |= FT_LOAD_MONOCHROME;
928#endif
929 }
930 else if (bits_per_pixel != 8)
931 /* We don't support such a rendering. */
932 return -1;
933
934 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
935 return -1;
b51e5112
KH
936 bitmap->bits_per_pixel
937 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
938 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
939 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
940 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
941 : -1);
942 if (bitmap->bits_per_pixel < 0)
943 /* We don't suport that kind of pixel mode. */
944 return -1;
c2f5bfd6
KH
945 bitmap->rows = ft_face->glyph->bitmap.rows;
946 bitmap->width = ft_face->glyph->bitmap.width;
947 bitmap->pitch = ft_face->glyph->bitmap.pitch;
948 bitmap->buffer = ft_face->glyph->bitmap.buffer;
949 bitmap->left = ft_face->glyph->bitmap_left;
950 bitmap->top = ft_face->glyph->bitmap_top;
951 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
952 bitmap->extra = NULL;
953
954 return 0;
955}
956
957static int
958ftfont_anchor_point (font, code, index, x, y)
959 struct font *font;
960 unsigned code;
961 int index;
962 int *x, *y;
963{
964 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
965 FT_Face ft_face = ftfont_info->ft_size->face;
966
967 if (ftfont_info->ft_size != ft_face->size)
968 FT_Activate_Size (ftfont_info->ft_size);
969 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
970 return -1;
971 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
972 return -1;
973 if (index >= ft_face->glyph->outline.n_points)
974 return -1;
975 *x = ft_face->glyph->outline.points[index].x;
976 *y = ft_face->glyph->outline.points[index].y;
977 return 0;
978}
979
de023c40
KH
980#ifdef HAVE_LIBOTF
981#ifdef HAVE_M17N_FLT
982
983struct MFLTFontFT
984{
985 MFLTFont flt_font;
986 struct font *font;
987 FT_Face ft_face;
988 OTF *otf;
989};
990
991static int
992ftfont_get_glyph_id (font, gstring, from, to)
993 MFLTFont *font;
994 MFLTGlyphString *gstring;
995 int from, to;
996{
997 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
998 FT_Face ft_face = flt_font_ft->ft_face;
999 MFLTGlyph *g;
1000
1001 for (g = gstring->glyphs + from; from < to; g++, from++)
1002 if (! g->encoded)
1003 {
1004 FT_UInt code = FT_Get_Char_Index (ft_face, g->code);
1005
1006 g->code = code > 0 ? code : FONT_INVALID_CODE;
1007 g->encoded = 1;
1008 }
1009 return 0;
1010}
1011
1012static int
1013ftfont_get_metrics (font, gstring, from, to)
1014 MFLTFont *font;
1015 MFLTGlyphString *gstring;
1016 int from, to;
1017{
1018 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1019 FT_Face ft_face = flt_font_ft->ft_face;
1020 MFLTGlyph *g;
1021
1022 for (g = gstring->glyphs + from; from < to; g++, from++)
1023 if (! g->measured)
1024 {
1025 if (g->code != FONT_INVALID_CODE)
1026 {
1027 FT_Glyph_Metrics *m;
1028
1029 if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0)
1030 abort ();
1031 m = &ft_face->glyph->metrics;
1032
1033 g->lbearing = m->horiBearingX;
1034 g->rbearing = m->horiBearingX + m->width;
1035 g->ascent = m->horiBearingY;
1036 g->descent = m->height - m->horiBearingY;
1037 g->xadv = m->horiAdvance;
1038 }
1039 else
1040 {
1041 g->lbearing = 0;
1042 g->rbearing = g->xadv = flt_font_ft->font->font.space_width << 6;
1043 g->ascent = flt_font_ft->font->ascent << 6;
1044 g->descent = flt_font_ft->font->descent << 6;
1045 }
1046 g->yadv = 0;
1047 g->measured = 1;
1048 }
1049 return 0;
1050}
1051
1052static int
1053ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
1054{
1055 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1056 OTF *otf = flt_font_ft->otf;
1057 OTF_Tag *tags;
1058 int i, n, negative;
1059
1060 for (i = 0; i < 2; i++)
1061 {
1062 if (! spec->features[i])
1063 continue;
1064 for (n = 0; spec->features[i][n]; n++);
1065 tags = alloca (sizeof (OTF_Tag) * n);
1066 for (n = 0, negative = 0; spec->features[i][n]; n++)
1067 {
1068 if (spec->features[i][n] == 0xFFFFFFFF)
1069 negative = 1;
1070 else if (negative)
1071 tags[n - 1] = spec->features[i][n] | 0x80000000;
1072 else
1073 tags[n] = spec->features[i][n];
1074 }
1075 if (n - negative > 0
1076 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
1077 tags, n - negative) != 1)
1078 return 0;
1079 }
1080 return 1;
1081}
1082
1083#define DEVICE_DELTA(table, size) \
1084 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1085 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1086 : 0)
1087
1088static void
1089adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
1090 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
1091{
1092 if (anchor->AnchorFormat == 2)
1093 {
1094 FT_Outline *outline;
1095 int ap = anchor->f.f1.AnchorPoint;
1096
1097 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1098 outline = &ft_face->glyph->outline;
1099 if (ap < outline->n_points)
1100 {
1101 *x = outline->points[ap].x << 6;
1102 *y = outline->points[ap].y << 6;
1103 }
1104 }
1105 else if (anchor->AnchorFormat == 3)
1106 {
1107 if (anchor->f.f2.XDeviceTable.offset)
1108 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
1109 if (anchor->f.f2.YDeviceTable.offset)
1110 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
1111 }
1112}
1113
1114static OTF_GlyphString otf_gstring;
1115
1116static int
1117ftfont_drive_otf (font, spec, in, from, to, out, adjustment)
1118 MFLTFont *font;
1119 MFLTOtfSpec *spec;
1120 MFLTGlyphString *in;
1121 int from, to;
1122 MFLTGlyphString *out;
1123 MFLTGlyphAdjustment *adjustment;
1124{
1125 struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font;
1126 FT_Face ft_face = flt_font_ft->ft_face;
1127 OTF *otf = flt_font_ft->otf;
1128 int len = to - from;
1129 int i, j, gidx;
1130 OTF_Glyph *otfg;
1131 char script[5], *langsys = NULL;
1132 char *gsub_features = NULL, *gpos_features = NULL;
1133
1134 if (len == 0)
1135 return from;
1136 OTF_tag_name (spec->script, script);
1137 if (spec->langsys)
1138 {
1139 langsys = alloca (5);
1140 OTF_tag_name (spec->langsys, langsys);
1141 }
1142 for (i = 0; i < 2; i++)
1143 {
1144 char *p;
1145
1146 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
1147 {
1148 for (j = 0; spec->features[i][j]; j++);
1149 if (i == 0)
1150 p = gsub_features = alloca (6 * j);
1151 else
1152 p = gpos_features = alloca (6 * j);
1153 for (j = 0; spec->features[i][j]; j++)
1154 {
1155 if (spec->features[i][j] == 0xFFFFFFFF)
1156 *p++ = '*', *p++ = ',';
1157 else
1158 {
1159 OTF_tag_name (spec->features[i][j], p);
1160 p[4] = ',';
1161 p += 5;
1162 }
1163 }
1164 *--p = '\0';
1165 }
1166 }
1167
1168 if (otf_gstring.size == 0)
1169 {
1170 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1171 otf_gstring.size = len;
1172 }
1173 else if (otf_gstring.size < len)
1174 {
1175 otf_gstring.glyphs = (OTF_Glyph *) realloc (otf_gstring.glyphs,
1176 sizeof (OTF_Glyph) * len);
1177 otf_gstring.size = len;
1178 }
1179 otf_gstring.used = len;
1180 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1181 for (i = 0; i < len; i++)
1182 {
1183 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
1184 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
1185 }
1186
1187 OTF_drive_gdef (otf, &otf_gstring);
1188 gidx = out->used;
1189
1190 if (gsub_features)
1191 {
1192 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
1193 < 0)
1194 goto simple_copy;
1195 if (out->allocated < out->used + otf_gstring.used)
1196 return -2;
1197 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1198 {
1199 MFLTGlyph *g = out->glyphs + out->used;
1200 int j;
1201
1202 *g = in->glyphs[from + otfg->f.index.from];
1203 g->c = 0;
1204 for (j = from + otfg->f.index.from; j <= from + otfg->f.index.to; j++)
1205 if (in->glyphs[j].code == otfg->glyph_id)
1206 {
1207 g->c = in->glyphs[j].c;
1208 break;
1209 }
1210 if (g->code != otfg->glyph_id)
1211 {
1212 g->code = otfg->glyph_id;
1213 g->measured = 0;
1214 }
1215 out->used++;
1216 }
1217 }
1218 else
1219 {
1220 if (out->allocated < out->used + len)
1221 return -2;
1222 for (i = 0; i < len; i++)
1223 out->glyphs[out->used++] = in->glyphs[from + i];
1224 }
1225
1226 if (gpos_features)
1227 {
1228 MFLTGlyph *base = NULL, *mark = NULL, *g;
1229 int x_ppem, y_ppem, x_scale, y_scale;
1230
1231 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
1232 < 0)
1233 return to;
1234
1235 x_ppem = ft_face->size->metrics.x_ppem;
1236 y_ppem = ft_face->size->metrics.y_ppem;
1237 x_scale = ft_face->size->metrics.x_scale;
1238 y_scale = ft_face->size->metrics.y_scale;
1239
1240 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
1241 i < otf_gstring.used; i++, otfg++, g++)
1242 {
1243 MFLTGlyph *prev;
1244
1245 if (! otfg->glyph_id)
1246 continue;
1247 switch (otfg->positioning_type)
1248 {
1249 case 0:
1250 break;
1251 case 1: /* Single */
1252 case 2: /* Pair */
1253 {
1254 int format = otfg->f.f1.format;
1255
1256 if (format & OTF_XPlacement)
1257 adjustment[i].xoff
1258 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
1259 if (format & OTF_XPlaDevice)
1260 adjustment[i].xoff
1261 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
1262 if (format & OTF_YPlacement)
1263 adjustment[i].yoff
1264 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
1265 if (format & OTF_YPlaDevice)
1266 adjustment[i].yoff
1267 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
1268 if (format & OTF_XAdvance)
1269 adjustment[i].xadv
1270 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
1271 if (format & OTF_XAdvDevice)
1272 adjustment[i].xadv
1273 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
1274 if (format & OTF_YAdvance)
1275 adjustment[i].yadv
1276 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
1277 if (format & OTF_YAdvDevice)
1278 adjustment[i].yadv
1279 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
1280 adjustment[i].set = 1;
1281 }
1282 break;
1283 case 3: /* Cursive */
1284 /* Not yet supported. */
1285 break;
1286 case 4: /* Mark-to-Base */
1287 case 5: /* Mark-to-Ligature */
1288 if (! base)
1289 break;
1290 prev = base;
1291 goto label_adjust_anchor;
1292 default: /* i.e. case 6 Mark-to-Mark */
1293 if (! mark)
1294 break;
1295 prev = mark;
1296
1297 label_adjust_anchor:
1298 {
1299 int base_x, base_y, mark_x, mark_y;
1300 int this_from, this_to;
1301
1302 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
1303 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
1304 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
1305 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
1306
1307 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1308 adjust_anchor (ft_face, otfg->f.f4.base_anchor,
1309 prev->code, x_ppem, y_ppem, &base_x, &base_y);
1310 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1311 adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code,
1312 x_ppem, y_ppem, &mark_x, &mark_y);
1313 adjustment[i].xoff = (base_x - mark_x);
1314 adjustment[i].yoff = - (base_y - mark_y);
1315 adjustment[i].back = (g - prev);
1316 adjustment[i].xadv = 0;
1317 adjustment[i].advance_is_absolute = 1;
1318 adjustment[i].set = 1;
1319 this_from = g->from;
1320 this_to = g->to;
1321 for (j = 0; prev + j < g; j++)
1322 {
1323 if (this_from > prev[j].from)
1324 this_from = prev[j].from;
1325 if (this_to < prev[j].to)
1326 this_to = prev[j].to;
1327 }
1328 for (; prev <= g; prev++)
1329 {
1330 prev->from = this_from;
1331 prev->to = this_to;
1332 }
1333 }
1334 }
1335 if (otfg->GlyphClass == OTF_GlyphClass0)
1336 base = mark = g;
1337 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1338 mark = g;
1339 else
1340 base = g;
1341 }
1342 }
1343 return to;
1344
1345 simple_copy:
1346 if (out->allocated < out->used + len)
1347 return -2;
1348 font->get_metrics (font, in, from, to);
1349 memcpy (out->glyphs + out->used, in->glyphs + from,
1350 sizeof (MFLTGlyph) * len);
1351 out->used += len;
1352 return to;
1353}
1354
1355static MFLTGlyphString gstring;
1356
1357static int m17n_flt_initialized;
1358
1359extern Lisp_Object QCfamily;
1360
1361Lisp_Object
1362ftfont_shape_by_flt (lgstring, font, ft_face, otf)
1363 Lisp_Object lgstring;
1364 struct font *font;
1365 FT_Face ft_face;
1366 OTF *otf;
1367{
1368 EMACS_UINT len = LGSTRING_LENGTH (lgstring);
1369 EMACS_UINT i;
1370 struct MFLTFontFT flt_font_ft;
1371
1372 if (! m17n_flt_initialized)
1373 {
1374 M17N_INIT ();
1375 m17n_flt_initialized = 1;
1376 }
1377
1378 for (i = 0; i < len; i++)
1379 if (NILP (LGSTRING_GLYPH (lgstring, i)))
1380 break;
1381 len = i;
1382
1383 if (gstring.allocated == 0)
1384 {
1385 gstring.allocated = len * 2;
1386 gstring.glyph_size = sizeof (MFLTGlyph);
1387 gstring.glyphs = malloc (sizeof (MFLTGlyph) * gstring.allocated);
1388 }
1389 else if (gstring.allocated < len * 2)
1390 {
1391 gstring.allocated = len * 2;
1392 gstring.glyphs = realloc (gstring.glyphs,
1393 sizeof (MFLTGlyph) * gstring.allocated);
1394 }
1395 for (i = 0; i < len; i++)
1396 gstring.glyphs[i].c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
1397 gstring.used = len;
1398 gstring.r2l = 0;
1399
1400 {
1401 Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily);
1402
1403 if (NILP (family))
1404 flt_font_ft.flt_font.family = Mnil;
1405 else
1406 flt_font_ft.flt_font.family = msymbol (SDATA (SYMBOL_NAME (family)));
1407 }
1408 flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
1409 flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
1410 flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id;
1411 flt_font_ft.flt_font.get_metrics = ftfont_get_metrics;
1412 flt_font_ft.flt_font.check_otf = ftfont_check_otf;
1413 flt_font_ft.flt_font.drive_otf = ftfont_drive_otf;
1414 flt_font_ft.flt_font.internal = NULL;
1415 flt_font_ft.font = font;
1416 flt_font_ft.ft_face = ft_face;
1417 flt_font_ft.otf = otf;
1418 for (i = 0; i < 3; i++)
1419 {
1420 int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, NULL);
1421 if (result != -2)
1422 break;
1423 gstring.allocated += gstring.allocated;
1424 gstring.glyphs = realloc (gstring.glyphs,
1425 sizeof (MFLTGlyph) * gstring.allocated);
1426 }
1427 if (gstring.used > LGSTRING_LENGTH (lgstring))
1428 return Qnil;
1429 for (i = 0; i < gstring.used; i++)
1430 {
1431 MFLTGlyph *g = gstring.glyphs + i;
1432
1433 g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from));
1434 g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to));
1435 }
1436
1437 for (i = 0; i < gstring.used; i++)
1438 {
1439 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
1440 MFLTGlyph *g = gstring.glyphs + i;
1441
1442 LGLYPH_SET_FROM (lglyph, g->from);
1443 LGLYPH_SET_TO (lglyph, g->to);
1444 LGLYPH_SET_CHAR (lglyph, g->c);
1445 LGLYPH_SET_CODE (lglyph, g->code);
1446 LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6);
1447 LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6);
1448 LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6);
1449 LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6);
1450 LGLYPH_SET_DESCENT (lglyph, g->descent >> 6);
1451 if (g->adjusted)
1452 {
1453 Lisp_Object vec;
1454
1455 vec = Fmake_vector (make_number (3), Qnil);
1456 ASET (vec, 0, make_number (g->xoff >> 6));
1457 ASET (vec, 1, make_number (g->yoff >> 6));
1458 ASET (vec, 2, make_number (g->xadv >> 6));
1459 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
1460 }
1461 }
1462 return make_number (i);
1463}
1464
1465Lisp_Object
1466ftfont_shape (lgstring)
1467 Lisp_Object lgstring;
1468{
1469 struct font *font;
1470 struct ftfont_info *ftfont_info;
1471
1472 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
1473 ftfont_info = (struct ftfont_info *) font;
1474 if (! ftfont_info->maybe_otf)
1475 return 0;
1476 if (! ftfont_info->otf)
1477 {
1478 OTF *otf = OTF_open_ft_face (ftfont_info->ft_size->face);
1479
1480 if (! otf || OTF_get_table (otf, "head") < 0)
1481 {
1482 if (otf)
1483 OTF_close (otf);
1484 ftfont_info->maybe_otf = 0;
1485 return 0;
1486 }
1487
1488 ftfont_info->otf = otf;
1489 }
1490
1491 return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face,
1492 ftfont_info->otf);
1493}
1494
1495#endif /* HAVE_M17N_FLT */
1496#endif /* HAVE_LIBOTF */
1497
0b966021
KH
1498Lisp_Object
1499ftfont_font_format (FcPattern *pattern)
1500{
e907d979 1501 FcChar8 *str;
0b966021 1502
e907d979
KH
1503#ifdef FC_FONTFORMAT
1504 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
0b966021 1505 return Qnil;
e907d979 1506 if (strcmp ((char *) str, "TrueType") == 0)
0b966021 1507 return intern ("truetype");
48875afe 1508 if (strcmp ((char *) str, "Type 1") == 0)
0b966021 1509 return intern ("type1");
e907d979 1510 if (strcmp ((char *) str, "PCF") == 0)
0b966021 1511 return intern ("pcf");
e907d979 1512 if (strcmp ((char *) str, "BDF") == 0)
0b966021 1513 return intern ("bdf");
e907d979 1514#else /* not FC_FONTFORMAT */
09a56ce4 1515 if (FcPatternGetString (pattern, FC_FILE, 0, &str) != FcResultMatch)
e907d979
KH
1516 return Qnil;
1517 if (strcasestr ((char *) str, ".ttf") == 0)
1518 return intern ("truetype");
1519 if (strcasestr ((char *) str, "pfb") == 0)
1520 return intern ("type1");
1521 if (strcasestr ((char *) str, "pcf") == 0)
1522 return intern ("pcf");
1523 if (strcasestr ((char *) str, "bdf") == 0)
1524 return intern ("bdf");
1525#endif /* not FC_FONTFORMAT */
0b966021
KH
1526 return intern ("unknown");
1527}
1528
c2f5bfd6
KH
1529\f
1530void
1531syms_of_ftfont ()
1532{
706b6995
KH
1533 DEFSYM (Qfreetype, "freetype");
1534 DEFSYM (Qmonospace, "monospace");
1535 DEFSYM (Qsans_serif, "sans-serif");
1536 DEFSYM (Qserif, "serif");
1537 DEFSYM (Qmono, "mono");
1538 DEFSYM (Qsans, "sans");
1539 DEFSYM (Qsans__serif, "sans serif");
1540
c2f5bfd6 1541 staticpro (&freetype_font_cache);
c2801c99 1542 freetype_font_cache = Fcons (Qt, Qnil);
c2f5bfd6 1543
706b6995
KH
1544 staticpro (&ftfont_generic_family_list);
1545 ftfont_generic_family_list
1546 = Fcons (Fcons (Qmonospace, Qt),
1547 Fcons (Fcons (Qsans_serif, Qt),
1548 Fcons (Fcons (Qsans, Qt), Qnil)));
c2f5bfd6
KH
1549
1550 ftfont_driver.type = Qfreetype;
1551 register_font_driver (&ftfont_driver, NULL);
1552}
885b7d09
MB
1553
1554/* arch-tag: 7cfa432c-33a6-4988-83d2-a82ed8604aca
1555 (do not change this comment) */