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