Mercurial > emacs
comparison src/ftfont.c @ 90400:80fff33f74f5
New file.
author | Kenichi Handa <handa@m17n.org> |
---|---|
date | Tue, 06 Jun 2006 03:47:13 +0000 |
parents | |
children | ddb25860d044 |
comparison
equal
deleted
inserted
replaced
90399:a5812696f7bf | 90400:80fff33f74f5 |
---|---|
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 Lisp_Object Qfreetype; | |
44 | |
45 static int fc_initialized; | |
46 static FT_Library ft_library; | |
47 | |
48 static Lisp_Object freetype_font_cache; | |
49 | |
50 static Lisp_Object Qiso8859_1, Qiso10646_1, Qunicode_bmp; | |
51 | |
52 static FcCharSet *cs_iso8859_1; | |
53 | |
54 /* The actual structure for FreeType font that can be casted to struct | |
55 font. */ | |
56 | |
57 struct ftfont_info | |
58 { | |
59 struct font font; | |
60 FT_Size ft_size; | |
61 }; | |
62 | |
63 static int | |
64 ftfont_build_basic_charsets () | |
65 { | |
66 FcChar32 c; | |
67 | |
68 cs_iso8859_1 = FcCharSetCreate (); | |
69 if (! cs_iso8859_1) | |
70 return -1; | |
71 for (c = ' '; c < 127; c++) | |
72 if (! FcCharSetAddChar (cs_iso8859_1, c)) | |
73 return -1; | |
74 for (c = 192; c < 256; c++) | |
75 if (! FcCharSetAddChar (cs_iso8859_1, c)) | |
76 return -1; | |
77 return 0; | |
78 } | |
79 | |
80 static Lisp_Object ftfont_get_cache P_ ((Lisp_Object)); | |
81 static int ftfont_parse_name P_ ((FRAME_PTR, char *, Lisp_Object)); | |
82 static Lisp_Object ftfont_list P_ ((Lisp_Object, Lisp_Object)); | |
83 static Lisp_Object ftfont_list_family P_ ((Lisp_Object)); | |
84 static void ftfont_free_entity P_ ((Lisp_Object)); | |
85 static struct font *ftfont_open P_ ((FRAME_PTR, Lisp_Object, int)); | |
86 static void ftfont_close P_ ((FRAME_PTR, struct font *)); | |
87 static int ftfont_has_char P_ ((Lisp_Object, int)); | |
88 static unsigned ftfont_encode_char P_ ((struct font *, int)); | |
89 static int ftfont_text_extents P_ ((struct font *, unsigned *, int, | |
90 struct font_metrics *)); | |
91 static int ftfont_get_bitmap P_ ((struct font *, unsigned, | |
92 struct font_bitmap *, int)); | |
93 static int ftfont_anchor_point P_ ((struct font *, unsigned, int, | |
94 int *, int *)); | |
95 | |
96 struct font_driver ftfont_driver = | |
97 { | |
98 (Lisp_Object) NULL, /* Qfreetype */ | |
99 ftfont_get_cache, | |
100 ftfont_parse_name, | |
101 ftfont_list, | |
102 ftfont_list_family, | |
103 ftfont_free_entity, | |
104 ftfont_open, | |
105 ftfont_close, | |
106 /* We can't draw a text without device dependent functions. */ | |
107 NULL, | |
108 NULL, | |
109 ftfont_has_char, | |
110 ftfont_encode_char, | |
111 ftfont_text_extents, | |
112 /* We can't draw a text without device dependent functions. */ | |
113 NULL, | |
114 ftfont_get_bitmap, | |
115 NULL, | |
116 NULL, | |
117 NULL, | |
118 ftfont_anchor_point, | |
119 #ifdef HAVE_LIBOTF | |
120 font_otf_capability, | |
121 font_otf_gsub, | |
122 font_otf_gpos | |
123 #else | |
124 NULL, | |
125 NULL, | |
126 NULL | |
127 #endif /* HAVE_LIBOTF */ | |
128 }; | |
129 | |
130 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM)) | |
131 | |
132 extern Lisp_Object QCname; | |
133 | |
134 static Lisp_Object | |
135 ftfont_get_cache (frame) | |
136 Lisp_Object frame; | |
137 { | |
138 if (NILP (freetype_font_cache)) | |
139 freetype_font_cache = Fcons (Qt, Qnil); | |
140 return freetype_font_cache; | |
141 } | |
142 | |
143 static int | |
144 ftfont_parse_name (f, name, spec) | |
145 FRAME_PTR f; | |
146 char *name; | |
147 Lisp_Object spec; | |
148 { | |
149 FcPattern *p; | |
150 FcChar8 *str; | |
151 int numeric; | |
152 double dbl; | |
153 | |
154 if (name[0] == '-' || strchr (name, '*')) | |
155 /* It seems that NAME is XLFD. */ | |
156 return -1; | |
157 p = FcNameParse ((FcChar8 *) name); | |
158 if (! p) | |
159 return -1; | |
160 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch) | |
161 ASET (spec, FONT_FOUNDRY_INDEX, | |
162 intern_downcase ((char *) str, strlen ((char *) str))); | |
163 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch) | |
164 ASET (spec, FONT_FAMILY_INDEX, | |
165 intern_downcase ((char *) str, strlen ((char *) str))); | |
166 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch) | |
167 ASET (spec, FONT_WEIGHT_INDEX, make_number (numeric)); | |
168 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch) | |
169 ASET (spec, FONT_SLANT_INDEX, make_number (numeric + 100)); | |
170 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch) | |
171 ASET (spec, FONT_WIDTH_INDEX, make_number (numeric)); | |
172 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch) | |
173 ASET (spec, FONT_SIZE_INDEX, make_number (dbl)); | |
174 else if (FcPatternGetDouble (p, FC_SIZE, 0, &dbl) == FcResultMatch) | |
175 ASET (spec, FONT_SIZE_INDEX, make_float (dbl)); | |
176 return 0; | |
177 } | |
178 | |
179 static Lisp_Object | |
180 ftfont_list (frame, spec) | |
181 Lisp_Object frame, spec; | |
182 { | |
183 Lisp_Object val, tmp, extra, font_name; | |
184 int i; | |
185 FcPattern *pattern = NULL; | |
186 FcCharSet *charset = NULL; | |
187 FcLangSet *langset = NULL; | |
188 FcFontSet *fontset = NULL; | |
189 FcObjectSet *objset = NULL; | |
190 Lisp_Object registry = Qnil; | |
191 | |
192 val = null_vector; | |
193 | |
194 if (! fc_initialized) | |
195 { | |
196 FcInit (); | |
197 fc_initialized = 1; | |
198 } | |
199 | |
200 if (! NILP (AREF (spec, FONT_ADSTYLE_INDEX))) | |
201 return val; | |
202 if (! NILP (AREF (spec, FONT_REGISTRY_INDEX))) | |
203 { | |
204 registry = AREF (spec, FONT_REGISTRY_INDEX); | |
205 if (EQ (registry, Qiso8859_1)) | |
206 { | |
207 if (! cs_iso8859_1 | |
208 && ftfont_build_basic_charsets () < 0) | |
209 goto err; | |
210 charset = cs_iso8859_1; | |
211 registry = Qnil; | |
212 } | |
213 } | |
214 | |
215 extra = AREF (spec, FONT_EXTRA_INDEX); | |
216 font_name = Qnil; | |
217 if (CONSP (extra)) | |
218 { | |
219 tmp = Fassq (QCotf, extra); | |
220 if (! NILP (tmp)) | |
221 return val; | |
222 tmp = Fassq (QClanguage, extra); | |
223 if (CONSP (tmp)) | |
224 { | |
225 langset = FcLangSetCreate (); | |
226 if (! langset) | |
227 goto err; | |
228 tmp = XCDR (tmp); | |
229 if (SYMBOLP (tmp)) | |
230 { | |
231 if (! FcLangSetAdd (langset, SYMBOL_FcChar8 (tmp))) | |
232 goto err; | |
233 } | |
234 else | |
235 while (CONSP (tmp)) | |
236 { | |
237 if (SYMBOLP (XCAR (tmp)) | |
238 && ! FcLangSetAdd (langset, SYMBOL_FcChar8 (XCAR (tmp)))) | |
239 goto err; | |
240 tmp = XCDR (tmp); | |
241 } | |
242 } | |
243 tmp = Fassq (QCname, extra); | |
244 if (CONSP (tmp)) | |
245 font_name = XCDR (tmp); | |
246 tmp = Fassq (QCscript, extra); | |
247 if (CONSP (tmp) && ! charset) | |
248 { | |
249 Lisp_Object script = XCDR (tmp); | |
250 Lisp_Object chars = assq_no_quit (script, | |
251 Vscript_representative_chars); | |
252 | |
253 if (CONSP (chars)) | |
254 { | |
255 charset = FcCharSetCreate (); | |
256 if (! charset) | |
257 goto err; | |
258 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars)) | |
259 if (CHARACTERP (XCAR (chars)) | |
260 && ! FcCharSetAddChar (charset, XUINT (XCAR (chars)))) | |
261 goto err; | |
262 } | |
263 } | |
264 } | |
265 | |
266 if (! NILP (registry) && ! charset) | |
267 goto finish; | |
268 | |
269 if (STRINGP (font_name)) | |
270 { | |
271 if (! isalpha (SDATA (font_name)[0])) | |
272 goto finish; | |
273 pattern = FcNameParse (SDATA (font_name)); | |
274 if (! pattern) | |
275 goto err; | |
276 } | |
277 else | |
278 { | |
279 pattern = FcPatternCreate (); | |
280 if (! pattern) | |
281 goto err; | |
282 | |
283 tmp = AREF (spec, FONT_FOUNDRY_INDEX); | |
284 if (SYMBOLP (tmp) && ! NILP (tmp) | |
285 && ! FcPatternAddString (pattern, FC_FOUNDRY, SYMBOL_FcChar8 (tmp))) | |
286 goto err; | |
287 tmp = AREF (spec, FONT_FAMILY_INDEX); | |
288 if (SYMBOLP (tmp) && ! NILP (tmp) | |
289 && ! FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (tmp))) | |
290 goto err; | |
291 tmp = AREF (spec, FONT_WEIGHT_INDEX); | |
292 if (INTEGERP (tmp) | |
293 && ! FcPatternAddInteger (pattern, FC_WEIGHT, XINT (tmp))) | |
294 goto err; | |
295 tmp = AREF (spec, FONT_SLANT_INDEX); | |
296 if (INTEGERP (tmp) | |
297 && XINT (tmp) >= 100 | |
298 && ! FcPatternAddInteger (pattern, FC_SLANT, XINT (tmp) - 100)) | |
299 goto err; | |
300 tmp = AREF (spec, FONT_WIDTH_INDEX); | |
301 if (INTEGERP (tmp) | |
302 && ! FcPatternAddInteger (pattern, FC_WIDTH, XINT (tmp))) | |
303 goto err; | |
304 if (! FcPatternAddBool (pattern, FC_SCALABLE, FcTrue)) | |
305 goto err; | |
306 } | |
307 | |
308 if (charset | |
309 && ! FcPatternAddCharSet (pattern, FC_CHARSET, charset)) | |
310 goto err; | |
311 if (langset | |
312 && ! FcPatternAddLangSet (pattern, FC_LANG, langset)) | |
313 goto err; | |
314 objset = FcObjectSetBuild (FC_FOUNDRY, FC_FAMILY, FC_WEIGHT, FC_SLANT, | |
315 FC_WIDTH, FC_PIXEL_SIZE, FC_SPACING, | |
316 FC_CHARSET, FC_FILE, NULL); | |
317 if (! objset) | |
318 goto err; | |
319 | |
320 BLOCK_INPUT; | |
321 fontset = FcFontList (NULL, pattern, objset); | |
322 UNBLOCK_INPUT; | |
323 if (! fontset) | |
324 goto err; | |
325 val = Qnil; | |
326 for (i = 0; i < fontset->nfont; i++) | |
327 { | |
328 FcPattern *p = fontset->fonts[i]; | |
329 FcChar8 *str, *file; | |
330 | |
331 if (FcPatternGetString (p, FC_FILE, 0, &file) == FcResultMatch | |
332 && FcPatternGetCharSet (p, FC_CHARSET, 0, &charset) == FcResultMatch) | |
333 { | |
334 Lisp_Object entity = Fmake_vector (make_number (FONT_ENTITY_MAX), | |
335 null_string); | |
336 int numeric; | |
337 double dbl; | |
338 FcPattern *p0; | |
339 | |
340 ASET (entity, FONT_TYPE_INDEX, Qfreetype); | |
341 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1); | |
342 ASET (entity, FONT_FRAME_INDEX, frame); | |
343 ASET (entity, FONT_OBJLIST_INDEX, Qnil); | |
344 | |
345 if (FcPatternGetString (p, FC_FOUNDRY, 0, &str) == FcResultMatch) | |
346 ASET (entity, FONT_FOUNDRY_INDEX, | |
347 intern_downcase ((char *) str, strlen ((char *) str))); | |
348 if (FcPatternGetString (p, FC_FAMILY, 0, &str) == FcResultMatch) | |
349 ASET (entity, FONT_FAMILY_INDEX, | |
350 intern_downcase ((char *) str, strlen ((char *) str))); | |
351 if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch) | |
352 ASET (entity, FONT_WEIGHT_INDEX, make_number (numeric)); | |
353 if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch) | |
354 ASET (entity, FONT_SLANT_INDEX, make_number (numeric + 100)); | |
355 if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch) | |
356 ASET (entity, FONT_WIDTH_INDEX, make_number (numeric)); | |
357 if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch) | |
358 ASET (entity, FONT_SIZE_INDEX, make_number (dbl)); | |
359 else | |
360 ASET (entity, FONT_SIZE_INDEX, make_number (0)); | |
361 | |
362 if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) != FcResultMatch) | |
363 numeric = FC_MONO; | |
364 p0 = FcPatternCreate (); | |
365 if (! p0 | |
366 || FcPatternAddString (p0, FC_FILE, file) == FcFalse | |
367 || FcPatternAddCharSet (p0, FC_CHARSET, charset) == FcFalse | |
368 || FcPatternAddInteger (p0, FC_SPACING, numeric) == FcFalse) | |
369 break; | |
370 ASET (entity, FONT_EXTRA_INDEX, make_save_value (p0, 0)); | |
371 | |
372 val = Fcons (entity, val); | |
373 } | |
374 } | |
375 val = Fvconcat (1, &val); | |
376 goto finish; | |
377 | |
378 err: | |
379 /* We come here because of unexpected error in fontconfig API call | |
380 (usually insufficiency memory). */ | |
381 val = Qnil; | |
382 | |
383 finish: | |
384 if (charset && charset != cs_iso8859_1) FcCharSetDestroy (charset); | |
385 if (objset) FcObjectSetDestroy (objset); | |
386 if (fontset) FcFontSetDestroy (fontset); | |
387 if (langset) FcLangSetDestroy (langset); | |
388 if (pattern) FcPatternDestroy (pattern); | |
389 | |
390 return val; | |
391 } | |
392 | |
393 static Lisp_Object | |
394 ftfont_list_family (frame) | |
395 Lisp_Object frame; | |
396 { | |
397 Lisp_Object list; | |
398 FcPattern *pattern = NULL; | |
399 FcFontSet *fontset = NULL; | |
400 FcObjectSet *objset = NULL; | |
401 int i; | |
402 | |
403 if (! fc_initialized) | |
404 { | |
405 FcInit (); | |
406 fc_initialized = 1; | |
407 } | |
408 | |
409 pattern = FcPatternCreate (); | |
410 if (! pattern) | |
411 goto finish; | |
412 objset = FcObjectSetBuild (FC_FAMILY); | |
413 if (! objset) | |
414 goto finish; | |
415 fontset = FcFontList (NULL, pattern, objset); | |
416 if (! fontset) | |
417 goto finish; | |
418 | |
419 list = Qnil; | |
420 for (i = 0; i < fontset->nfont; i++) | |
421 { | |
422 FcPattern *pat = fontset->fonts[i]; | |
423 FcChar8 *str; | |
424 | |
425 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch) | |
426 list = Fcons (intern_downcase ((char *) str, strlen ((char *) str)), | |
427 list); | |
428 } | |
429 | |
430 finish: | |
431 if (objset) FcObjectSetDestroy (objset); | |
432 if (fontset) FcFontSetDestroy (fontset); | |
433 if (pattern) FcPatternDestroy (pattern); | |
434 | |
435 return list; | |
436 } | |
437 | |
438 | |
439 static void | |
440 ftfont_free_entity (entity) | |
441 Lisp_Object entity; | |
442 { | |
443 Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX); | |
444 FcPattern *pattern = XSAVE_VALUE (val)->pointer; | |
445 | |
446 FcPatternDestroy (pattern); | |
447 } | |
448 | |
449 static struct font * | |
450 ftfont_open (f, entity, pixel_size) | |
451 FRAME_PTR f; | |
452 Lisp_Object entity; | |
453 int pixel_size; | |
454 { | |
455 struct ftfont_info *ftfont_info; | |
456 struct font *font; | |
457 FT_Face ft_face; | |
458 FT_Size ft_size; | |
459 FT_UInt size; | |
460 Lisp_Object val; | |
461 FcPattern *pattern; | |
462 FcChar8 *file; | |
463 int spacing; | |
464 | |
465 val = AREF (entity, FONT_EXTRA_INDEX); | |
466 if (XTYPE (val) != Lisp_Misc | |
467 || XMISCTYPE (val) != Lisp_Misc_Save_Value) | |
468 return NULL; | |
469 pattern = XSAVE_VALUE (val)->pointer; | |
470 if (XSAVE_VALUE (val)->integer == 0) | |
471 { | |
472 /* We have not yet created FT_Face for this font. */ | |
473 if (! ft_library | |
474 && FT_Init_FreeType (&ft_library) != 0) | |
475 return NULL; | |
476 if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch) | |
477 return NULL; | |
478 if (FT_New_Face (ft_library, (char *) file, 0, &ft_face) != 0) | |
479 return NULL; | |
480 FcPatternAddFTFace (pattern, FC_FT_FACE, ft_face); | |
481 ft_size = ft_face->size; | |
482 } | |
483 else | |
484 { | |
485 if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face) | |
486 != FcResultMatch) | |
487 return NULL; | |
488 if (FT_New_Size (ft_face, &ft_size) != 0) | |
489 return NULL; | |
490 if (FT_Activate_Size (ft_size) != 0) | |
491 { | |
492 FT_Done_Size (ft_size); | |
493 return NULL; | |
494 } | |
495 } | |
496 | |
497 size = XINT (AREF (entity, FONT_SIZE_INDEX)); | |
498 if (size == 0) | |
499 size = pixel_size; | |
500 if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0) | |
501 { | |
502 if (XSAVE_VALUE (val)->integer == 0) | |
503 FT_Done_Face (ft_face); | |
504 return NULL; | |
505 } | |
506 | |
507 ftfont_info = malloc (sizeof (struct ftfont_info)); | |
508 if (! ftfont_info) | |
509 return NULL; | |
510 ftfont_info->ft_size = ft_size; | |
511 | |
512 font = (struct font *) ftfont_info; | |
513 font->entity = entity; | |
514 font->pixel_size = size; | |
515 font->driver = &ftfont_driver; | |
516 font->font.name = font->font.full_name = NULL; | |
517 font->file_name = (char *) file; | |
518 font->font.size = ft_face->size->metrics.max_advance >> 6; | |
519 font->ascent = ft_face->size->metrics.ascender >> 6; | |
520 font->descent = - ft_face->size->metrics.descender >> 6; | |
521 font->font.height = ft_face->size->metrics.height >> 6; | |
522 if (FcPatternGetInteger (pattern, FC_SPACING, 0, &spacing) != FcResultMatch | |
523 || spacing != FC_PROPORTIONAL) | |
524 font->font.average_width = font->font.space_width = font->font.size; | |
525 else | |
526 { | |
527 int i; | |
528 | |
529 for (i = 32; i < 127; i++) | |
530 { | |
531 if (FT_Load_Char (ft_face, i, FT_LOAD_DEFAULT) != 0) | |
532 break; | |
533 if (i == 32) | |
534 font->font.space_width = ft_face->glyph->metrics.horiAdvance >> 6; | |
535 font->font.average_width += ft_face->glyph->metrics.horiAdvance >> 6; | |
536 } | |
537 if (i == 127) | |
538 { | |
539 /* The font contains all ASCII printable characters. */ | |
540 font->font.average_width /= 95; | |
541 } | |
542 else | |
543 { | |
544 if (i == 32) | |
545 font->font.space_width = font->font.size; | |
546 font->font.average_width = font->font.size; | |
547 } | |
548 } | |
549 | |
550 font->font.baseline_offset = 0; | |
551 font->font.relative_compose = 0; | |
552 font->font.default_ascent = 0; | |
553 font->font.vertical_centering = 0; | |
554 | |
555 (XSAVE_VALUE (val)->integer)++; | |
556 | |
557 return font; | |
558 } | |
559 | |
560 static void | |
561 ftfont_close (f, font) | |
562 FRAME_PTR f; | |
563 struct font *font; | |
564 { | |
565 struct ftfont_info *ftfont_info = (struct ftfont_info *) font; | |
566 Lisp_Object entity = font->entity; | |
567 Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX); | |
568 | |
569 (XSAVE_VALUE (val)->integer)--; | |
570 if (XSAVE_VALUE (val)->integer == 0) | |
571 FT_Done_Face (ftfont_info->ft_size->face); | |
572 else | |
573 FT_Done_Size (ftfont_info->ft_size); | |
574 | |
575 free (font); | |
576 } | |
577 | |
578 static int | |
579 ftfont_has_char (entity, c) | |
580 Lisp_Object entity; | |
581 int c; | |
582 { | |
583 Lisp_Object val; | |
584 FcPattern *pattern; | |
585 FcCharSet *charset; | |
586 | |
587 val = AREF (entity, FONT_EXTRA_INDEX); | |
588 pattern = XSAVE_VALUE (val)->pointer; | |
589 FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset); | |
590 | |
591 return (FcCharSetHasChar (charset, (FcChar32) c) == FcTrue); | |
592 } | |
593 | |
594 static unsigned | |
595 ftfont_encode_char (font, c) | |
596 struct font *font; | |
597 int c; | |
598 { | |
599 struct ftfont_info *ftfont_info = (struct ftfont_info *) font; | |
600 FT_Face ft_face = ftfont_info->ft_size->face; | |
601 FT_ULong charcode = c; | |
602 FT_UInt code = FT_Get_Char_Index (ft_face, charcode); | |
603 | |
604 return (code > 0 ? code : 0xFFFFFFFF); | |
605 } | |
606 | |
607 static int | |
608 ftfont_text_extents (font, code, nglyphs, metrics) | |
609 struct font *font; | |
610 unsigned *code; | |
611 int nglyphs; | |
612 struct font_metrics *metrics; | |
613 { | |
614 struct ftfont_info *ftfont_info = (struct ftfont_info *) font; | |
615 FT_Face ft_face = ftfont_info->ft_size->face; | |
616 int width = 0; | |
617 int i; | |
618 | |
619 if (ftfont_info->ft_size != ft_face->size) | |
620 FT_Activate_Size (ftfont_info->ft_size); | |
621 if (metrics) | |
622 bzero (metrics, sizeof (struct font_metrics)); | |
623 for (i = 0; i < nglyphs; i++) | |
624 { | |
625 if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0) | |
626 { | |
627 FT_Glyph_Metrics *m = &ft_face->glyph->metrics; | |
628 | |
629 if (metrics) | |
630 { | |
631 if (metrics->lbearing > width + (m->horiBearingX >> 6)) | |
632 metrics->lbearing = width + (m->horiBearingX >> 6); | |
633 if (metrics->rbearing | |
634 < width + ((m->horiBearingX + m->width) >> 6)) | |
635 metrics->rbearing | |
636 = width + ((m->horiBearingX + m->width) >> 6); | |
637 if (metrics->ascent < (m->horiBearingY >> 6)) | |
638 metrics->ascent = m->horiBearingY >> 6; | |
639 if (metrics->descent > ((m->horiBearingY + m->height) >> 6)) | |
640 metrics->descent = (m->horiBearingY + m->height) >> 6; | |
641 } | |
642 width += m->horiAdvance >> 6; | |
643 } | |
644 else | |
645 { | |
646 width += font->font.space_width; | |
647 } | |
648 } | |
649 if (metrics) | |
650 metrics->width = width; | |
651 | |
652 return width; | |
653 } | |
654 | |
655 static int | |
656 ftfont_get_bitmap (font, code, bitmap, bits_per_pixel) | |
657 struct font *font; | |
658 unsigned code; | |
659 struct font_bitmap *bitmap; | |
660 int bits_per_pixel; | |
661 { | |
662 struct ftfont_info *ftfont_info = (struct ftfont_info *) font; | |
663 FT_Face ft_face = ftfont_info->ft_size->face; | |
664 FT_Int32 load_flags = FT_LOAD_RENDER; | |
665 | |
666 if (ftfont_info->ft_size != ft_face->size) | |
667 FT_Activate_Size (ftfont_info->ft_size); | |
668 if (bits_per_pixel == 1) | |
669 { | |
670 #ifdef FT_LOAD_TARGET_MONO | |
671 load_flags |= FT_LOAD_TARGET_MONO; | |
672 #else | |
673 load_flags |= FT_LOAD_MONOCHROME; | |
674 #endif | |
675 } | |
676 else if (bits_per_pixel != 8) | |
677 /* We don't support such a rendering. */ | |
678 return -1; | |
679 | |
680 if (FT_Load_Glyph (ft_face, code, load_flags) != 0) | |
681 return -1; | |
682 bitmap->rows = ft_face->glyph->bitmap.rows; | |
683 bitmap->width = ft_face->glyph->bitmap.width; | |
684 bitmap->pitch = ft_face->glyph->bitmap.pitch; | |
685 bitmap->buffer = ft_face->glyph->bitmap.buffer; | |
686 bitmap->left = ft_face->glyph->bitmap_left; | |
687 bitmap->top = ft_face->glyph->bitmap_top; | |
688 bitmap->advance = ft_face->glyph->metrics.horiAdvance >> 6; | |
689 bitmap->extra = NULL; | |
690 | |
691 return 0; | |
692 } | |
693 | |
694 static int | |
695 ftfont_anchor_point (font, code, index, x, y) | |
696 struct font *font; | |
697 unsigned code; | |
698 int index; | |
699 int *x, *y; | |
700 { | |
701 struct ftfont_info *ftfont_info = (struct ftfont_info *) font; | |
702 FT_Face ft_face = ftfont_info->ft_size->face; | |
703 | |
704 if (ftfont_info->ft_size != ft_face->size) | |
705 FT_Activate_Size (ftfont_info->ft_size); | |
706 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0) | |
707 return -1; | |
708 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) | |
709 return -1; | |
710 if (index >= ft_face->glyph->outline.n_points) | |
711 return -1; | |
712 *x = ft_face->glyph->outline.points[index].x; | |
713 *y = ft_face->glyph->outline.points[index].y; | |
714 return 0; | |
715 } | |
716 | |
717 | |
718 void | |
719 syms_of_ftfont () | |
720 { | |
721 staticpro (&freetype_font_cache); | |
722 freetype_font_cache = Qnil; | |
723 | |
724 DEFSYM (Qfreetype, "freetype"); | |
725 DEFSYM (Qiso8859_1, "iso8859-1"); | |
726 DEFSYM (Qiso10646_1, "iso10646-1"); | |
727 DEFSYM (Qunicode_bmp, "unicode-bmp"); | |
728 | |
729 ftfont_driver.type = Qfreetype; | |
730 register_font_driver (&ftfont_driver, NULL); | |
731 } |