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