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