(fontset_find_font) [USE_FONT_BACKEND]: Try multiple
[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
27#include <ft2build.h>
28#include FT_FREETYPE_H
29#include FT_SIZES_H
30#include <fontconfig/fontconfig.h>
31#include <fontconfig/fcfreetype.h>
32
33#include "lisp.h"
34#include "dispextern.h"
35#include "frame.h"
36#include "blockinput.h"
37#include "character.h"
38#include "charset.h"
39#include "coding.h"
40#include "fontset.h"
41#include "font.h"
42
c2801c99 43/* Symbolic type of this font-driver. */
c2f5bfd6
KH
44Lisp_Object Qfreetype;
45
706b6995
KH
46/* Fontconfig's generic families and their aliases. */
47static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
48
c2801c99 49/* Flag to tell if FcInit is areadly called or not. */
c2f5bfd6 50static int fc_initialized;
c2801c99
KH
51
52/* Handle to a FreeType library instance. */
c2f5bfd6
KH
53static FT_Library ft_library;
54
c2801c99 55/* Cache for FreeType fonts. */
c2f5bfd6
KH
56static Lisp_Object freetype_font_cache;
57
c2801c99
KH
58/* Fontconfig's charset used for finding fonts of registry
59 "iso8859-1". */
c2f5bfd6
KH
60static FcCharSet *cs_iso8859_1;
61
62/* The actual structure for FreeType font that can be casted to struct
63 font. */
64
65struct ftfont_info
66{
67 struct font font;
68 FT_Size ft_size;
69};
70
706b6995
KH
71static int ftfont_build_basic_charsets P_ ((void));
72static Lisp_Object ftfont_pattern_entity P_ ((FcPattern *,
73 Lisp_Object, Lisp_Object));
74static Lisp_Object ftfont_list_generic_family P_ ((Lisp_Object, Lisp_Object,
75 Lisp_Object));
0b966021 76Lisp_Object ftfont_font_format P_ ((FcPattern *));
706b6995
KH
77
78#define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
79
c2f5bfd6
KH
80static int
81ftfont_build_basic_charsets ()
82{
83 FcChar32 c;
84
85 cs_iso8859_1 = FcCharSetCreate ();
86 if (! cs_iso8859_1)
87 return -1;
88 for (c = ' '; c < 127; c++)
89 if (! FcCharSetAddChar (cs_iso8859_1, c))
90 return -1;
260a71fb
KH
91#if 0
92 /* This part is currently disabled. Should be fixed later. */
c2f5bfd6
KH
93 for (c = 192; c < 256; c++)
94 if (! FcCharSetAddChar (cs_iso8859_1, c))
95 return -1;
260a71fb 96#endif
c2f5bfd6
KH
97 return 0;
98}
99
706b6995
KH
100static Lisp_Object
101ftfont_pattern_entity (p, frame, registry)
c2801c99 102 FcPattern *p;
706b6995 103 Lisp_Object frame, registry;
c2801c99
KH
104{
105 Lisp_Object entity;
0b966021 106 FcChar8 *file, *fontformat;
c2801c99
KH
107 FcCharSet *charset;
108 char *str;
109 int numeric;
110 double dbl;
111
112 if (FcPatternGetString (p, FC_FILE, 0, &file) != FcResultMatch)
113 return Qnil;
f0365b6f 114 if (FcPatternGetCharSet (p, FC_CHARSET, 0, &charset) != FcResultMatch)
c2801c99 115 charset = NULL;
e907d979 116#ifdef FC_FONTFORMAT
0b966021 117 if (FcPatternGetString (p, FC_FONTFORMAT, 0, &fontformat) != FcResultMatch)
e907d979 118#endif /* FC_FONTFORMAT */
0b966021 119 fontformat = NULL;
c2801c99
KH
120
121 entity = Fmake_vector (make_number (FONT_ENTITY_MAX), null_string);
122
123 ASET (entity, FONT_TYPE_INDEX, Qfreetype);
124 ASET (entity, FONT_REGISTRY_INDEX, registry);
125 ASET (entity, FONT_FRAME_INDEX, frame);
126 ASET (entity, FONT_OBJLIST_INDEX, Qnil);
127
128 if (FcPatternGetString (p, FC_FOUNDRY, 0, (FcChar8 **) &str) == FcResultMatch)
129 ASET (entity, FONT_FOUNDRY_INDEX, intern_downcase (str, strlen (str)));
130 if (FcPatternGetString (p, FC_FAMILY, 0, (FcChar8 **) &str) == FcResultMatch)
131 ASET (entity, FONT_FAMILY_INDEX, intern_downcase (str, strlen (str)));
132 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
f63d54dc
KH
133 {
134 if (numeric == FC_WEIGHT_REGULAR)
135 numeric = 100;
136 ASET (entity, FONT_WEIGHT_INDEX, make_number (numeric));
137 }
c2801c99
KH
138 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
139 ASET (entity, FONT_SLANT_INDEX, make_number (numeric + 100));
140 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
141 ASET (entity, FONT_WIDTH_INDEX, make_number (numeric));
142 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
143 ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
144 else
145 ASET (entity, FONT_SIZE_INDEX, make_number (0));
146
147 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) != FcResultMatch)
f0432f81 148 numeric = -1;
c2801c99
KH
149 file = FcStrCopy (file);
150 if (! file)
151 return Qnil;
152
153 p = FcPatternCreate ();
154 if (! p)
155 return Qnil;
156
157 if (FcPatternAddString (p, FC_FILE, file) == FcFalse
0b966021
KH
158 || (charset
159 && FcPatternAddCharSet (p, FC_CHARSET, charset) == FcFalse)
e907d979 160#ifdef FC_FONTFORMAT
0b966021
KH
161 || (fontformat
162 && FcPatternAddString (p, FC_FONTFORMAT, fontformat) == FcFalse)
e907d979 163#endif /* FC_FONTFORMAT */
f0432f81
KH
164 || (numeric >= 0
165 && FcPatternAddInteger (p, FC_SPACING, numeric) == FcFalse))
c2801c99
KH
166 {
167 FcPatternDestroy (p);
168 return Qnil;
169 }
170 ASET (entity, FONT_EXTRA_INDEX, make_save_value (p, 0));
171 return entity;
172}
173
706b6995
KH
174static Lisp_Object ftfont_generic_family_list;
175
176static Lisp_Object
177ftfont_list_generic_family (spec, frame, registry)
178 Lisp_Object spec, frame, registry;
179{
180 Lisp_Object family = AREF (spec, FONT_FAMILY_INDEX);
181 Lisp_Object slot, list, val;
182
183 if (EQ (family, Qmono))
184 family = Qmonospace;
185 else if (EQ (family, Qsans) || EQ (family, Qsans__serif))
186 family = Qsans_serif;
187 slot = assq_no_quit (family, ftfont_generic_family_list);
188 if (! CONSP (slot))
189 return null_vector;
190 list = XCDR (slot);
191 if (EQ (list, Qt))
192 {
193 /* Not yet listed. */
194 FcObjectSet *objset = NULL;
195 FcPattern *pattern = NULL, *pat = NULL;
196 FcFontSet *fontset = NULL;
197 FcChar8 *fam;
198 int i, j;
199
200 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
201 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING,
e907d979
KH
202 FC_CHARSET, FC_FILE,
203#ifdef FC_FONTFORMAT
204 FC_FONTFORMAT,
205#endif /* FC_FONTFORMAT */
206 NULL);
706b6995
KH
207 if (! objset)
208 goto err;
209 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString,
210 SYMBOL_FcChar8 (family), (char *) 0);
211 if (! pattern)
212 goto err;
213 pat = FcPatternCreate ();
214 if (! pat)
215 goto err;
216 FcConfigSubstitute (NULL, pattern, FcMatchPattern);
217 for (i = 0, val = Qnil;
218 FcPatternGetString (pattern, FC_FAMILY, i, &fam) == FcResultMatch;
219 i++)
220 {
221 if (strcmp ((char *) fam, (char *) SYMBOL_FcChar8 (family)) == 0)
222 continue;
223 if (! FcPatternAddString (pat, FC_FAMILY, fam))
224 goto err;
225 fontset = FcFontList (NULL, pat, objset);
226 if (! fontset)
227 goto err;
228 /* Here we build the list in reverse order so that the last
229 loop in this function build a list in the correct
230 order. */
231 for (j = 0; j < fontset->nfont; j++)
232 {
233 Lisp_Object entity;
234
235 entity = ftfont_pattern_entity (fontset->fonts[j],
236 frame, registry);
237 if (! NILP (entity))
238 val = Fcons (entity, val);
239 }
240 FcFontSetDestroy (fontset);
241 fontset = NULL;
242 FcPatternDel (pat, FC_FAMILY);
243 }
244 list = val;
245 XSETCDR (slot, list);
246 err:
247 if (pat) FcPatternDestroy (pat);
248 if (pattern) FcPatternDestroy (pattern);
249 if (fontset) FcFontSetDestroy (fontset);
250 if (objset) FcObjectSetDestroy (objset);
251 if (EQ (list, Qt))
252 return Qnil;
253 }
254 ASET (spec, FONT_FAMILY_INDEX, Qnil);
255 for (val = Qnil; CONSP (list); list = XCDR (list))
256 if (font_match_p (spec, XCAR (list)))
257 val = Fcons (XCAR (list), val);
258 ASET (spec, FONT_FAMILY_INDEX, family);
259 return Fvconcat (1, &val);
260}
261
c2801c99 262
c2f5bfd6 263static Lisp_Object ftfont_get_cache P_ ((Lisp_Object));
c2f5bfd6 264static Lisp_Object ftfont_list P_ ((Lisp_Object, Lisp_Object));
8daf5667 265static Lisp_Object ftfont_match P_ ((Lisp_Object, Lisp_Object));
c2f5bfd6
KH
266static Lisp_Object ftfont_list_family P_ ((Lisp_Object));
267static void ftfont_free_entity P_ ((Lisp_Object));
268static struct font *ftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
269static void ftfont_close P_ ((FRAME_PTR, struct font *));
270static int ftfont_has_char P_ ((Lisp_Object, int));
271static unsigned ftfont_encode_char P_ ((struct font *, int));
272static int ftfont_text_extents P_ ((struct font *, unsigned *, int,
273 struct font_metrics *));
274static int ftfont_get_bitmap P_ ((struct font *, unsigned,
275 struct font_bitmap *, int));
276static int ftfont_anchor_point P_ ((struct font *, unsigned, int,
277 int *, int *));
278
279struct font_driver ftfont_driver =
280 {
09a56ce4 281 0, /* Qfreetype */
c2f5bfd6 282 ftfont_get_cache,
c2f5bfd6 283 ftfont_list,
8daf5667 284 ftfont_match,
c2f5bfd6
KH
285 ftfont_list_family,
286 ftfont_free_entity,
287 ftfont_open,
288 ftfont_close,
289 /* We can't draw a text without device dependent functions. */
290 NULL,
291 NULL,
292 ftfont_has_char,
293 ftfont_encode_char,
294 ftfont_text_extents,
295 /* We can't draw a text without device dependent functions. */
296 NULL,
297 ftfont_get_bitmap,
298 NULL,
299 NULL,
300 NULL,
301 ftfont_anchor_point,
302#ifdef HAVE_LIBOTF
303 font_otf_capability,
abb610f2 304 font_drive_otf,
c2f5bfd6
KH
305#else
306 NULL,
307 NULL,
308 NULL
309#endif /* HAVE_LIBOTF */
310 };
311
c2f5bfd6
KH
312extern Lisp_Object QCname;
313
314static Lisp_Object
315ftfont_get_cache (frame)
316 Lisp_Object frame;
317{
c2f5bfd6
KH
318 return freetype_font_cache;
319}
320
c2f5bfd6
KH
321static Lisp_Object
322ftfont_list (frame, spec)
323 Lisp_Object frame, spec;
324{
8daf5667 325 Lisp_Object val, tmp, extra;
c2f5bfd6
KH
326 int i;
327 FcPattern *pattern = NULL;
328 FcCharSet *charset = NULL;
329 FcLangSet *langset = NULL;
330 FcFontSet *fontset = NULL;
331 FcObjectSet *objset = NULL;
8daf5667 332 Lisp_Object script;
c2801c99 333 Lisp_Object registry = Qunicode_bmp;
63565713 334 int weight = 0;
bc9a2afe
KH
335 double dpi = -1;
336 int spacing = -1;
337 int scalable = -1;
a85f724a 338 char otf_script[15]; /* For "otlayout\:XXXX" */
c2f5bfd6
KH
339
340 val = null_vector;
341
342 if (! fc_initialized)
343 {
344 FcInit ();
345 fc_initialized = 1;
346 }
347
63565713
KH
348 if (! NILP (AREF (spec, FONT_ADSTYLE_INDEX))
349 && ! EQ (AREF (spec, FONT_ADSTYLE_INDEX), null_string))
c2f5bfd6 350 return val;
63565713
KH
351 if (! NILP (AREF (spec, FONT_SLANT_INDEX))
352 && XINT (AREF (spec, FONT_SLANT_INDEX)) < 100)
353 /* Fontconfig doesn't support reverse-italic/obligue. */
354 return val;
355
c2f5bfd6
KH
356 if (! NILP (AREF (spec, FONT_REGISTRY_INDEX)))
357 {
358 registry = AREF (spec, FONT_REGISTRY_INDEX);
359 if (EQ (registry, Qiso8859_1))
360 {
361 if (! cs_iso8859_1
362 && ftfont_build_basic_charsets () < 0)
706b6995 363 return Qnil;
c2f5bfd6 364 charset = cs_iso8859_1;
c2f5bfd6 365 }
e1cae3d3
KH
366 else if (! EQ (registry, Qiso10646_1)
367 && ! EQ (registry, Qunicode_bmp)
368 && ! EQ (registry, Qunicode_sip))
706b6995 369 return val;
c2f5bfd6
KH
370 }
371
a85f724a 372 otf_script[0] = '\0';
8daf5667
KH
373 script = Qnil;
374 for (extra = AREF (spec, FONT_EXTRA_INDEX);
375 CONSP (extra); extra = XCDR (extra))
c2f5bfd6 376 {
8daf5667
KH
377 Lisp_Object key, val;
378
379 tmp = XCAR (extra);
380 key = XCAR (tmp), val = XCDR (tmp);
381 if (EQ (key, QCotf))
a85f724a 382 {
8daf5667 383 script = assq_no_quit (val, Votf_script_alist);
a85f724a
KH
384 if (CONSP (script) && SYMBOLP (XCDR (script)))
385 script = XCDR (script);
8daf5667 386 tmp = SYMBOL_NAME (val);
a85f724a
KH
387 sprintf (otf_script, "otlayout:%s", (char *) SDATA (tmp));
388 }
8daf5667 389 else if (EQ (key, QClanguage))
c2f5bfd6
KH
390 {
391 langset = FcLangSetCreate ();
392 if (! langset)
393 goto err;
8daf5667 394 if (SYMBOLP (val))
c2f5bfd6 395 {
8daf5667 396 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
c2f5bfd6
KH
397 goto err;
398 }
399 else
8daf5667
KH
400 for (; CONSP (val); val = XCDR (val))
401 if (SYMBOLP (XCAR (val))
402 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
403 goto err;
c2f5bfd6 404 }
8daf5667
KH
405 else if (EQ (key, QCscript))
406 script = val;
407 else if (EQ (key, QCdpi))
408 dpi = XINT (val);
409 else if (EQ (key, QCspacing))
410 spacing = XINT (val);
411 else if (EQ (key, QCscalable))
412 scalable = ! NILP (val);
413 }
c2f5bfd6 414
8daf5667
KH
415 if (! NILP (script) && ! charset)
416 {
417 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
418
419 if (CONSP (chars))
420 {
421 charset = FcCharSetCreate ();
422 if (! charset)
423 goto err;
424 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
425 if (CHARACTERP (XCAR (chars))
426 && ! FcCharSetAddChar (charset, XUINT (XCAR (chars))))
427 goto err;
c2f5bfd6
KH
428 }
429 }
430
8daf5667 431 pattern = FcPatternCreate ();
706b6995
KH
432 if (! pattern)
433 goto err;
706b6995
KH
434 tmp = AREF (spec, FONT_FOUNDRY_INDEX);
435 if (SYMBOLP (tmp) && ! NILP (tmp)
436 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp)))
437 goto err;
438 tmp = AREF (spec, FONT_FAMILY_INDEX);
439 if (SYMBOLP (tmp) && ! NILP (tmp)
440 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp)))
441 goto err;
63565713
KH
442 /* Emacs conventionally doesn't distinguish normal, regular, and
443 medium weight, but fontconfig does. So, we can't restrict font
444 listing by weight. We check it after getting a list. */
706b6995 445 tmp = AREF (spec, FONT_WEIGHT_INDEX);
63565713
KH
446 if (INTEGERP (tmp))
447 weight = XINT (tmp);
706b6995
KH
448 tmp = AREF (spec, FONT_SLANT_INDEX);
449 if (INTEGERP (tmp)
706b6995
KH
450 && ! FcPatternAddInteger (pattern, FC_SLANT, XINT (tmp) - 100))
451 goto err;
452 tmp = AREF (spec, FONT_WIDTH_INDEX);
453 if (INTEGERP (tmp)
454 && ! FcPatternAddInteger (pattern, FC_WIDTH, XINT (tmp)))
455 goto err;
c2f5bfd6
KH
456
457 if (charset
458 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset))
459 goto err;
460 if (langset
461 && ! FcPatternAddLangSet (pattern, FC_LANG, langset))
462 goto err;
bc9a2afe
KH
463 if (dpi >= 0
464 && ! FcPatternAddDouble (pattern, FC_DPI, dpi))
465 goto err;
466 if (spacing >= 0
467 && ! FcPatternAddInteger (pattern, FC_SPACING, spacing))
468 goto err;
469 if (scalable >= 0
25a5d05b 470 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
bc9a2afe 471 goto err;
c2f5bfd6 472
706b6995
KH
473 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
474 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING,
e907d979
KH
475 FC_CHARSET, FC_FILE,
476#ifdef FC_FONTFORMAT
477 FC_FONTFORMAT,
478#endif /* FC_FONTFORMAT */
479 NULL);
706b6995
KH
480 if (! objset)
481 goto err;
bc5f6c42
KH
482 if (otf_script[0])
483 {
484#ifndef FC_CAPABILITY
485 goto finish;
486#else /* not FC_CAPABILITY */
487 if (! FcObjectSetAdd (objset, FC_CAPABILITY))
488 goto err;
bc5f6c42 489#endif /* not FC_CAPABILITY */
5ed08958 490 }
f63d54dc 491
706b6995
KH
492 fontset = FcFontList (NULL, pattern, objset);
493 if (! fontset)
494 goto err;
c2f5bfd6 495
706b6995
KH
496 if (fontset->nfont > 0)
497 {
f63d54dc
KH
498 double pixel_size;
499
500 if (NILP (AREF (spec, FONT_SIZE_INDEX)))
501 pixel_size = 0;
502 else
503 pixel_size = XINT (AREF (spec, FONT_SIZE_INDEX));
504
706b6995 505 for (i = 0, val = Qnil; i < fontset->nfont; i++)
c2f5bfd6 506 {
f63d54dc
KH
507 Lisp_Object entity;
508
509 if (pixel_size > 0)
510 {
511 double this;
512
513 if (FcPatternGetDouble (fontset->fonts[i], FC_PIXEL_SIZE, 0,
514 &this) == FcResultMatch
63565713
KH
515 && ((this < pixel_size - FONT_PIXEL_SIZE_QUANTUM)
516 || (this > pixel_size + FONT_PIXEL_SIZE_QUANTUM)))
517 continue;
518 }
519 if (weight > 0)
520 {
521 int this;
522
523 if (FcPatternGetInteger (fontset->fonts[i], FC_WEIGHT, 0,
524 &this) != FcResultMatch
525 || (this != weight
526 && (weight != 100
527 || this < FC_WEIGHT_REGULAR
528 || this > FC_WEIGHT_MEDIUM)))
f63d54dc
KH
529 continue;
530 }
bc5f6c42 531#ifdef FC_CAPABILITY
a85f724a
KH
532 if (otf_script[0])
533 {
534 FcChar8 *this;
535
536 if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0,
537 &this) != FcResultMatch
538 || ! strstr ((char *) this, otf_script))
539 continue;
540 }
bc5f6c42 541#endif /* FC_CAPABILITY */
f63d54dc 542 entity = ftfont_pattern_entity (fontset->fonts[i], frame, registry);
c2801c99
KH
543 if (! NILP (entity))
544 val = Fcons (entity, val);
c2f5bfd6 545 }
c2801c99 546 val = Fvconcat (1, &val);
c2f5bfd6 547 }
706b6995
KH
548 else if (! NILP (AREF (spec, FONT_FAMILY_INDEX)))
549 val = ftfont_list_generic_family (spec, frame, registry);
c2f5bfd6
KH
550 goto finish;
551
552 err:
553 /* We come here because of unexpected error in fontconfig API call
706b6995 554 (usually insufficient memory). */
c2f5bfd6
KH
555 val = Qnil;
556
557 finish:
558 if (charset && charset != cs_iso8859_1) FcCharSetDestroy (charset);
559 if (objset) FcObjectSetDestroy (objset);
560 if (fontset) FcFontSetDestroy (fontset);
561 if (langset) FcLangSetDestroy (langset);
562 if (pattern) FcPatternDestroy (pattern);
563
564 return val;
565}
566
8daf5667
KH
567static Lisp_Object
568ftfont_match (frame, spec)
569 Lisp_Object frame, spec;
570{
571 Lisp_Object extra, val, entity;
572 FcPattern *pattern = NULL, *match = NULL;
573 FcResult result;
574
575 if (! fc_initialized)
576 {
577 FcInit ();
578 fc_initialized = 1;
579 }
580
581 extra = AREF (spec, FONT_EXTRA_INDEX);
582 val = assq_no_quit (QCname, extra);
583 if (! CONSP (val) || ! STRINGP (XCDR (val)))
584 return Qnil;
585
586 entity = Qnil;
587 pattern = FcNameParse (SDATA (XCDR (val)));
588 if (pattern)
589 {
590 if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
591 {
592 FcDefaultSubstitute (pattern);
593 match = FcFontMatch (NULL, pattern, &result);
8daf5667
KH
594 if (match)
595 {
596 entity = ftfont_pattern_entity (match, frame, Qunicode_bmp);
597 FcPatternDestroy (match);
598 }
599 }
600 FcPatternDestroy (pattern);
601 }
602
603 return entity;
604}
605
c2f5bfd6
KH
606static Lisp_Object
607ftfont_list_family (frame)
608 Lisp_Object frame;
609{
610 Lisp_Object list;
611 FcPattern *pattern = NULL;
612 FcFontSet *fontset = NULL;
613 FcObjectSet *objset = NULL;
614 int i;
615
616 if (! fc_initialized)
617 {
618 FcInit ();
619 fc_initialized = 1;
620 }
621
622 pattern = FcPatternCreate ();
623 if (! pattern)
624 goto finish;
706b6995 625 objset = FcObjectSetBuild (FC_FAMILY, NULL);
c2f5bfd6
KH
626 if (! objset)
627 goto finish;
628 fontset = FcFontList (NULL, pattern, objset);
629 if (! fontset)
630 goto finish;
631
632 list = Qnil;
633 for (i = 0; i < fontset->nfont; i++)
634 {
635 FcPattern *pat = fontset->fonts[i];
636 FcChar8 *str;
637
638 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
639 list = Fcons (intern_downcase ((char *) str, strlen ((char *) str)),
640 list);
641 }
642
643 finish:
644 if (objset) FcObjectSetDestroy (objset);
645 if (fontset) FcFontSetDestroy (fontset);
646 if (pattern) FcPatternDestroy (pattern);
647
648 return list;
649}
650
651
652static void
653ftfont_free_entity (entity)
654 Lisp_Object entity;
655{
656 Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX);
657 FcPattern *pattern = XSAVE_VALUE (val)->pointer;
658
659 FcPatternDestroy (pattern);
660}
661
662static struct font *
663ftfont_open (f, entity, pixel_size)
664 FRAME_PTR f;
665 Lisp_Object entity;
666 int pixel_size;
667{
668 struct ftfont_info *ftfont_info;
669 struct font *font;
670 FT_Face ft_face;
671 FT_Size ft_size;
672 FT_UInt size;
673 Lisp_Object val;
674 FcPattern *pattern;
675 FcChar8 *file;
676 int spacing;
c9c0c429
KH
677 char *name;
678 int len;
c2f5bfd6
KH
679
680 val = AREF (entity, FONT_EXTRA_INDEX);
681 if (XTYPE (val) != Lisp_Misc
682 || XMISCTYPE (val) != Lisp_Misc_Save_Value)
683 return NULL;
684 pattern = XSAVE_VALUE (val)->pointer;
685 if (XSAVE_VALUE (val)->integer == 0)
686 {
687 /* We have not yet created FT_Face for this font. */
688 if (! ft_library
689 && FT_Init_FreeType (&ft_library) != 0)
690 return NULL;
691 if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch)
692 return NULL;
693 if (FT_New_Face (ft_library, (char *) file, 0, &ft_face) != 0)
694 return NULL;
695 FcPatternAddFTFace (pattern, FC_FT_FACE, ft_face);
696 ft_size = ft_face->size;
697 }
698 else
699 {
700 if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
701 != FcResultMatch)
702 return NULL;
703 if (FT_New_Size (ft_face, &ft_size) != 0)
704 return NULL;
705 if (FT_Activate_Size (ft_size) != 0)
706 {
707 FT_Done_Size (ft_size);
708 return NULL;
709 }
710 }
711
712 size = XINT (AREF (entity, FONT_SIZE_INDEX));
713 if (size == 0)
714 size = pixel_size;
715 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
716 {
717 if (XSAVE_VALUE (val)->integer == 0)
718 FT_Done_Face (ft_face);
719 return NULL;
720 }
721
722 ftfont_info = malloc (sizeof (struct ftfont_info));
723 if (! ftfont_info)
724 return NULL;
725 ftfont_info->ft_size = ft_size;
726
727 font = (struct font *) ftfont_info;
0b966021 728 font->format = ftfont_font_format (pattern);
c2f5bfd6
KH
729 font->entity = entity;
730 font->pixel_size = size;
731 font->driver = &ftfont_driver;
c9c0c429
KH
732 len = 96;
733 name = malloc (len);
734 while (name && font_unparse_fcname (entity, pixel_size, name, len) < 0)
735 {
736 char *new = realloc (name, len += 32);
737
738 if (! new)
739 free (name);
740 name = new;
741 }
742 font->font.full_name = font->font.name = name;
c2f5bfd6
KH
743 font->file_name = (char *) file;
744 font->font.size = ft_face->size->metrics.max_advance >> 6;
c9c0c429
KH
745 if (font->font.size <= 0)
746 font->font.size = size;
a85f724a 747 font->font.charset = font->encoding_charset = font->repertory_charset = -1;
c2f5bfd6
KH
748 font->ascent = ft_face->size->metrics.ascender >> 6;
749 font->descent = - ft_face->size->metrics.descender >> 6;
c9c0c429
KH
750 font->font.height = font->ascent + font->descent;
751 if (FcPatternGetInteger (pattern, FC_SPACING, 0, &spacing) != FcResultMatch)
752 spacing = FC_PROPORTIONAL;
753 if (spacing != FC_PROPORTIONAL)
c2f5bfd6
KH
754 font->font.average_width = font->font.space_width = font->font.size;
755 else
756 {
757 int i;
758
759 for (i = 32; i < 127; i++)
760 {
761 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) != 0)
762 break;
763 if (i == 32)
764 font->font.space_width = ft_face->glyph->metrics.horiAdvance >> 6;
765 font->font.average_width += ft_face->glyph->metrics.horiAdvance >> 6;
766 }
767 if (i == 127)
768 {
769 /* The font contains all ASCII printable characters. */
770 font->font.average_width /= 95;
771 }
772 else
773 {
774 if (i == 32)
775 font->font.space_width = font->font.size;
776 font->font.average_width = font->font.size;
777 }
778 }
779
c9c0c429
KH
780 /* Unfortunately FreeType doesn't provide a way to get minimum char
781 width. So, we use space_width instead. */
782 font->min_width = font->font.space_width;
783
c2f5bfd6
KH
784 font->font.baseline_offset = 0;
785 font->font.relative_compose = 0;
786 font->font.default_ascent = 0;
787 font->font.vertical_centering = 0;
788
789 (XSAVE_VALUE (val)->integer)++;
790
791 return font;
792}
793
794static void
795ftfont_close (f, font)
796 FRAME_PTR f;
797 struct font *font;
798{
799 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
800 Lisp_Object entity = font->entity;
801 Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX);
802
803 (XSAVE_VALUE (val)->integer)--;
804 if (XSAVE_VALUE (val)->integer == 0)
805 FT_Done_Face (ftfont_info->ft_size->face);
806 else
807 FT_Done_Size (ftfont_info->ft_size);
808
809 free (font);
810}
811
812static int
813ftfont_has_char (entity, c)
814 Lisp_Object entity;
815 int c;
816{
817 Lisp_Object val;
818 FcPattern *pattern;
819 FcCharSet *charset;
820
821 val = AREF (entity, FONT_EXTRA_INDEX);
822 pattern = XSAVE_VALUE (val)->pointer;
c2801c99
KH
823 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
824 return -1;
c2f5bfd6
KH
825 return (FcCharSetHasChar (charset, (FcChar32) c) == FcTrue);
826}
827
828static unsigned
829ftfont_encode_char (font, c)
830 struct font *font;
831 int c;
832{
833 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
834 FT_Face ft_face = ftfont_info->ft_size->face;
835 FT_ULong charcode = c;
836 FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
837
838 return (code > 0 ? code : 0xFFFFFFFF);
839}
840
841static int
842ftfont_text_extents (font, code, nglyphs, metrics)
843 struct font *font;
844 unsigned *code;
845 int nglyphs;
846 struct font_metrics *metrics;
847{
848 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
849 FT_Face ft_face = ftfont_info->ft_size->face;
850 int width = 0;
851 int i;
852
853 if (ftfont_info->ft_size != ft_face->size)
854 FT_Activate_Size (ftfont_info->ft_size);
855 if (metrics)
856 bzero (metrics, sizeof (struct font_metrics));
857 for (i = 0; i < nglyphs; i++)
858 {
859 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
860 {
861 FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
862
863 if (metrics)
864 {
865 if (metrics->lbearing > width + (m->horiBearingX >> 6))
866 metrics->lbearing = width + (m->horiBearingX >> 6);
867 if (metrics->rbearing
868 < width + ((m->horiBearingX + m->width) >> 6))
869 metrics->rbearing
870 = width + ((m->horiBearingX + m->width) >> 6);
871 if (metrics->ascent < (m->horiBearingY >> 6))
872 metrics->ascent = m->horiBearingY >> 6;
873 if (metrics->descent > ((m->horiBearingY + m->height) >> 6))
874 metrics->descent = (m->horiBearingY + m->height) >> 6;
875 }
876 width += m->horiAdvance >> 6;
877 }
878 else
879 {
880 width += font->font.space_width;
881 }
882 }
883 if (metrics)
884 metrics->width = width;
885
886 return width;
887}
888
889static int
890ftfont_get_bitmap (font, code, bitmap, bits_per_pixel)
891 struct font *font;
892 unsigned code;
893 struct font_bitmap *bitmap;
894 int bits_per_pixel;
895{
896 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
897 FT_Face ft_face = ftfont_info->ft_size->face;
898 FT_Int32 load_flags = FT_LOAD_RENDER;
899
900 if (ftfont_info->ft_size != ft_face->size)
901 FT_Activate_Size (ftfont_info->ft_size);
902 if (bits_per_pixel == 1)
903 {
904#ifdef FT_LOAD_TARGET_MONO
905 load_flags |= FT_LOAD_TARGET_MONO;
906#else
907 load_flags |= FT_LOAD_MONOCHROME;
908#endif
909 }
910 else if (bits_per_pixel != 8)
911 /* We don't support such a rendering. */
912 return -1;
913
914 if (FT_Load_Glyph (ft_face, code, load_flags) != 0)
915 return -1;
b51e5112
KH
916 bitmap->bits_per_pixel
917 = (ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 1
918 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ? 8
919 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ? 8
920 : ft_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V ? 8
921 : -1);
922 if (bitmap->bits_per_pixel < 0)
923 /* We don't suport that kind of pixel mode. */
924 return -1;
c2f5bfd6
KH
925 bitmap->rows = ft_face->glyph->bitmap.rows;
926 bitmap->width = ft_face->glyph->bitmap.width;
927 bitmap->pitch = ft_face->glyph->bitmap.pitch;
928 bitmap->buffer = ft_face->glyph->bitmap.buffer;
929 bitmap->left = ft_face->glyph->bitmap_left;
930 bitmap->top = ft_face->glyph->bitmap_top;
931 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
932 bitmap->extra = NULL;
933
934 return 0;
935}
936
937static int
938ftfont_anchor_point (font, code, index, x, y)
939 struct font *font;
940 unsigned code;
941 int index;
942 int *x, *y;
943{
944 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
945 FT_Face ft_face = ftfont_info->ft_size->face;
946
947 if (ftfont_info->ft_size != ft_face->size)
948 FT_Activate_Size (ftfont_info->ft_size);
949 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
950 return -1;
951 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
952 return -1;
953 if (index >= ft_face->glyph->outline.n_points)
954 return -1;
955 *x = ft_face->glyph->outline.points[index].x;
956 *y = ft_face->glyph->outline.points[index].y;
957 return 0;
958}
959
0b966021
KH
960Lisp_Object
961ftfont_font_format (FcPattern *pattern)
962{
e907d979 963 FcChar8 *str;
0b966021 964
e907d979
KH
965#ifdef FC_FONTFORMAT
966 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
0b966021 967 return Qnil;
e907d979 968 if (strcmp ((char *) str, "TrueType") == 0)
0b966021 969 return intern ("truetype");
48875afe 970 if (strcmp ((char *) str, "Type 1") == 0)
0b966021 971 return intern ("type1");
e907d979 972 if (strcmp ((char *) str, "PCF") == 0)
0b966021 973 return intern ("pcf");
e907d979 974 if (strcmp ((char *) str, "BDF") == 0)
0b966021 975 return intern ("bdf");
e907d979 976#else /* not FC_FONTFORMAT */
09a56ce4 977 if (FcPatternGetString (pattern, FC_FILE, 0, &str) != FcResultMatch)
e907d979
KH
978 return Qnil;
979 if (strcasestr ((char *) str, ".ttf") == 0)
980 return intern ("truetype");
981 if (strcasestr ((char *) str, "pfb") == 0)
982 return intern ("type1");
983 if (strcasestr ((char *) str, "pcf") == 0)
984 return intern ("pcf");
985 if (strcasestr ((char *) str, "bdf") == 0)
986 return intern ("bdf");
987#endif /* not FC_FONTFORMAT */
0b966021
KH
988 return intern ("unknown");
989}
990
c2f5bfd6
KH
991\f
992void
993syms_of_ftfont ()
994{
706b6995
KH
995 DEFSYM (Qfreetype, "freetype");
996 DEFSYM (Qmonospace, "monospace");
997 DEFSYM (Qsans_serif, "sans-serif");
998 DEFSYM (Qserif, "serif");
999 DEFSYM (Qmono, "mono");
1000 DEFSYM (Qsans, "sans");
1001 DEFSYM (Qsans__serif, "sans serif");
1002
c2f5bfd6 1003 staticpro (&freetype_font_cache);
c2801c99 1004 freetype_font_cache = Fcons (Qt, Qnil);
c2f5bfd6 1005
706b6995
KH
1006 staticpro (&ftfont_generic_family_list);
1007 ftfont_generic_family_list
1008 = Fcons (Fcons (Qmonospace, Qt),
1009 Fcons (Fcons (Qsans_serif, Qt),
1010 Fcons (Fcons (Qsans, Qt), Qnil)));
c2f5bfd6
KH
1011
1012 ftfont_driver.type = Qfreetype;
1013 register_font_driver (&ftfont_driver, NULL);
1014}
885b7d09
MB
1015
1016/* arch-tag: 7cfa432c-33a6-4988-83d2-a82ed8604aca
1017 (do not change this comment) */