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