Merge from emacs--devo--0
[bpt/emacs.git] / src / ftfont.c
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
7 This file is part of GNU Emacs.
8
9 GNU Emacs is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, 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
43 /* Symbolic type of this font-driver. */
44 Lisp_Object Qfreetype;
45
46 /* Fontconfig's generic families and their aliases. */
47 static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
48
49 /* Flag to tell if FcInit is areadly called or not. */
50 static int fc_initialized;
51
52 /* Handle to a FreeType library instance. */
53 static FT_Library ft_library;
54
55 /* Cache for FreeType fonts. */
56 static Lisp_Object freetype_font_cache;
57
58 /* Fontconfig's charset used for finding fonts of registry
59 "iso8859-1". */
60 static FcCharSet *cs_iso8859_1;
61
62 /* The actual structure for FreeType font that can be casted to struct
63 font. */
64
65 struct ftfont_info
66 {
67 struct font font;
68 FT_Size ft_size;
69 };
70
71 static int ftfont_build_basic_charsets P_ ((void));
72 static Lisp_Object ftfont_pattern_entity P_ ((FcPattern *,
73 Lisp_Object, Lisp_Object));
74 static Lisp_Object ftfont_list_generic_family P_ ((Lisp_Object, Lisp_Object,
75 Lisp_Object));
76 Lisp_Object ftfont_font_format P_ ((FcPattern *));
77
78 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
79
80 static int
81 ftfont_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;
91 #if 0
92 /* This part is currently disabled. Should be fixed later. */
93 for (c = 192; c < 256; c++)
94 if (! FcCharSetAddChar (cs_iso8859_1, c))
95 return -1;
96 #endif
97 return 0;
98 }
99
100 static Lisp_Object
101 ftfont_pattern_entity (p, frame, registry)
102 FcPattern *p;
103 Lisp_Object frame, registry;
104 {
105 Lisp_Object entity;
106 FcChar8 *file, *fontformat;
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;
114 if (FcPatternGetCharSet (p, FC_CHARSET, 0, &charset) != FcResultMatch)
115 charset = NULL;
116 #ifdef FC_FONTFORMAT
117 if (FcPatternGetString (p, FC_FONTFORMAT, 0, &fontformat) != FcResultMatch)
118 #endif /* FC_FONTFORMAT */
119 fontformat = NULL;
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)
133 {
134 if (numeric == FC_WEIGHT_REGULAR)
135 numeric = 100;
136 ASET (entity, FONT_WEIGHT_INDEX, make_number (numeric));
137 }
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)
148 numeric = -1;
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
158 || (charset
159 && FcPatternAddCharSet (p, FC_CHARSET, charset) == FcFalse)
160 #ifdef FC_FONTFORMAT
161 || (fontformat
162 && FcPatternAddString (p, FC_FONTFORMAT, fontformat) == FcFalse)
163 #endif /* FC_FONTFORMAT */
164 || (numeric >= 0
165 && FcPatternAddInteger (p, FC_SPACING, numeric) == FcFalse))
166 {
167 FcPatternDestroy (p);
168 return Qnil;
169 }
170 ASET (entity, FONT_EXTRA_INDEX, make_save_value (p, 0));
171 return entity;
172 }
173
174 static Lisp_Object ftfont_generic_family_list;
175
176 static Lisp_Object
177 ftfont_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,
202 FC_CHARSET, FC_FILE,
203 #ifdef FC_FONTFORMAT
204 FC_FONTFORMAT,
205 #endif /* FC_FONTFORMAT */
206 NULL);
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
262
263 static Lisp_Object ftfont_get_cache P_ ((Lisp_Object));
264 static Lisp_Object ftfont_list P_ ((Lisp_Object, Lisp_Object));
265 static Lisp_Object ftfont_match P_ ((Lisp_Object, Lisp_Object));
266 static Lisp_Object ftfont_list_family P_ ((Lisp_Object));
267 static void ftfont_free_entity P_ ((Lisp_Object));
268 static struct font *ftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
269 static void ftfont_close P_ ((FRAME_PTR, struct font *));
270 static int ftfont_has_char P_ ((Lisp_Object, int));
271 static unsigned ftfont_encode_char P_ ((struct font *, int));
272 static int ftfont_text_extents P_ ((struct font *, unsigned *, int,
273 struct font_metrics *));
274 static int ftfont_get_bitmap P_ ((struct font *, unsigned,
275 struct font_bitmap *, int));
276 static int ftfont_anchor_point P_ ((struct font *, unsigned, int,
277 int *, int *));
278
279 struct font_driver ftfont_driver =
280 {
281 0, /* Qfreetype */
282 ftfont_get_cache,
283 ftfont_list,
284 ftfont_match,
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,
304 font_drive_otf,
305 #else
306 NULL,
307 NULL,
308 NULL
309 #endif /* HAVE_LIBOTF */
310 };
311
312 extern Lisp_Object QCname;
313
314 static Lisp_Object
315 ftfont_get_cache (frame)
316 Lisp_Object frame;
317 {
318 return freetype_font_cache;
319 }
320
321 static Lisp_Object
322 ftfont_list (frame, spec)
323 Lisp_Object frame, spec;
324 {
325 Lisp_Object val, tmp, extra;
326 int i;
327 FcPattern *pattern = NULL;
328 FcCharSet *charset = NULL;
329 FcLangSet *langset = NULL;
330 FcFontSet *fontset = NULL;
331 FcObjectSet *objset = NULL;
332 Lisp_Object script;
333 Lisp_Object registry = Qunicode_bmp;
334 int weight = 0;
335 double dpi = -1;
336 int spacing = -1;
337 int scalable = -1;
338 char otf_script[15]; /* For "otlayout\:XXXX" */
339
340 val = null_vector;
341
342 if (! fc_initialized)
343 {
344 FcInit ();
345 fc_initialized = 1;
346 }
347
348 if (! NILP (AREF (spec, FONT_ADSTYLE_INDEX))
349 && ! EQ (AREF (spec, FONT_ADSTYLE_INDEX), null_string))
350 return val;
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
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)
363 return Qnil;
364 charset = cs_iso8859_1;
365 }
366 else if (! EQ (registry, Qiso10646_1)
367 && ! EQ (registry, Qunicode_bmp)
368 && ! EQ (registry, Qunicode_sip))
369 return val;
370 }
371
372 otf_script[0] = '\0';
373 script = Qnil;
374 for (extra = AREF (spec, FONT_EXTRA_INDEX);
375 CONSP (extra); extra = XCDR (extra))
376 {
377 Lisp_Object key, val;
378
379 tmp = XCAR (extra);
380 key = XCAR (tmp), val = XCDR (tmp);
381 if (EQ (key, QCotf))
382 {
383 script = assq_no_quit (val, Votf_script_alist);
384 if (CONSP (script) && SYMBOLP (XCDR (script)))
385 script = XCDR (script);
386 tmp = SYMBOL_NAME (val);
387 sprintf (otf_script, "otlayout:%s", (char *) SDATA (tmp));
388 }
389 else if (EQ (key, QClanguage))
390 {
391 langset = FcLangSetCreate ();
392 if (! langset)
393 goto err;
394 if (SYMBOLP (val))
395 {
396 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (val)))
397 goto err;
398 }
399 else
400 for (; CONSP (val); val = XCDR (val))
401 if (SYMBOLP (XCAR (val))
402 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (val))))
403 goto err;
404 }
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 }
414
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;
428 }
429 }
430
431 pattern = FcPatternCreate ();
432 if (! pattern)
433 goto err;
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;
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. */
445 tmp = AREF (spec, FONT_WEIGHT_INDEX);
446 if (INTEGERP (tmp))
447 weight = XINT (tmp);
448 tmp = AREF (spec, FONT_SLANT_INDEX);
449 if (INTEGERP (tmp)
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;
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;
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
470 && ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
471 goto err;
472
473 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT,
474 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING,
475 FC_CHARSET, FC_FILE,
476 #ifdef FC_FONTFORMAT
477 FC_FONTFORMAT,
478 #endif /* FC_FONTFORMAT */
479 NULL);
480 if (! objset)
481 goto err;
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;
489 #endif /* not FC_CAPABILITY */
490 }
491
492 fontset = FcFontList (NULL, pattern, objset);
493 if (! fontset)
494 goto err;
495
496 if (fontset->nfont > 0)
497 {
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
505 for (i = 0, val = Qnil; i < fontset->nfont; i++)
506 {
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
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)))
529 continue;
530 }
531 #ifdef FC_CAPABILITY
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 }
541 #endif /* FC_CAPABILITY */
542 entity = ftfont_pattern_entity (fontset->fonts[i], frame, registry);
543 if (! NILP (entity))
544 val = Fcons (entity, val);
545 }
546 val = Fvconcat (1, &val);
547 }
548 else if (! NILP (AREF (spec, FONT_FAMILY_INDEX)))
549 val = ftfont_list_generic_family (spec, frame, registry);
550 goto finish;
551
552 err:
553 /* We come here because of unexpected error in fontconfig API call
554 (usually insufficient memory). */
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
567 static Lisp_Object
568 ftfont_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);
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
606 static Lisp_Object
607 ftfont_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;
625 objset = FcObjectSetBuild (FC_FAMILY, NULL);
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
652 static void
653 ftfont_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
662 static struct font *
663 ftfont_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;
677 char *name;
678 int len;
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;
728 font->format = ftfont_font_format (pattern);
729 font->entity = entity;
730 font->pixel_size = size;
731 font->driver = &ftfont_driver;
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;
743 font->file_name = (char *) file;
744 font->font.size = ft_face->size->metrics.max_advance >> 6;
745 if (font->font.size <= 0)
746 font->font.size = size;
747 font->font.charset = font->encoding_charset = font->repertory_charset = -1;
748 font->ascent = ft_face->size->metrics.ascender >> 6;
749 font->descent = - ft_face->size->metrics.descender >> 6;
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)
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
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
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
794 static void
795 ftfont_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
812 static int
813 ftfont_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;
823 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
824 return -1;
825 return (FcCharSetHasChar (charset, (FcChar32) c) == FcTrue);
826 }
827
828 static unsigned
829 ftfont_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
841 static int
842 ftfont_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
889 static int
890 ftfont_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;
916 bitmap->rows = ft_face->glyph->bitmap.rows;
917 bitmap->width = ft_face->glyph->bitmap.width;
918 bitmap->pitch = ft_face->glyph->bitmap.pitch;
919 bitmap->buffer = ft_face->glyph->bitmap.buffer;
920 bitmap->left = ft_face->glyph->bitmap_left;
921 bitmap->top = ft_face->glyph->bitmap_top;
922 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6;
923 bitmap->extra = NULL;
924
925 return 0;
926 }
927
928 static int
929 ftfont_anchor_point (font, code, index, x, y)
930 struct font *font;
931 unsigned code;
932 int index;
933 int *x, *y;
934 {
935 struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
936 FT_Face ft_face = ftfont_info->ft_size->face;
937
938 if (ftfont_info->ft_size != ft_face->size)
939 FT_Activate_Size (ftfont_info->ft_size);
940 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
941 return -1;
942 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
943 return -1;
944 if (index >= ft_face->glyph->outline.n_points)
945 return -1;
946 *x = ft_face->glyph->outline.points[index].x;
947 *y = ft_face->glyph->outline.points[index].y;
948 return 0;
949 }
950
951 Lisp_Object
952 ftfont_font_format (FcPattern *pattern)
953 {
954 FcChar8 *str;
955
956 #ifdef FC_FONTFORMAT
957 if (FcPatternGetString (pattern, FC_FONTFORMAT, 0, &str) != FcResultMatch)
958 return Qnil;
959 if (strcmp ((char *) str, "TrueType") == 0)
960 return intern ("truetype");
961 if (strcmp ((char *) str, "Type 1") == 0)
962 return intern ("type1");
963 if (strcmp ((char *) str, "PCF") == 0)
964 return intern ("pcf");
965 if (strcmp ((char *) str, "BDF") == 0)
966 return intern ("bdf");
967 #else /* not FC_FONTFORMAT */
968 if (FcPatternGetString (pattern, FC_FILE, 0, &str) != FcResultMatch)
969 return Qnil;
970 if (strcasestr ((char *) str, ".ttf") == 0)
971 return intern ("truetype");
972 if (strcasestr ((char *) str, "pfb") == 0)
973 return intern ("type1");
974 if (strcasestr ((char *) str, "pcf") == 0)
975 return intern ("pcf");
976 if (strcasestr ((char *) str, "bdf") == 0)
977 return intern ("bdf");
978 #endif /* not FC_FONTFORMAT */
979 return intern ("unknown");
980 }
981
982 \f
983 void
984 syms_of_ftfont ()
985 {
986 DEFSYM (Qfreetype, "freetype");
987 DEFSYM (Qmonospace, "monospace");
988 DEFSYM (Qsans_serif, "sans-serif");
989 DEFSYM (Qserif, "serif");
990 DEFSYM (Qmono, "mono");
991 DEFSYM (Qsans, "sans");
992 DEFSYM (Qsans__serif, "sans serif");
993
994 staticpro (&freetype_font_cache);
995 freetype_font_cache = Fcons (Qt, Qnil);
996
997 staticpro (&ftfont_generic_family_list);
998 ftfont_generic_family_list
999 = Fcons (Fcons (Qmonospace, Qt),
1000 Fcons (Fcons (Qsans_serif, Qt),
1001 Fcons (Fcons (Qsans, Qt), Qnil)));
1002
1003 ftfont_driver.type = Qfreetype;
1004 register_font_driver (&ftfont_driver, NULL);
1005 }
1006
1007 /* arch-tag: 7cfa432c-33a6-4988-83d2-a82ed8604aca
1008 (do not change this comment) */