1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
3 Copyright (C) 2006, 2007, 2008, 2009, 2010
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
7 This file is part of GNU Emacs.
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 3 of the License, or
12 (at your option) any later version.
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.
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
26 #include <fontconfig/fontconfig.h>
27 #include <fontconfig/fcfreetype.h>
30 #include "dispextern.h"
32 #include "blockinput.h"
33 #include "character.h"
36 #include "composite.h"
41 /* Symbolic type of this font-driver. */
42 Lisp_Object Qfreetype
;
44 /* Fontconfig's generic families and their aliases. */
45 static Lisp_Object Qmonospace
, Qsans_serif
, Qserif
, Qmono
, Qsans
, Qsans__serif
;
47 /* Flag to tell if FcInit is already called or not. */
48 static int fc_initialized
;
50 /* Handle to a FreeType library instance. */
51 static FT_Library ft_library
;
53 /* Cache for FreeType fonts. */
54 static Lisp_Object freetype_font_cache
;
56 /* Cache for FT_Face and FcCharSet. */
57 static Lisp_Object ft_face_cache
;
59 /* The actual structure for FreeType font that can be casted to struct
66 /* The following four members must be here in this order to be
67 compatible with struct xftfont_info (in xftfont.c). */
68 int maybe_otf
; /* Flag to tell if this may be OTF or not. */
70 #endif /* HAVE_LIBOTF */
78 FTFONT_CACHE_FOR_FACE
,
79 FTFONT_CACHE_FOR_CHARSET
,
80 FTFONT_CACHE_FOR_ENTITY
83 static Lisp_Object
ftfont_pattern_entity (FcPattern
*, Lisp_Object
);
85 static Lisp_Object
ftfont_resolve_generic_family (Lisp_Object
,
87 static Lisp_Object
ftfont_lookup_cache (Lisp_Object
,
88 enum ftfont_cache_for
);
90 static void ftfont_filter_properties (Lisp_Object font
, Lisp_Object alist
);
92 Lisp_Object
ftfont_font_format (FcPattern
*, Lisp_Object
);
94 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
100 /* characters to distinguish the charset from the others */
102 /* additional constraint by language */
105 FcCharSet
*fc_charset
;
106 } fc_charset_table
[] =
107 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
108 { "iso8859-2", { 0x00A0, 0x010E }},
109 { "iso8859-3", { 0x00A0, 0x0108 }},
110 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
111 { "iso8859-5", { 0x00A0, 0x0401 }},
112 { "iso8859-6", { 0x00A0, 0x060C }},
113 { "iso8859-7", { 0x00A0, 0x0384 }},
114 { "iso8859-8", { 0x00A0, 0x05D0 }},
115 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
116 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
117 { "iso8859-11", { 0x00A0, 0x0E01 }},
118 { "iso8859-13", { 0x00A0, 0x201C }},
119 { "iso8859-14", { 0x00A0, 0x0174 }},
120 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
121 { "iso8859-16", { 0x00A0, 0x0218}},
122 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
123 { "big5-0", { 0xF6B1 }, "zh-tw" },
124 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
125 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
126 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
127 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
128 { "cns11643.1992-3", { 0x201A9 }},
129 { "cns11643.1992-4", { 0x20057 }},
130 { "cns11643.1992-5", { 0x20000 }},
131 { "cns11643.1992-6", { 0x20003 }},
132 { "cns11643.1992-7", { 0x20055 }},
133 { "gbk-0", { 0x4E06 }, "zh-cn"},
134 { "jisx0212.1990-0", { 0x4E44 }},
135 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
136 { "jisx0213.2000-2", { 0xFA49 }},
137 { "jisx0213.2004-1", { 0x20B9F }},
138 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
139 { "tis620.2529-1", { 0x0E01 }, "th"},
140 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
141 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
142 { "mulelao-1", { 0x0E81 }, "lo"},
143 { "unicode-sip", { 0x20000 }},
147 /* Dirty hack for handing ADSTYLE property.
149 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
150 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
151 "Oblique", "Italic", or any non-normal SWIDTH property names
152 (e.g. SemiCondensed) are appended. In addition, if there's no
153 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
154 "Regular" is used for FC_STYLE (see the function
155 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
157 Unfortunately this behavior is not documented, so the following
158 code may fail if FreeType changes the behavior in the future. */
161 get_adstyle_property (FcPattern
*p
)
166 if (FcPatternGetString (p
, FC_STYLE
, 0, (FcChar8
**) &str
) != FcResultMatch
)
168 for (end
= str
; *end
&& *end
!= ' '; end
++);
171 char *p
= alloca (end
- str
+ 1);
172 memcpy (p
, str
, end
- str
);
174 end
= p
+ (end
- str
);
177 if (xstrcasecmp (str
, "Regular") == 0
178 || xstrcasecmp (str
, "Bold") == 0
179 || xstrcasecmp (str
, "Oblique") == 0
180 || xstrcasecmp (str
, "Italic") == 0)
182 adstyle
= font_intern_prop (str
, end
- str
, 1);
183 if (font_style_to_value (FONT_WIDTH_INDEX
, adstyle
, 0) >= 0)
189 ftfont_pattern_entity (FcPattern
*p
, Lisp_Object extra
)
191 Lisp_Object key
, cache
, entity
;
198 if (FcPatternGetString (p
, FC_FILE
, 0, (FcChar8
**) &file
) != FcResultMatch
)
200 if (FcPatternGetInteger (p
, FC_INDEX
, 0, &index
) != FcResultMatch
)
203 key
= Fcons (make_unibyte_string ((char *) file
, strlen ((char *) file
)),
204 make_number (index
));
205 cache
= ftfont_lookup_cache (key
, FTFONT_CACHE_FOR_ENTITY
);
206 entity
= XCAR (cache
);
209 Lisp_Object val
= font_make_entity ();
212 for (i
= 0; i
< FONT_OBJLIST_INDEX
; i
++)
213 ASET (val
, i
, AREF (entity
, i
));
216 entity
= font_make_entity ();
217 XSETCAR (cache
, entity
);
219 ASET (entity
, FONT_TYPE_INDEX
, Qfreetype
);
220 ASET (entity
, FONT_REGISTRY_INDEX
, Qiso10646_1
);
222 if (FcPatternGetString (p
, FC_FOUNDRY
, 0, (FcChar8
**) &str
) == FcResultMatch
)
223 ASET (entity
, FONT_FOUNDRY_INDEX
, font_intern_prop (str
, strlen (str
), 1));
224 if (FcPatternGetString (p
, FC_FAMILY
, 0, (FcChar8
**) &str
) == FcResultMatch
)
225 ASET (entity
, FONT_FAMILY_INDEX
, font_intern_prop (str
, strlen (str
), 1));
226 if (FcPatternGetInteger (p
, FC_WEIGHT
, 0, &numeric
) == FcResultMatch
)
228 if (numeric
>= FC_WEIGHT_REGULAR
&& numeric
< FC_WEIGHT_MEDIUM
)
229 numeric
= FC_WEIGHT_MEDIUM
;
230 FONT_SET_STYLE (entity
, FONT_WEIGHT_INDEX
, make_number (numeric
));
232 if (FcPatternGetInteger (p
, FC_SLANT
, 0, &numeric
) == FcResultMatch
)
235 FONT_SET_STYLE (entity
, FONT_SLANT_INDEX
, make_number (numeric
));
237 if (FcPatternGetInteger (p
, FC_WIDTH
, 0, &numeric
) == FcResultMatch
)
239 FONT_SET_STYLE (entity
, FONT_WIDTH_INDEX
, make_number (numeric
));
241 if (FcPatternGetDouble (p
, FC_PIXEL_SIZE
, 0, &dbl
) == FcResultMatch
)
243 ASET (entity
, FONT_SIZE_INDEX
, make_number (dbl
));
246 ASET (entity
, FONT_SIZE_INDEX
, make_number (0));
247 if (FcPatternGetInteger (p
, FC_SPACING
, 0, &numeric
) == FcResultMatch
)
248 ASET (entity
, FONT_SPACING_INDEX
, make_number (numeric
));
249 if (FcPatternGetDouble (p
, FC_DPI
, 0, &dbl
) == FcResultMatch
)
252 ASET (entity
, FONT_DPI_INDEX
, make_number (dpi
));
254 if (FcPatternGetBool (p
, FC_SCALABLE
, 0, &b
) == FcResultMatch
257 ASET (entity
, FONT_SIZE_INDEX
, make_number (0));
258 ASET (entity
, FONT_AVGWIDTH_INDEX
, make_number (0));
262 /* As this font is not scalable, parhaps this is a BDF or PCF
266 ASET (entity
, FONT_ADSTYLE_INDEX
, get_adstyle_property (p
));
267 if ((ft_library
|| FT_Init_FreeType (&ft_library
) == 0)
268 && FT_New_Face (ft_library
, file
, index
, &ft_face
) == 0)
272 if (FT_Get_BDF_Property (ft_face
, "AVERAGE_WIDTH", &rec
) == 0
273 && rec
.type
== BDF_PROPERTY_TYPE_INTEGER
)
274 ASET (entity
, FONT_AVGWIDTH_INDEX
, make_number (rec
.u
.integer
));
275 FT_Done_Face (ft_face
);
279 ASET (entity
, FONT_EXTRA_INDEX
, Fcopy_sequence (extra
));
280 font_put_extra (entity
, QCfont_entity
, key
);
285 static Lisp_Object ftfont_generic_family_list
;
288 ftfont_resolve_generic_family (Lisp_Object family
, FcPattern
*pattern
)
295 family
= Fintern (Fdowncase (SYMBOL_NAME (family
)), Qnil
);
296 if (EQ (family
, Qmono
))
298 else if (EQ (family
, Qsans
) || EQ (family
, Qsans__serif
))
299 family
= Qsans_serif
;
300 slot
= assq_no_quit (family
, ftfont_generic_family_list
);
303 if (! EQ (XCDR (slot
), Qt
))
305 pattern
= FcPatternDuplicate (pattern
);
308 FcPatternDel (pattern
, FC_FOUNDRY
);
309 FcPatternDel (pattern
, FC_FAMILY
);
310 FcPatternAddString (pattern
, FC_FAMILY
, SYMBOL_FcChar8 (family
));
311 if (FcPatternGetLangSet (pattern
, FC_LANG
, 0, &langset
) != FcResultMatch
)
313 /* This is to avoid the effect of locale. */
314 langset
= FcLangSetCreate ();
315 FcLangSetAdd (langset
, "en");
316 FcPatternAddLangSet (pattern
, FC_LANG
, langset
);
317 FcLangSetDestroy (langset
);
319 FcConfigSubstitute (NULL
, pattern
, FcMatchPattern
);
320 FcDefaultSubstitute (pattern
);
321 match
= FcFontMatch (NULL
, pattern
, &result
);
326 if (FcPatternGetString (match
, FC_FAMILY
, 0, &fam
) == FcResultMatch
)
327 family
= intern ((char *) fam
);
331 XSETCDR (slot
, family
);
332 if (match
) FcPatternDestroy (match
);
334 if (pattern
) FcPatternDestroy (pattern
);
338 struct ftfont_cache_data
341 FcCharSet
*fc_charset
;
345 ftfont_lookup_cache (Lisp_Object key
, enum ftfont_cache_for cache_for
)
347 Lisp_Object cache
, val
, entity
;
348 struct ftfont_cache_data
*cache_data
;
350 if (FONT_ENTITY_P (key
))
353 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
354 xassert (CONSP (val
));
360 if (NILP (ft_face_cache
))
363 cache
= Fgethash (key
, ft_face_cache
, Qnil
);
366 if (NILP (ft_face_cache
))
372 ft_face_cache
= Fmake_hash_table (2, args
);
374 cache_data
= xmalloc (sizeof (struct ftfont_cache_data
));
375 cache_data
->ft_face
= NULL
;
376 cache_data
->fc_charset
= NULL
;
377 val
= make_save_value (NULL
, 0);
378 XSAVE_VALUE (val
)->integer
= 0;
379 XSAVE_VALUE (val
)->pointer
= cache_data
;
380 cache
= Fcons (Qnil
, val
);
381 Fputhash (key
, cache
, ft_face_cache
);
386 cache_data
= XSAVE_VALUE (val
)->pointer
;
389 if (cache_for
== FTFONT_CACHE_FOR_ENTITY
)
392 if (cache_for
== FTFONT_CACHE_FOR_FACE
393 ? ! cache_data
->ft_face
: ! cache_data
->fc_charset
)
395 char *filename
= (char *) SDATA (XCAR (key
));
396 int index
= XINT (XCDR (key
));
398 if (cache_for
== FTFONT_CACHE_FOR_FACE
)
401 && FT_Init_FreeType (&ft_library
) != 0)
403 if (FT_New_Face (ft_library
, filename
, index
, &cache_data
->ft_face
)
409 FcPattern
*pat
= NULL
;
410 FcFontSet
*fontset
= NULL
;
411 FcObjectSet
*objset
= NULL
;
412 FcCharSet
*charset
= NULL
;
414 pat
= FcPatternBuild (0, FC_FILE
, FcTypeString
, (FcChar8
*) filename
,
415 FC_INDEX
, FcTypeInteger
, index
, NULL
);
418 objset
= FcObjectSetBuild (FC_CHARSET
, FC_STYLE
, NULL
);
421 fontset
= FcFontList (NULL
, pat
, objset
);
424 if (fontset
&& fontset
->nfont
> 0
425 && (FcPatternGetCharSet (fontset
->fonts
[0], FC_CHARSET
, 0,
428 cache_data
->fc_charset
= FcCharSetCopy (charset
);
430 cache_data
->fc_charset
= FcCharSetCreate ();
434 FcFontSetDestroy (fontset
);
436 FcObjectSetDestroy (objset
);
438 FcPatternDestroy (pat
);
445 ftfont_get_fc_charset (Lisp_Object entity
)
447 Lisp_Object val
, cache
;
448 struct ftfont_cache_data
*cache_data
;
450 cache
= ftfont_lookup_cache (entity
, FTFONT_CACHE_FOR_CHARSET
);
452 cache_data
= XSAVE_VALUE (val
)->pointer
;
453 return cache_data
->fc_charset
;
458 ftfont_get_otf (struct ftfont_info
*ftfont_info
)
462 if (ftfont_info
->otf
)
463 return ftfont_info
->otf
;
464 if (! ftfont_info
->maybe_otf
)
466 otf
= OTF_open_ft_face (ftfont_info
->ft_size
->face
);
467 if (! otf
|| OTF_get_table (otf
, "head") < 0)
471 ftfont_info
->maybe_otf
= 0;
474 ftfont_info
->otf
= otf
;
477 #endif /* HAVE_LIBOTF */
479 static Lisp_Object
ftfont_get_cache (FRAME_PTR
);
480 static Lisp_Object
ftfont_list (Lisp_Object
, Lisp_Object
);
481 static Lisp_Object
ftfont_match (Lisp_Object
, Lisp_Object
);
482 static Lisp_Object
ftfont_list_family (Lisp_Object
);
483 static Lisp_Object
ftfont_open (FRAME_PTR
, Lisp_Object
, int);
484 static void ftfont_close (FRAME_PTR
, struct font
*);
485 static int ftfont_has_char (Lisp_Object
, int);
486 static unsigned ftfont_encode_char (struct font
*, int);
487 static int ftfont_text_extents (struct font
*, unsigned *, int,
488 struct font_metrics
*);
489 static int ftfont_get_bitmap (struct font
*, unsigned,
490 struct font_bitmap
*, int);
491 static int ftfont_anchor_point (struct font
*, unsigned, int,
493 static Lisp_Object
ftfont_otf_capability (struct font
*);
494 static Lisp_Object
ftfont_shape (Lisp_Object
);
496 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
497 static int ftfont_variation_glyphs (struct font
*, int c
,
498 unsigned variations
[256]);
499 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
501 struct font_driver ftfont_driver
=
504 0, /* case insensitive */
509 NULL
, /* free_entity */
512 /* We can't draw a text without device dependent functions. */
513 NULL
, /* prepare_face */
514 NULL
, /* done_face */
518 /* We can't draw a text without device dependent functions. */
521 NULL
, /* get_bitmap */
522 NULL
, /* free_bitmap */
523 NULL
, /* get_outline */
526 ftfont_otf_capability
,
527 #else /* not HAVE_LIBOTF */
529 #endif /* not HAVE_LIBOTF */
530 NULL
, /* otf_drive */
531 NULL
, /* start_for_frame */
532 NULL
, /* end_for_frame */
533 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
535 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
537 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
540 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
541 ftfont_variation_glyphs
,
546 ftfont_filter_properties
, /* filter_properties */
550 ftfont_get_cache (FRAME_PTR f
)
552 return freetype_font_cache
;
556 ftfont_get_charset (Lisp_Object registry
)
558 char *str
= (char *) SDATA (SYMBOL_NAME (registry
));
559 char *re
= alloca (SBYTES (SYMBOL_NAME (registry
)) * 2 + 1);
563 for (i
= j
= 0; i
< SBYTES (SYMBOL_NAME (registry
)); i
++, j
++)
567 else if (str
[i
] == '*')
574 regexp
= make_unibyte_string (re
, j
);
575 for (i
= 0; fc_charset_table
[i
].name
; i
++)
576 if (fast_c_string_match_ignore_case (regexp
, fc_charset_table
[i
].name
) >= 0)
578 if (! fc_charset_table
[i
].name
)
580 if (! fc_charset_table
[i
].fc_charset
)
582 FcCharSet
*charset
= FcCharSetCreate ();
583 int *uniquifier
= fc_charset_table
[i
].uniquifier
;
587 for (j
= 0; uniquifier
[j
]; j
++)
588 if (! FcCharSetAddChar (charset
, uniquifier
[j
]))
590 FcCharSetDestroy (charset
);
593 fc_charset_table
[i
].fc_charset
= charset
;
601 unsigned int script_tag
, langsys_tag
;
603 unsigned int *features
[2];
606 #define OTF_SYM_TAG(SYM, TAG) \
608 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
609 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
612 #define OTF_TAG_STR(TAG, P) \
614 (P)[0] = (char) (TAG >> 24); \
615 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
616 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
617 (P)[3] = (char) (TAG & 0xFF); \
621 #define OTF_TAG_SYM(SYM, TAG) \
625 OTF_TAG_STR (TAG, str); \
626 (SYM) = font_intern_prop (str, 4, 1); \
630 static struct OpenTypeSpec
*
631 ftfont_get_open_type_spec (Lisp_Object otf_spec
)
633 struct OpenTypeSpec
*spec
= malloc (sizeof (struct OpenTypeSpec
));
639 spec
->script
= XCAR (otf_spec
);
640 if (! NILP (spec
->script
))
642 OTF_SYM_TAG (spec
->script
, spec
->script_tag
);
643 val
= assq_no_quit (spec
->script
, Votf_script_alist
);
644 if (CONSP (val
) && SYMBOLP (XCDR (val
)))
645 spec
->script
= XCDR (val
);
650 spec
->script_tag
= 0x44464C54; /* "DFLT" */
651 otf_spec
= XCDR (otf_spec
);
652 spec
->langsys_tag
= 0;
653 if (! NILP (otf_spec
))
655 val
= XCAR (otf_spec
);
657 OTF_SYM_TAG (val
, spec
->langsys_tag
);
658 otf_spec
= XCDR (otf_spec
);
660 spec
->nfeatures
[0] = spec
->nfeatures
[1] = 0;
661 for (i
= 0; i
< 2 && ! NILP (otf_spec
); i
++, otf_spec
= XCDR (otf_spec
))
665 val
= XCAR (otf_spec
);
669 spec
->features
[i
] = malloc (sizeof (int) * XINT (len
));
670 if (! spec
->features
[i
])
672 if (i
> 0 && spec
->features
[0])
673 free (spec
->features
[0]);
677 for (j
= 0, negative
= 0; CONSP (val
); val
= XCDR (val
))
679 if (NILP (XCAR (val
)))
685 OTF_SYM_TAG (XCAR (val
), tag
);
686 spec
->features
[i
][j
++] = negative
? tag
& 0x80000000 : tag
;
689 spec
->nfeatures
[i
] = j
;
694 static FcPattern
*ftfont_spec_pattern (Lisp_Object
, char *,
695 struct OpenTypeSpec
**,
699 ftfont_spec_pattern (Lisp_Object spec
, char *otlayout
, struct OpenTypeSpec
**otspec
, char **langname
)
701 Lisp_Object tmp
, extra
;
702 FcPattern
*pattern
= NULL
;
703 FcCharSet
*charset
= NULL
;
704 FcLangSet
*langset
= NULL
;
708 Lisp_Object script
= Qnil
;
709 Lisp_Object registry
;
712 if ((n
= FONT_SLANT_NUMERIC (spec
)) >= 0
714 /* Fontconfig doesn't support reverse-italic/obligue. */
717 if (INTEGERP (AREF (spec
, FONT_DPI_INDEX
)))
718 dpi
= XINT (AREF (spec
, FONT_DPI_INDEX
));
719 if (INTEGERP (AREF (spec
, FONT_AVGWIDTH_INDEX
))
720 && XINT (AREF (spec
, FONT_AVGWIDTH_INDEX
)) == 0)
723 registry
= AREF (spec
, FONT_REGISTRY_INDEX
);
725 || EQ (registry
, Qascii_0
)
726 || EQ (registry
, Qiso10646_1
)
727 || EQ (registry
, Qunicode_bmp
))
733 fc_charset_idx
= ftfont_get_charset (registry
);
734 if (fc_charset_idx
< 0)
736 charset
= fc_charset_table
[fc_charset_idx
].fc_charset
;
737 *langname
= fc_charset_table
[fc_charset_idx
].lang
;
738 lang
= (FcChar8
*) *langname
;
741 langset
= FcLangSetCreate ();
744 FcLangSetAdd (langset
, lang
);
749 for (extra
= AREF (spec
, FONT_EXTRA_INDEX
);
750 CONSP (extra
); extra
= XCDR (extra
))
752 Lisp_Object key
, val
;
754 key
= XCAR (XCAR (extra
)), val
= XCDR (XCAR (extra
));
757 else if (EQ (key
, QClang
))
760 langset
= FcLangSetCreate ();
765 if (! FcLangSetAdd (langset
, SYMBOL_FcChar8 (val
)))
769 for (; CONSP (val
); val
= XCDR (val
))
770 if (SYMBOLP (XCAR (val
))
771 && ! FcLangSetAdd (langset
, SYMBOL_FcChar8 (XCAR (val
))))
774 else if (EQ (key
, QCotf
))
776 *otspec
= ftfont_get_open_type_spec (val
);
779 strcat (otlayout
, "otlayout:");
780 OTF_TAG_STR ((*otspec
)->script_tag
, otlayout
+ 9);
781 script
= (*otspec
)->script
;
783 else if (EQ (key
, QCscript
))
785 else if (EQ (key
, QCscalable
))
786 scalable
= ! NILP (val
);
789 if (! NILP (script
) && ! charset
)
791 Lisp_Object chars
= assq_no_quit (script
, Vscript_representative_chars
);
793 if (CONSP (chars
) && CONSP (CDR (chars
)))
795 charset
= FcCharSetCreate ();
798 for (chars
= XCDR (chars
); CONSP (chars
); chars
= XCDR (chars
))
799 if (CHARACTERP (XCAR (chars
))
800 && ! FcCharSetAddChar (charset
, XUINT (XCAR (chars
))))
805 pattern
= FcPatternCreate ();
808 tmp
= AREF (spec
, FONT_FOUNDRY_INDEX
);
810 && ! FcPatternAddString (pattern
, FC_FOUNDRY
, SYMBOL_FcChar8 (tmp
)))
812 tmp
= AREF (spec
, FONT_FAMILY_INDEX
);
814 && ! FcPatternAddString (pattern
, FC_FAMILY
, SYMBOL_FcChar8 (tmp
)))
817 && ! FcPatternAddCharSet (pattern
, FC_CHARSET
, charset
))
820 && ! FcPatternAddLangSet (pattern
, FC_LANG
, langset
))
823 && ! FcPatternAddDouble (pattern
, FC_DPI
, dpi
))
826 && ! FcPatternAddBool (pattern
, FC_SCALABLE
, scalable
? FcTrue
: FcFalse
))
832 /* We come here because of unexpected error in fontconfig API call
833 (usually insufficient memory). */
836 FcPatternDestroy (pattern
);
841 if ((*otspec
)->nfeatures
[0] > 0)
842 free ((*otspec
)->features
[0]);
843 if ((*otspec
)->nfeatures
[1] > 0)
844 free ((*otspec
)->features
[1]);
850 if (langset
) FcLangSetDestroy (langset
);
851 if (charset
&& fc_charset_idx
< 0) FcCharSetDestroy (charset
);
856 ftfont_list (Lisp_Object frame
, Lisp_Object spec
)
858 Lisp_Object val
= Qnil
, family
, adstyle
;
861 FcFontSet
*fontset
= NULL
;
862 FcObjectSet
*objset
= NULL
;
864 Lisp_Object chars
= Qnil
;
866 char otlayout
[15]; /* For "otlayout:XXXX" */
867 struct OpenTypeSpec
*otspec
= NULL
;
869 char *langname
= NULL
;
871 if (! fc_initialized
)
877 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
880 if (FcPatternGetCharSet (pattern
, FC_CHARSET
, 0, &charset
) != FcResultMatch
)
882 val
= assq_no_quit (QCscript
, AREF (spec
, FONT_EXTRA_INDEX
));
885 val
= assq_no_quit (XCDR (val
), Vscript_representative_chars
);
886 if (CONSP (val
) && VECTORP (XCDR (val
)))
891 if (INTEGERP (AREF (spec
, FONT_SPACING_INDEX
)))
892 spacing
= XINT (AREF (spec
, FONT_SPACING_INDEX
));
893 family
= AREF (spec
, FONT_FAMILY_INDEX
);
896 Lisp_Object resolved
;
898 resolved
= ftfont_resolve_generic_family (family
, pattern
);
899 if (! NILP (resolved
))
901 FcPatternDel (pattern
, FC_FAMILY
);
902 if (! FcPatternAddString (pattern
, FC_FAMILY
,
903 SYMBOL_FcChar8 (resolved
)))
907 adstyle
= AREF (spec
, FONT_ADSTYLE_INDEX
);
908 if (! NILP (adstyle
) && SBYTES (SYMBOL_NAME (adstyle
)) == 0)
910 objset
= FcObjectSetBuild (FC_FOUNDRY
, FC_FAMILY
, FC_WEIGHT
, FC_SLANT
,
911 FC_WIDTH
, FC_PIXEL_SIZE
, FC_SPACING
, FC_SCALABLE
,
912 FC_STYLE
, FC_FILE
, FC_INDEX
,
915 #endif /* FC_CAPABILITY */
923 FcObjectSetAdd (objset
, FC_CHARSET
);
925 fontset
= FcFontList (NULL
, pattern
, objset
);
926 if (! fontset
|| fontset
->nfont
== 0)
929 /* Need fix because this finds any fonts. */
930 if (fontset
->nfont
== 0 && ! NILP (family
))
932 /* Try maching with configuration. For instance, the
933 configuration may specify "Nimbus Mono L" as an alias of
935 FcPattern
*pat
= FcPatternBuild (0, FC_FAMILY
, FcTypeString
,
936 SYMBOL_FcChar8 (family
), NULL
);
939 if (FcConfigSubstitute (NULL
, pat
, FcMatchPattern
) == FcTrue
)
942 FcPatternGetString (pat
, FC_FAMILY
, i
, &fam
) == FcResultMatch
;
945 FcPatternDel (pattern
, FC_FAMILY
);
946 FcPatternAddString (pattern
, FC_FAMILY
, fam
);
947 FcFontSetDestroy (fontset
);
948 fontset
= FcFontList (NULL
, pattern
, objset
);
949 if (fontset
&& fontset
->nfont
> 0)
955 for (i
= 0; i
< fontset
->nfont
; i
++)
963 if ((FcPatternGetInteger (fontset
->fonts
[i
], FC_SPACING
, 0, &this)
974 if (FcPatternGetString (fontset
->fonts
[i
], FC_CAPABILITY
, 0, &this)
976 || ! strstr ((char *) this, otlayout
))
979 #endif /* FC_CAPABILITY */
986 if (FcPatternGetString (fontset
->fonts
[i
], FC_FILE
, 0, &file
)
989 otf
= OTF_open ((char *) file
);
992 if (OTF_check_features (otf
, 1,
993 otspec
->script_tag
, otspec
->langsys_tag
,
995 otspec
->nfeatures
[0]) != 1
996 || OTF_check_features (otf
, 0,
997 otspec
->script_tag
, otspec
->langsys_tag
,
999 otspec
->nfeatures
[1]) != 1)
1002 #endif /* HAVE_LIBOTF */
1003 if (VECTORP (chars
))
1007 if (FcPatternGetCharSet (fontset
->fonts
[i
], FC_CHARSET
, 0, &charset
)
1010 for (j
= 0; j
< ASIZE (chars
); j
++)
1011 if (NATNUMP (AREF (chars
, j
))
1012 && FcCharSetHasChar (charset
, XFASTINT (AREF (chars
, j
))))
1014 if (j
== ASIZE (chars
))
1017 if (! NILP (adstyle
) || langname
)
1019 Lisp_Object this_adstyle
= get_adstyle_property (fontset
->fonts
[i
]);
1021 if (! NILP (adstyle
)
1022 && (NILP (this_adstyle
)
1023 || xstrcasecmp (SDATA (SYMBOL_NAME (adstyle
)),
1024 SDATA (SYMBOL_NAME (this_adstyle
))) != 0))
1027 && ! NILP (this_adstyle
)
1028 && xstrcasecmp (langname
, SDATA (SYMBOL_NAME (this_adstyle
))))
1031 entity
= ftfont_pattern_entity (fontset
->fonts
[i
],
1032 AREF (spec
, FONT_EXTRA_INDEX
));
1033 if (! NILP (entity
))
1034 val
= Fcons (entity
, val
);
1036 val
= Fnreverse (val
);
1040 /* We come here because of unexpected error in fontconfig API call
1041 (usually insufficient memory). */
1045 FONT_ADD_LOG ("ftfont-list", spec
, val
);
1046 if (objset
) FcObjectSetDestroy (objset
);
1047 if (fontset
) FcFontSetDestroy (fontset
);
1048 if (pattern
) FcPatternDestroy (pattern
);
1053 ftfont_match (Lisp_Object frame
, Lisp_Object spec
)
1055 Lisp_Object entity
= Qnil
;
1056 FcPattern
*pattern
, *match
= NULL
;
1058 char otlayout
[15]; /* For "otlayout:XXXX" */
1059 struct OpenTypeSpec
*otspec
= NULL
;
1060 char *langname
= NULL
;
1062 if (! fc_initialized
)
1068 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
1072 if (INTEGERP (AREF (spec
, FONT_SIZE_INDEX
)))
1076 value
.type
= FcTypeDouble
;
1077 value
.u
.d
= XINT (AREF (spec
, FONT_SIZE_INDEX
));
1078 FcPatternAdd (pattern
, FC_PIXEL_SIZE
, value
, FcFalse
);
1080 if (FcConfigSubstitute (NULL
, pattern
, FcMatchPattern
) == FcTrue
)
1082 FcDefaultSubstitute (pattern
);
1083 match
= FcFontMatch (NULL
, pattern
, &result
);
1086 entity
= ftfont_pattern_entity (match
, AREF (spec
, FONT_EXTRA_INDEX
));
1087 FcPatternDestroy (match
);
1088 if (! NILP (AREF (spec
, FONT_FAMILY_INDEX
))
1089 && NILP (assq_no_quit (AREF (spec
, FONT_FAMILY_INDEX
),
1090 ftfont_generic_family_list
))
1091 && NILP (Fstring_equal (AREF (spec
, FONT_FAMILY_INDEX
),
1092 AREF (entity
, FONT_FAMILY_INDEX
))))
1096 FcPatternDestroy (pattern
);
1098 FONT_ADD_LOG ("ftfont-match", spec
, entity
);
1103 ftfont_list_family (Lisp_Object frame
)
1105 Lisp_Object list
= Qnil
;
1106 FcPattern
*pattern
= NULL
;
1107 FcFontSet
*fontset
= NULL
;
1108 FcObjectSet
*objset
= NULL
;
1111 if (! fc_initialized
)
1117 pattern
= FcPatternCreate ();
1120 objset
= FcObjectSetBuild (FC_FAMILY
, NULL
);
1123 fontset
= FcFontList (NULL
, pattern
, objset
);
1127 for (i
= 0; i
< fontset
->nfont
; i
++)
1129 FcPattern
*pat
= fontset
->fonts
[i
];
1132 if (FcPatternGetString (pat
, FC_FAMILY
, 0, &str
) == FcResultMatch
)
1133 list
= Fcons (intern ((char *) str
), list
);
1137 if (objset
) FcObjectSetDestroy (objset
);
1138 if (fontset
) FcFontSetDestroy (fontset
);
1139 if (pattern
) FcPatternDestroy (pattern
);
1146 ftfont_open (FRAME_PTR f
, Lisp_Object entity
, int pixel_size
)
1148 struct ftfont_info
*ftfont_info
;
1150 struct ftfont_cache_data
*cache_data
;
1154 Lisp_Object val
, filename
, index
, cache
, font_object
;
1161 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
1165 cache
= ftfont_lookup_cache (entity
, FTFONT_CACHE_FOR_FACE
);
1168 filename
= XCAR (val
);
1171 cache_data
= XSAVE_VALUE (XCDR (cache
))->pointer
;
1172 ft_face
= cache_data
->ft_face
;
1173 if (XSAVE_VALUE (val
)->integer
> 0)
1175 /* FT_Face in this cache is already used by the different size. */
1176 if (FT_New_Size (ft_face
, &ft_size
) != 0)
1178 if (FT_Activate_Size (ft_size
) != 0)
1180 FT_Done_Size (ft_size
);
1184 XSAVE_VALUE (val
)->integer
++;
1185 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
1188 if (FT_Set_Pixel_Sizes (ft_face
, size
, size
) != 0)
1190 if (XSAVE_VALUE (val
)->integer
== 0)
1191 FT_Done_Face (ft_face
);
1195 font_object
= font_make_object (VECSIZE (struct ftfont_info
), entity
, size
);
1196 ASET (font_object
, FONT_TYPE_INDEX
, Qfreetype
);
1197 len
= font_unparse_xlfd (entity
, size
, name
, 256);
1199 ASET (font_object
, FONT_NAME_INDEX
, make_string (name
, len
));
1200 len
= font_unparse_fcname (entity
, size
, name
, 256);
1202 ASET (font_object
, FONT_FULLNAME_INDEX
, make_string (name
, len
));
1204 ASET (font_object
, FONT_FULLNAME_INDEX
,
1205 AREF (font_object
, FONT_NAME_INDEX
));
1206 ASET (font_object
, FONT_FILE_INDEX
, filename
);
1207 ASET (font_object
, FONT_FORMAT_INDEX
, ftfont_font_format (NULL
, filename
));
1208 font
= XFONT_OBJECT (font_object
);
1209 ftfont_info
= (struct ftfont_info
*) font
;
1210 ftfont_info
->ft_size
= ft_face
->size
;
1211 ftfont_info
->index
= XINT (index
);
1213 ftfont_info
->maybe_otf
= ft_face
->face_flags
& FT_FACE_FLAG_SFNT
;
1214 ftfont_info
->otf
= NULL
;
1215 #endif /* HAVE_LIBOTF */
1216 /* This means that there's no need of transformation. */
1217 ftfont_info
->matrix
.xx
= 0;
1218 font
->pixel_size
= size
;
1219 font
->driver
= &ftfont_driver
;
1220 font
->encoding_charset
= font
->repertory_charset
= -1;
1222 upEM
= ft_face
->units_per_EM
;
1223 scalable
= (INTEGERP (AREF (entity
, FONT_AVGWIDTH_INDEX
))
1224 && XINT (AREF (entity
, FONT_AVGWIDTH_INDEX
)) == 0);
1227 font
->ascent
= ft_face
->ascender
* size
/ upEM
;
1228 font
->descent
= - ft_face
->descender
* size
/ upEM
;
1229 font
->height
= ft_face
->height
* size
/ upEM
;
1233 font
->ascent
= ft_face
->size
->metrics
.ascender
>> 6;
1234 font
->descent
= - ft_face
->size
->metrics
.descender
>> 6;
1235 font
->height
= ft_face
->size
->metrics
.height
>> 6;
1237 if (INTEGERP (AREF (entity
, FONT_SPACING_INDEX
)))
1238 spacing
= XINT (AREF (entity
, FONT_SPACING_INDEX
));
1240 spacing
= FC_PROPORTIONAL
;
1241 if (spacing
!= FC_PROPORTIONAL
&& spacing
!= FC_DUAL
)
1242 font
->min_width
= font
->average_width
= font
->space_width
1243 = (scalable
? ft_face
->max_advance_width
* size
/ upEM
1244 : ft_face
->size
->metrics
.max_advance
>> 6);
1249 font
->min_width
= font
->average_width
= font
->space_width
= 0;
1250 for (i
= 32, n
= 0; i
< 127; i
++)
1251 if (FT_Load_Char (ft_face
, i
, FT_LOAD_DEFAULT
) == 0)
1253 int this_width
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1256 && (! font
->min_width
|| font
->min_width
> this_width
))
1257 font
->min_width
= this_width
;
1259 font
->space_width
= this_width
;
1260 font
->average_width
+= this_width
;
1264 font
->average_width
/= n
;
1267 font
->baseline_offset
= 0;
1268 font
->relative_compose
= 0;
1269 font
->default_ascent
= 0;
1270 font
->vertical_centering
= 0;
1273 font
->underline_position
= -ft_face
->underline_position
* size
/ upEM
;
1274 font
->underline_thickness
= ft_face
->underline_thickness
* size
/ upEM
;
1278 font
->underline_position
= -1;
1279 font
->underline_thickness
= 0;
1286 ftfont_close (FRAME_PTR f
, struct font
*font
)
1288 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1289 Lisp_Object val
, cache
;
1291 val
= Fcons (font
->props
[FONT_FILE_INDEX
], make_number (ftfont_info
->index
));
1292 cache
= ftfont_lookup_cache (val
, FTFONT_CACHE_FOR_FACE
);
1293 xassert (CONSP (cache
));
1295 (XSAVE_VALUE (val
)->integer
)--;
1296 if (XSAVE_VALUE (val
)->integer
== 0)
1298 struct ftfont_cache_data
*cache_data
= XSAVE_VALUE (val
)->pointer
;
1300 FT_Done_Face (cache_data
->ft_face
);
1302 if (ftfont_info
->otf
)
1303 OTF_close (ftfont_info
->otf
);
1305 cache_data
->ft_face
= NULL
;
1308 FT_Done_Size (ftfont_info
->ft_size
);
1312 ftfont_has_char (Lisp_Object font
, int c
)
1314 struct charset
*cs
= NULL
;
1316 if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qja
)
1317 && charset_jisx0208
>= 0)
1318 cs
= CHARSET_FROM_ID (charset_jisx0208
);
1319 else if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qko
)
1320 && charset_ksc5601
>= 0)
1321 cs
= CHARSET_FROM_ID (charset_ksc5601
);
1323 return (ENCODE_CHAR (cs
, c
) != CHARSET_INVALID_CODE (cs
));
1325 if (FONT_ENTITY_P (font
))
1327 FcCharSet
*charset
= ftfont_get_fc_charset (font
);
1329 return (FcCharSetHasChar (charset
, c
) == FcTrue
);
1333 struct ftfont_info
*ftfont_info
;
1335 ftfont_info
= (struct ftfont_info
*) XFONT_OBJECT (font
);
1336 return (FT_Get_Char_Index (ftfont_info
->ft_size
->face
, (FT_ULong
) c
)
1342 ftfont_encode_char (struct font
*font
, int c
)
1344 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1345 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1346 FT_ULong charcode
= c
;
1347 FT_UInt code
= FT_Get_Char_Index (ft_face
, charcode
);
1349 return (code
> 0 ? code
: FONT_INVALID_CODE
);
1353 ftfont_text_extents (struct font
*font
, unsigned int *code
, int nglyphs
, struct font_metrics
*metrics
)
1355 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1356 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1360 if (ftfont_info
->ft_size
!= ft_face
->size
)
1361 FT_Activate_Size (ftfont_info
->ft_size
);
1363 memset (metrics
, 0, sizeof (struct font_metrics
));
1364 for (i
= 0, first
= 1; i
< nglyphs
; i
++)
1366 if (FT_Load_Glyph (ft_face
, code
[i
], FT_LOAD_DEFAULT
) == 0)
1368 FT_Glyph_Metrics
*m
= &ft_face
->glyph
->metrics
;
1374 metrics
->lbearing
= m
->horiBearingX
>> 6;
1375 metrics
->rbearing
= (m
->horiBearingX
+ m
->width
) >> 6;
1376 metrics
->ascent
= m
->horiBearingY
>> 6;
1377 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1383 if (metrics
->lbearing
> width
+ (m
->horiBearingX
>> 6))
1384 metrics
->lbearing
= width
+ (m
->horiBearingX
>> 6);
1385 if (metrics
->rbearing
1386 < width
+ ((m
->horiBearingX
+ m
->width
) >> 6))
1388 = width
+ ((m
->horiBearingX
+ m
->width
) >> 6);
1389 if (metrics
->ascent
< (m
->horiBearingY
>> 6))
1390 metrics
->ascent
= m
->horiBearingY
>> 6;
1391 if (metrics
->descent
> ((m
->height
- m
->horiBearingY
) >> 6))
1392 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1394 width
+= m
->horiAdvance
>> 6;
1398 width
+= font
->space_width
;
1402 metrics
->width
= width
;
1408 ftfont_get_bitmap (struct font
*font
, unsigned int code
, struct font_bitmap
*bitmap
, int bits_per_pixel
)
1410 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1411 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1412 FT_Int32 load_flags
= FT_LOAD_RENDER
;
1414 if (ftfont_info
->ft_size
!= ft_face
->size
)
1415 FT_Activate_Size (ftfont_info
->ft_size
);
1416 if (bits_per_pixel
== 1)
1418 #ifdef FT_LOAD_TARGET_MONO
1419 load_flags
|= FT_LOAD_TARGET_MONO
;
1421 load_flags
|= FT_LOAD_MONOCHROME
;
1424 else if (bits_per_pixel
!= 8)
1425 /* We don't support such a rendering. */
1428 if (FT_Load_Glyph (ft_face
, code
, load_flags
) != 0)
1430 bitmap
->bits_per_pixel
1431 = (ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_MONO
? 1
1432 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
? 8
1433 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD
? 8
1434 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD_V
? 8
1436 if (bitmap
->bits_per_pixel
< 0)
1437 /* We don't suport that kind of pixel mode. */
1439 bitmap
->rows
= ft_face
->glyph
->bitmap
.rows
;
1440 bitmap
->width
= ft_face
->glyph
->bitmap
.width
;
1441 bitmap
->pitch
= ft_face
->glyph
->bitmap
.pitch
;
1442 bitmap
->buffer
= ft_face
->glyph
->bitmap
.buffer
;
1443 bitmap
->left
= ft_face
->glyph
->bitmap_left
;
1444 bitmap
->top
= ft_face
->glyph
->bitmap_top
;
1445 bitmap
->advance
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1446 bitmap
->extra
= NULL
;
1452 ftfont_anchor_point (struct font
*font
, unsigned int code
, int index
, int *x
, int *y
)
1454 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1455 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1457 if (ftfont_info
->ft_size
!= ft_face
->size
)
1458 FT_Activate_Size (ftfont_info
->ft_size
);
1459 if (FT_Load_Glyph (ft_face
, code
, FT_LOAD_DEFAULT
) != 0)
1461 if (ft_face
->glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
1463 if (index
>= ft_face
->glyph
->outline
.n_points
)
1465 *x
= ft_face
->glyph
->outline
.points
[index
].x
;
1466 *y
= ft_face
->glyph
->outline
.points
[index
].y
;
1473 ftfont_otf_features (OTF_GSUB_GPOS
*gsub_gpos
)
1475 Lisp_Object scripts
, langsyses
, features
, sym
;
1478 for (scripts
= Qnil
, i
= gsub_gpos
->ScriptList
.ScriptCount
- 1; i
>= 0; i
--)
1480 OTF_Script
*otf_script
= gsub_gpos
->ScriptList
.Script
+ i
;
1482 for (langsyses
= Qnil
, j
= otf_script
->LangSysCount
- 1; j
>= -1; j
--)
1484 OTF_LangSys
*otf_langsys
;
1487 otf_langsys
= otf_script
->LangSys
+ j
;
1488 else if (otf_script
->DefaultLangSysOffset
)
1489 otf_langsys
= &otf_script
->DefaultLangSys
;
1493 for (features
= Qnil
, k
= otf_langsys
->FeatureCount
- 1; k
>= 0; k
--)
1495 l
= otf_langsys
->FeatureIndex
[k
];
1496 if (l
>= gsub_gpos
->FeatureList
.FeatureCount
)
1498 OTF_TAG_SYM (sym
, gsub_gpos
->FeatureList
.Feature
[l
].FeatureTag
);
1499 features
= Fcons (sym
, features
);
1502 OTF_TAG_SYM (sym
, otf_script
->LangSysRecord
[j
].LangSysTag
);
1505 langsyses
= Fcons (Fcons (sym
, features
), langsyses
);
1508 OTF_TAG_SYM (sym
, gsub_gpos
->ScriptList
.Script
[i
].ScriptTag
);
1509 scripts
= Fcons (Fcons (sym
, langsyses
), scripts
);
1517 ftfont_otf_capability (struct font
*font
)
1519 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1520 OTF
*otf
= ftfont_get_otf (ftfont_info
);
1521 Lisp_Object gsub_gpos
;
1525 gsub_gpos
= Fcons (Qnil
, Qnil
);
1526 if (OTF_get_table (otf
, "GSUB") == 0
1527 && otf
->gsub
->FeatureList
.FeatureCount
> 0)
1528 XSETCAR (gsub_gpos
, ftfont_otf_features (otf
->gsub
));
1529 if (OTF_get_table (otf
, "GPOS") == 0
1530 && otf
->gpos
->FeatureList
.FeatureCount
> 0)
1531 XSETCDR (gsub_gpos
, ftfont_otf_features (otf
->gpos
));
1535 #ifdef HAVE_M17N_FLT
1537 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1538 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1539 /* We can use the new feature of libotf and m17n-flt to handle the
1540 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1541 some Agian scripts. */
1542 #define M17N_FLT_USE_NEW_FEATURE
1555 ftfont_get_glyph_id (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1558 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1559 FT_Face ft_face
= flt_font_ft
->ft_face
;
1562 for (g
= gstring
->glyphs
+ from
; from
< to
; g
++, from
++)
1565 FT_UInt code
= FT_Get_Char_Index (ft_face
, g
->code
);
1567 g
->code
= code
> 0 ? code
: FONT_INVALID_CODE
;
1573 /* Operators for 26.6 fixed fractional pixel format */
1575 #define FLOOR(x) ((x) & -64)
1576 #define CEIL(x) (((x)+63) & -64)
1577 #define ROUND(x) (((x)+32) & -64)
1580 ftfont_get_metrics (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1583 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1584 FT_Face ft_face
= flt_font_ft
->ft_face
;
1587 for (g
= gstring
->glyphs
+ from
; from
< to
; g
++, from
++)
1590 if (g
->code
!= FONT_INVALID_CODE
)
1592 FT_Glyph_Metrics
*m
;
1593 int lbearing
, rbearing
, ascent
, descent
, xadv
;
1595 if (FT_Load_Glyph (ft_face
, g
->code
, FT_LOAD_DEFAULT
) != 0)
1597 m
= &ft_face
->glyph
->metrics
;
1598 if (flt_font_ft
->matrix
)
1603 v
[0].x
= v
[1].x
= m
->horiBearingX
;
1604 v
[2].x
= v
[3].x
= m
->horiBearingX
+ m
->width
;
1605 v
[0].y
= v
[2].y
= m
->horiBearingY
;
1606 v
[1].y
= v
[3].y
= m
->horiBearingY
- m
->height
;
1607 for (i
= 0; i
< 4; i
++)
1608 FT_Vector_Transform (v
+ i
, flt_font_ft
->matrix
);
1609 g
->lbearing
= v
[0].x
< v
[1].x
? FLOOR (v
[0].x
) : FLOOR (v
[1].x
);
1610 g
->rbearing
= v
[2].x
> v
[3].x
? CEIL (v
[2].x
) : CEIL (v
[3].x
);
1611 g
->ascent
= v
[0].y
> v
[2].y
? CEIL (v
[0].y
) : CEIL (v
[2].y
);
1612 g
->descent
= v
[1].y
< v
[3].y
? - FLOOR (v
[1].y
) : - FLOOR (v
[3].y
);
1616 g
->lbearing
= FLOOR (m
->horiBearingX
);
1617 g
->rbearing
= CEIL (m
->horiBearingX
+ m
->width
);
1618 g
->ascent
= CEIL (m
->horiBearingY
);
1619 g
->descent
= - FLOOR (m
->horiBearingY
- m
->height
);
1621 g
->xadv
= ROUND (ft_face
->glyph
->advance
.x
);
1626 g
->rbearing
= g
->xadv
= flt_font_ft
->font
->space_width
<< 6;
1627 g
->ascent
= flt_font_ft
->font
->ascent
<< 6;
1628 g
->descent
= flt_font_ft
->font
->descent
<< 6;
1637 ftfont_check_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
)
1639 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1640 OTF
*otf
= flt_font_ft
->otf
;
1644 for (i
= 0; i
< 2; i
++)
1646 if (! spec
->features
[i
])
1648 for (n
= 0; spec
->features
[i
][n
]; n
++);
1649 tags
= alloca (sizeof (OTF_Tag
) * n
);
1650 for (n
= 0, negative
= 0; spec
->features
[i
][n
]; n
++)
1652 if (spec
->features
[i
][n
] == 0xFFFFFFFF)
1655 tags
[n
- 1] = spec
->features
[i
][n
] | 0x80000000;
1657 tags
[n
] = spec
->features
[i
][n
];
1659 #ifdef M17N_FLT_USE_NEW_FEATURE
1660 if (OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1661 tags
, n
- negative
) != 1)
1663 #else /* not M17N_FLT_USE_NEW_FEATURE */
1664 if (n
- negative
> 0
1665 && OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1666 tags
, n
- negative
) != 1)
1668 #endif /* not M17N_FLT_USE_NEW_FEATURE */
1673 #define DEVICE_DELTA(table, size) \
1674 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1675 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1679 adjust_anchor (FT_Face ft_face
, OTF_Anchor
*anchor
,
1680 unsigned code
, int x_ppem
, int y_ppem
, int *x
, int *y
)
1682 if (anchor
->AnchorFormat
== 2)
1684 FT_Outline
*outline
;
1685 int ap
= anchor
->f
.f1
.AnchorPoint
;
1687 FT_Load_Glyph (ft_face
, (FT_UInt
) code
, FT_LOAD_MONOCHROME
);
1688 outline
= &ft_face
->glyph
->outline
;
1689 if (ap
< outline
->n_points
)
1691 *x
= outline
->points
[ap
].x
<< 6;
1692 *y
= outline
->points
[ap
].y
<< 6;
1695 else if (anchor
->AnchorFormat
== 3)
1697 if (anchor
->f
.f2
.XDeviceTable
.offset
1698 && anchor
->f
.f2
.XDeviceTable
.DeltaValue
)
1699 *x
+= DEVICE_DELTA (anchor
->f
.f2
.XDeviceTable
, x_ppem
);
1700 if (anchor
->f
.f2
.YDeviceTable
.offset
1701 && anchor
->f
.f2
.YDeviceTable
.DeltaValue
)
1702 *y
+= DEVICE_DELTA (anchor
->f
.f2
.YDeviceTable
, y_ppem
);
1706 static OTF_GlyphString otf_gstring
;
1709 setup_otf_gstring (int size
)
1711 if (otf_gstring
.size
== 0)
1713 otf_gstring
.glyphs
= (OTF_Glyph
*) xmalloc (sizeof (OTF_Glyph
) * size
);
1714 otf_gstring
.size
= size
;
1716 else if (otf_gstring
.size
< size
)
1718 otf_gstring
.glyphs
= xrealloc (otf_gstring
.glyphs
,
1719 sizeof (OTF_Glyph
) * size
);
1720 otf_gstring
.size
= size
;
1722 otf_gstring
.used
= size
;
1723 memset (otf_gstring
.glyphs
, 0, sizeof (OTF_Glyph
) * size
);
1726 #ifdef M17N_FLT_USE_NEW_FEATURE
1728 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1729 #define PACK_OTF_TAG(TAG) \
1730 ((((TAG) & 0x7F000000) >> 3) \
1731 | (((TAG) & 0x7F0000) >> 2) \
1732 | (((TAG) & 0x7F00) >> 1) \
1735 /* Assuming that FONT is an OpenType font, apply OpenType features
1736 specified in SPEC on glyphs between FROM and TO of IN, and record
1737 the lastly applied feature in each glyph of IN. If OUT is not
1738 NULL, append the resulting glyphs to OUT while storing glyph
1739 position adjustment information in ADJUSTMENT. */
1742 ftfont_drive_otf (font
, spec
, in
, from
, to
, out
, adjustment
)
1745 MFLTGlyphString
*in
;
1747 MFLTGlyphString
*out
;
1748 MFLTGlyphAdjustment
*adjustment
;
1750 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1751 FT_Face ft_face
= flt_font_ft
->ft_face
;
1752 OTF
*otf
= flt_font_ft
->otf
;
1753 int len
= to
- from
;
1756 char script
[5], *langsys
= NULL
;
1757 char *gsub_features
= NULL
, *gpos_features
= NULL
;
1758 OTF_Feature
*features
;
1762 OTF_tag_name (spec
->script
, script
);
1765 langsys
= alloca (5);
1766 OTF_tag_name (spec
->langsys
, langsys
);
1768 for (i
= 0; i
< 2; i
++)
1772 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
1774 for (j
= 0; spec
->features
[i
][j
]; j
++);
1776 p
= gsub_features
= alloca (6 * j
);
1778 p
= gpos_features
= alloca (6 * j
);
1779 for (j
= 0; spec
->features
[i
][j
]; j
++)
1781 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
1782 *p
++ = '*', *p
++ = ',';
1785 OTF_tag_name (spec
->features
[i
][j
], p
);
1794 setup_otf_gstring (len
);
1795 for (i
= 0; i
< len
; i
++)
1797 otf_gstring
.glyphs
[i
].c
= in
->glyphs
[from
+ i
].c
;
1798 otf_gstring
.glyphs
[i
].glyph_id
= in
->glyphs
[from
+ i
].code
;
1801 OTF_drive_gdef (otf
, &otf_gstring
);
1802 gidx
= out
? out
->used
: from
;
1804 if (gsub_features
&& out
)
1806 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1809 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
1811 features
= otf
->gsub
->FeatureList
.Feature
;
1812 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
1815 int min_from
, max_to
;
1817 int feature_idx
= otfg
->positioning_type
>> 4;
1819 g
= out
->glyphs
+ out
->used
;
1820 *g
= in
->glyphs
[from
+ otfg
->f
.index
.from
];
1821 if (g
->code
!= otfg
->glyph_id
)
1824 g
->code
= otfg
->glyph_id
;
1830 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
1832 /* OTFG substitutes multiple glyphs in IN. */
1833 for (j
= from
+ otfg
->f
.index
.from
+ 1;
1834 j
<= from
+ otfg
->f
.index
.to
; j
++)
1836 if (min_from
> in
->glyphs
[j
].from
)
1837 min_from
= in
->glyphs
[j
].from
;
1838 if (max_to
< in
->glyphs
[j
].to
)
1839 max_to
= in
->glyphs
[j
].to
;
1846 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1847 tag
= PACK_OTF_TAG (tag
);
1848 g
->internal
= (g
->internal
& ~0x1FFFFFFF) | tag
;
1850 for (i
++, otfg
++; (i
< otf_gstring
.used
1851 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
1854 g
= out
->glyphs
+ out
->used
;
1855 *g
= in
->glyphs
[from
+ otfg
->f
.index
.to
];
1856 if (g
->code
!= otfg
->glyph_id
)
1859 g
->code
= otfg
->glyph_id
;
1862 feature_idx
= otfg
->positioning_type
>> 4;
1865 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1866 tag
= PACK_OTF_TAG (tag
);
1867 g
->internal
= (g
->internal
& ~0x1FFFFFFF) | tag
;
1873 else if (gsub_features
)
1875 /* Just for checking which features will be applied. */
1876 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1879 features
= otf
->gsub
->FeatureList
.Feature
;
1880 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; i
++,
1883 int feature_idx
= otfg
->positioning_type
>> 4;
1887 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1888 tag
= PACK_OTF_TAG (tag
);
1889 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
1891 MFLTGlyph
*g
= in
->glyphs
+ (from
+ j
);
1892 g
->internal
= (g
->internal
& ~0x1FFFFFFF) | tag
;
1899 if (out
->allocated
< out
->used
+ len
)
1901 for (i
= 0; i
< len
; i
++)
1902 out
->glyphs
[out
->used
++] = in
->glyphs
[from
+ i
];
1905 if (gpos_features
&& out
)
1907 MFLTGlyph
*base
= NULL
, *mark
= NULL
, *g
;
1908 int x_ppem
, y_ppem
, x_scale
, y_scale
;
1910 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
1913 features
= otf
->gpos
->FeatureList
.Feature
;
1914 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
1915 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
1916 x_scale
= ft_face
->size
->metrics
.x_scale
;
1917 y_scale
= ft_face
->size
->metrics
.y_scale
;
1919 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out
->glyphs
+ gidx
;
1920 i
< otf_gstring
.used
; i
++, otfg
++, g
++)
1923 int feature_idx
= otfg
->positioning_type
>> 4;
1927 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1928 tag
= PACK_OTF_TAG (tag
);
1929 g
->internal
= (g
->internal
& ~0x1FFFFFFF) | tag
;
1932 if (! otfg
->glyph_id
)
1934 switch (otfg
->positioning_type
& 0xF)
1938 case 1: /* Single */
1941 int format
= otfg
->f
.f1
.format
;
1943 if (format
& OTF_XPlacement
)
1945 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
1946 if (format
& OTF_XPlaDevice
)
1948 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
1949 if (format
& OTF_YPlacement
)
1951 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
1952 if (format
& OTF_YPlaDevice
)
1954 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
1955 if (format
& OTF_XAdvance
)
1957 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
1958 if (format
& OTF_XAdvDevice
)
1960 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
1961 if (format
& OTF_YAdvance
)
1963 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
1964 if (format
& OTF_YAdvDevice
)
1966 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
1967 adjustment
[i
].set
= 1;
1970 case 3: /* Cursive */
1971 /* Not yet supported. */
1973 case 4: /* Mark-to-Base */
1974 case 5: /* Mark-to-Ligature */
1978 goto label_adjust_anchor
;
1979 default: /* i.e. case 6 Mark-to-Mark */
1984 label_adjust_anchor
:
1986 int base_x
, base_y
, mark_x
, mark_y
;
1987 int this_from
, this_to
;
1989 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
1990 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
1991 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
1992 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
1994 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
1995 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
,
1996 prev
->code
, x_ppem
, y_ppem
, &base_x
, &base_y
);
1997 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
1998 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->code
,
1999 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2000 adjustment
[i
].xoff
= (base_x
- mark_x
);
2001 adjustment
[i
].yoff
= - (base_y
- mark_y
);
2002 adjustment
[i
].back
= (g
- prev
);
2003 adjustment
[i
].xadv
= 0;
2004 adjustment
[i
].advance_is_absolute
= 1;
2005 adjustment
[i
].set
= 1;
2006 this_from
= g
->from
;
2008 for (j
= 0; prev
+ j
< g
; j
++)
2010 if (this_from
> prev
[j
].from
)
2011 this_from
= prev
[j
].from
;
2012 if (this_to
< prev
[j
].to
)
2013 this_to
= prev
[j
].to
;
2015 for (; prev
<= g
; prev
++)
2017 prev
->from
= this_from
;
2022 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2024 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2030 else if (gpos_features
)
2032 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
2035 features
= otf
->gpos
->FeatureList
.Feature
;
2036 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
;
2038 if (otfg
->positioning_type
& 0xF)
2040 int feature_idx
= otfg
->positioning_type
>> 4;
2044 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
2045 tag
= PACK_OTF_TAG (tag
);
2046 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
2048 MFLTGlyph
*g
= in
->glyphs
+ (from
+ j
);
2049 g
->internal
= (g
->internal
& ~0x1FFFFFFF) | tag
;
2059 if (out
->allocated
< out
->used
+ len
)
2061 font
->get_metrics (font
, in
, from
, to
);
2062 memcpy (out
->glyphs
+ out
->used
, in
->glyphs
+ from
,
2063 sizeof (MFLTGlyph
) * len
);
2069 ftfont_try_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
,
2070 MFLTGlyphString
*in
, int from
, int to
)
2072 return ftfont_drive_otf (font
, spec
, in
, from
, to
, NULL
, NULL
);
2075 #else /* not M17N_FLT_USE_NEW_FEATURE */
2078 ftfont_drive_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
, MFLTGlyphString
*in
,
2080 MFLTGlyphString
*out
, MFLTGlyphAdjustment
*adjustment
)
2082 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
2083 FT_Face ft_face
= flt_font_ft
->ft_face
;
2084 OTF
*otf
= flt_font_ft
->otf
;
2085 int len
= to
- from
;
2088 char script
[5], *langsys
= NULL
;
2089 char *gsub_features
= NULL
, *gpos_features
= NULL
;
2093 OTF_tag_name (spec
->script
, script
);
2096 langsys
= alloca (5);
2097 OTF_tag_name (spec
->langsys
, langsys
);
2099 for (i
= 0; i
< 2; i
++)
2103 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
2105 for (j
= 0; spec
->features
[i
][j
]; j
++);
2107 p
= gsub_features
= alloca (6 * j
);
2109 p
= gpos_features
= alloca (6 * j
);
2110 for (j
= 0; spec
->features
[i
][j
]; j
++)
2112 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
2113 *p
++ = '*', *p
++ = ',';
2116 OTF_tag_name (spec
->features
[i
][j
], p
);
2125 setup_otf_gstring (len
);
2126 for (i
= 0; i
< len
; i
++)
2128 otf_gstring
.glyphs
[i
].c
= in
->glyphs
[from
+ i
].c
;
2129 otf_gstring
.glyphs
[i
].glyph_id
= in
->glyphs
[from
+ i
].code
;
2132 OTF_drive_gdef (otf
, &otf_gstring
);
2137 if (OTF_drive_gsub (otf
, &otf_gstring
, script
, langsys
, gsub_features
)
2140 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
2142 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
2145 int min_from
, max_to
;
2148 g
= out
->glyphs
+ out
->used
;
2149 *g
= in
->glyphs
[from
+ otfg
->f
.index
.from
];
2150 if (g
->code
!= otfg
->glyph_id
)
2153 g
->code
= otfg
->glyph_id
;
2159 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
2161 /* OTFG substitutes multiple glyphs in IN. */
2162 for (j
= from
+ otfg
->f
.index
.from
+ 1;
2163 j
<= from
+ otfg
->f
.index
.to
; j
++)
2165 if (min_from
> in
->glyphs
[j
].from
)
2166 min_from
= in
->glyphs
[j
].from
;
2167 if (max_to
< in
->glyphs
[j
].to
)
2168 max_to
= in
->glyphs
[j
].to
;
2173 for (i
++, otfg
++; (i
< otf_gstring
.used
2174 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
2177 g
= out
->glyphs
+ out
->used
;
2178 *g
= in
->glyphs
[from
+ otfg
->f
.index
.to
];
2179 if (g
->code
!= otfg
->glyph_id
)
2182 g
->code
= otfg
->glyph_id
;
2191 if (out
->allocated
< out
->used
+ len
)
2193 for (i
= 0; i
< len
; i
++)
2194 out
->glyphs
[out
->used
++] = in
->glyphs
[from
+ i
];
2199 MFLTGlyph
*base
= NULL
, *mark
= NULL
, *g
;
2200 int x_ppem
, y_ppem
, x_scale
, y_scale
;
2202 if (OTF_drive_gpos (otf
, &otf_gstring
, script
, langsys
, gpos_features
)
2206 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2207 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2208 x_scale
= ft_face
->size
->metrics
.x_scale
;
2209 y_scale
= ft_face
->size
->metrics
.y_scale
;
2211 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out
->glyphs
+ gidx
;
2212 i
< otf_gstring
.used
; i
++, otfg
++, g
++)
2216 if (! otfg
->glyph_id
)
2218 switch (otfg
->positioning_type
)
2222 case 1: /* Single */
2225 int format
= otfg
->f
.f1
.format
;
2227 if (format
& OTF_XPlacement
)
2229 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
2230 if (format
& OTF_XPlaDevice
)
2232 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
2233 if (format
& OTF_YPlacement
)
2235 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
2236 if (format
& OTF_YPlaDevice
)
2238 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
2239 if (format
& OTF_XAdvance
)
2241 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
2242 if (format
& OTF_XAdvDevice
)
2244 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
2245 if (format
& OTF_YAdvance
)
2247 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
2248 if (format
& OTF_YAdvDevice
)
2250 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
2251 adjustment
[i
].set
= 1;
2254 case 3: /* Cursive */
2255 /* Not yet supported. */
2257 case 4: /* Mark-to-Base */
2258 case 5: /* Mark-to-Ligature */
2262 goto label_adjust_anchor
;
2263 default: /* i.e. case 6 Mark-to-Mark */
2268 label_adjust_anchor
:
2270 int base_x
, base_y
, mark_x
, mark_y
;
2271 int this_from
, this_to
;
2273 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
2274 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
2275 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
2276 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
2278 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
2279 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
,
2280 prev
->code
, x_ppem
, y_ppem
, &base_x
, &base_y
);
2281 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
2282 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->code
,
2283 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2284 adjustment
[i
].xoff
= (base_x
- mark_x
);
2285 adjustment
[i
].yoff
= - (base_y
- mark_y
);
2286 adjustment
[i
].back
= (g
- prev
);
2287 adjustment
[i
].xadv
= 0;
2288 adjustment
[i
].advance_is_absolute
= 1;
2289 adjustment
[i
].set
= 1;
2290 this_from
= g
->from
;
2292 for (j
= 0; prev
+ j
< g
; j
++)
2294 if (this_from
> prev
[j
].from
)
2295 this_from
= prev
[j
].from
;
2296 if (this_to
< prev
[j
].to
)
2297 this_to
= prev
[j
].to
;
2299 for (; prev
<= g
; prev
++)
2301 prev
->from
= this_from
;
2306 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2308 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2317 if (out
->allocated
< out
->used
+ len
)
2319 font
->get_metrics (font
, in
, from
, to
);
2320 memcpy (out
->glyphs
+ out
->used
, in
->glyphs
+ from
,
2321 sizeof (MFLTGlyph
) * len
);
2326 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2328 static MFLTGlyphString gstring
;
2330 static int m17n_flt_initialized
;
2333 ftfont_shape_by_flt (Lisp_Object lgstring
, struct font
*font
,
2334 FT_Face ft_face
, OTF
*otf
, FT_Matrix
*matrix
)
2336 EMACS_UINT len
= LGSTRING_GLYPH_LEN (lgstring
);
2338 struct MFLTFontFT flt_font_ft
;
2340 int with_variation_selector
= 0;
2342 if (! m17n_flt_initialized
)
2345 #ifdef M17N_FLT_USE_NEW_FEATURE
2346 mflt_enable_new_feature
= 1;
2347 mflt_try_otf
= ftfont_try_otf
;
2348 #endif /* M17N_FLT_USE_NEW_FEATURE */
2349 m17n_flt_initialized
= 1;
2352 for (i
= 0; i
< len
; i
++)
2354 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2359 c
= LGLYPH_CHAR (g
);
2360 if (CHAR_VARIATION_SELECTOR_P (c
))
2361 with_variation_selector
++;
2364 if (with_variation_selector
)
2366 setup_otf_gstring (len
);
2367 for (i
= 0; i
< len
; i
++)
2369 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2371 otf_gstring
.glyphs
[i
].c
= LGLYPH_CHAR (g
);
2372 otf_gstring
.glyphs
[i
].f
.index
.from
= LGLYPH_FROM (g
);
2373 otf_gstring
.glyphs
[i
].f
.index
.to
= LGLYPH_TO (g
);
2375 OTF_drive_cmap (otf
, &otf_gstring
);
2376 for (i
= 0; i
< otf_gstring
.used
; i
++)
2378 OTF_Glyph
*otfg
= otf_gstring
.glyphs
+ i
;
2379 Lisp_Object g0
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.from
);
2380 Lisp_Object g1
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.to
);
2382 LGLYPH_SET_CODE (g0
, otfg
->glyph_id
);
2383 LGLYPH_SET_TO (g0
, LGLYPH_TO (g1
));
2384 LGSTRING_SET_GLYPH (lgstring
, i
, g0
);
2386 if (len
> otf_gstring
.used
)
2388 len
= otf_gstring
.used
;
2389 LGSTRING_SET_GLYPH (lgstring
, len
, Qnil
);
2393 if (gstring
.allocated
== 0)
2395 gstring
.allocated
= len
* 2;
2396 gstring
.glyph_size
= sizeof (MFLTGlyph
);
2397 gstring
.glyphs
= xmalloc (sizeof (MFLTGlyph
) * gstring
.allocated
);
2399 else if (gstring
.allocated
< len
* 2)
2401 gstring
.allocated
= len
* 2;
2402 gstring
.glyphs
= xrealloc (gstring
.glyphs
,
2403 sizeof (MFLTGlyph
) * gstring
.allocated
);
2405 memset (gstring
.glyphs
, 0, sizeof (MFLTGlyph
) * len
);
2406 for (i
= 0; i
< len
; i
++)
2408 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2410 gstring
.glyphs
[i
].c
= LGLYPH_CHAR (g
);
2411 if (with_variation_selector
)
2413 gstring
.glyphs
[i
].code
= LGLYPH_CODE (g
);
2414 gstring
.glyphs
[i
].encoded
= 1;
2422 Lisp_Object family
= Ffont_get (LGSTRING_FONT (lgstring
), QCfamily
);
2425 flt_font_ft
.flt_font
.family
= Mnil
;
2427 flt_font_ft
.flt_font
.family
2428 = msymbol ((char *) SDATA (Fdowncase (SYMBOL_NAME (family
))));
2430 flt_font_ft
.flt_font
.x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2431 flt_font_ft
.flt_font
.y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2432 flt_font_ft
.flt_font
.get_glyph_id
= ftfont_get_glyph_id
;
2433 flt_font_ft
.flt_font
.get_metrics
= ftfont_get_metrics
;
2434 flt_font_ft
.flt_font
.check_otf
= ftfont_check_otf
;
2435 flt_font_ft
.flt_font
.drive_otf
= ftfont_drive_otf
;
2436 flt_font_ft
.flt_font
.internal
= NULL
;
2437 flt_font_ft
.font
= font
;
2438 flt_font_ft
.ft_face
= ft_face
;
2439 flt_font_ft
.otf
= otf
;
2440 flt_font_ft
.matrix
= matrix
->xx
!= 0 ? matrix
: 0;
2442 && gstring
.glyphs
[1].c
>= 0x300 && gstring
.glyphs
[1].c
<= 0x36F)
2443 /* A little bit ad hoc. Perhaps, shaper must get script and
2444 language information, and select a proper flt for them
2446 flt
= mflt_get (msymbol ("combining"));
2447 for (i
= 0; i
< 3; i
++)
2449 int result
= mflt_run (&gstring
, 0, len
, &flt_font_ft
.flt_font
, flt
);
2452 gstring
.allocated
+= gstring
.allocated
;
2453 gstring
.glyphs
= xrealloc (gstring
.glyphs
,
2454 sizeof (MFLTGlyph
) * gstring
.allocated
);
2456 if (gstring
.used
> LGSTRING_GLYPH_LEN (lgstring
))
2458 for (i
= 0; i
< gstring
.used
; i
++)
2460 MFLTGlyph
*g
= gstring
.glyphs
+ i
;
2462 g
->from
= LGLYPH_FROM (LGSTRING_GLYPH (lgstring
, g
->from
));
2463 g
->to
= LGLYPH_TO (LGSTRING_GLYPH (lgstring
, g
->to
));
2466 for (i
= 0; i
< gstring
.used
; i
++)
2468 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
, i
);
2469 MFLTGlyph
*g
= gstring
.glyphs
+ i
;
2473 lglyph
= Fmake_vector (make_number (LGLYPH_SIZE
), Qnil
);
2474 LGSTRING_SET_GLYPH (lgstring
, i
, lglyph
);
2476 LGLYPH_SET_FROM (lglyph
, g
->from
);
2477 LGLYPH_SET_TO (lglyph
, g
->to
);
2478 LGLYPH_SET_CHAR (lglyph
, g
->c
);
2479 LGLYPH_SET_CODE (lglyph
, g
->code
);
2480 LGLYPH_SET_WIDTH (lglyph
, g
->xadv
>> 6);
2481 LGLYPH_SET_LBEARING (lglyph
, g
->lbearing
>> 6);
2482 LGLYPH_SET_RBEARING (lglyph
, g
->rbearing
>> 6);
2483 LGLYPH_SET_ASCENT (lglyph
, g
->ascent
>> 6);
2484 LGLYPH_SET_DESCENT (lglyph
, g
->descent
>> 6);
2489 vec
= Fmake_vector (make_number (3), Qnil
);
2490 ASET (vec
, 0, make_number (g
->xoff
>> 6));
2491 ASET (vec
, 1, make_number (g
->yoff
>> 6));
2492 ASET (vec
, 2, make_number (g
->xadv
>> 6));
2493 LGLYPH_SET_ADJUSTMENT (lglyph
, vec
);
2496 return make_number (i
);
2500 ftfont_shape (Lisp_Object lgstring
)
2503 struct ftfont_info
*ftfont_info
;
2506 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring
), font
);
2507 ftfont_info
= (struct ftfont_info
*) font
;
2508 otf
= ftfont_get_otf (ftfont_info
);
2510 return make_number (0);
2511 return ftfont_shape_by_flt (lgstring
, font
, ftfont_info
->ft_size
->face
, otf
,
2512 &ftfont_info
->matrix
);
2515 #endif /* HAVE_M17N_FLT */
2517 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2520 ftfont_variation_glyphs (struct font
*font
, int c
, unsigned variations
[256])
2522 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
2523 OTF
*otf
= ftfont_get_otf (ftfont_info
);
2527 return OTF_get_variation_glyphs (otf
, c
, variations
);
2530 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2531 #endif /* HAVE_LIBOTF */
2534 ftfont_font_format (FcPattern
*pattern
, Lisp_Object filename
)
2538 #ifdef FC_FONTFORMAT
2541 if (FcPatternGetString (pattern
, FC_FONTFORMAT
, 0, &str
) != FcResultMatch
)
2543 if (strcmp ((char *) str
, "TrueType") == 0)
2544 return intern ("truetype");
2545 if (strcmp ((char *) str
, "Type 1") == 0)
2546 return intern ("type1");
2547 if (strcmp ((char *) str
, "PCF") == 0)
2548 return intern ("pcf");
2549 if (strcmp ((char *) str
, "BDF") == 0)
2550 return intern ("bdf");
2552 #endif /* FC_FONTFORMAT */
2553 if (STRINGP (filename
))
2555 int len
= SBYTES (filename
);
2559 str
= (FcChar8
*) (SDATA (filename
) + len
- 4);
2560 if (xstrcasecmp ((char *) str
, ".ttf") == 0)
2561 return intern ("truetype");
2562 if (xstrcasecmp ((char *) str
, ".pfb") == 0)
2563 return intern ("type1");
2564 if (xstrcasecmp ((char *) str
, ".pcf") == 0)
2565 return intern ("pcf");
2566 if (xstrcasecmp ((char *) str
, ".bdf") == 0)
2567 return intern ("bdf");
2570 return intern ("unknown");
2573 static const char *ftfont_booleans
[] = {
2586 static const char *ftfont_non_booleans
[] = {
2618 ftfont_filter_properties (Lisp_Object font
, Lisp_Object alist
)
2623 /* Set boolean values to Qt or Qnil */
2624 for (i
= 0; ftfont_booleans
[i
] != NULL
; ++i
)
2625 for (it
= alist
; ! NILP (it
); it
= XCDR (it
))
2627 Lisp_Object key
= XCAR (XCAR (it
));
2628 Lisp_Object val
= XCDR (XCAR (it
));
2629 char *keystr
= SDATA (SYMBOL_NAME (key
));
2631 if (strcmp (ftfont_booleans
[i
], keystr
) == 0)
2633 char *str
= SYMBOLP (val
) ? SDATA (SYMBOL_NAME (val
)) : NULL
;
2634 if (INTEGERP (val
)) str
= XINT (val
) != 0 ? "true" : "false";
2635 if (str
== NULL
) str
= "true";
2638 if (strcmp ("false", str
) == 0 || strcmp ("False", str
) == 0
2639 || strcmp ("FALSE", str
) == 0 || strcmp ("FcFalse", str
) == 0
2640 || strcmp ("off", str
) == 0 || strcmp ("OFF", str
) == 0
2641 || strcmp ("Off", str
) == 0)
2643 Ffont_put (font
, key
, val
);
2647 for (i
= 0; ftfont_non_booleans
[i
] != NULL
; ++i
)
2648 for (it
= alist
; ! NILP (it
); it
= XCDR (it
))
2650 Lisp_Object key
= XCAR (XCAR (it
));
2651 Lisp_Object val
= XCDR (XCAR (it
));
2652 char *keystr
= SDATA (SYMBOL_NAME (key
));
2653 if (strcmp (ftfont_non_booleans
[i
], keystr
) == 0)
2654 Ffont_put (font
, key
, val
);
2660 syms_of_ftfont (void)
2662 DEFSYM (Qfreetype
, "freetype");
2663 DEFSYM (Qmonospace
, "monospace");
2664 DEFSYM (Qsans_serif
, "sans-serif");
2665 DEFSYM (Qserif
, "serif");
2666 DEFSYM (Qmono
, "mono");
2667 DEFSYM (Qsans
, "sans");
2668 DEFSYM (Qsans__serif
, "sans serif");
2670 staticpro (&freetype_font_cache
);
2671 freetype_font_cache
= Fcons (Qt
, Qnil
);
2673 staticpro (&ftfont_generic_family_list
);
2674 ftfont_generic_family_list
2675 = Fcons (Fcons (Qmonospace
, Qt
),
2676 Fcons (Fcons (Qsans_serif
, Qt
),
2677 Fcons (Fcons (Qsans
, Qt
), Qnil
)));
2679 staticpro (&ft_face_cache
);
2680 ft_face_cache
= Qnil
;
2682 ftfont_driver
.type
= Qfreetype
;
2683 register_font_driver (&ftfont_driver
, NULL
);
2686 /* arch-tag: 7cfa432c-33a6-4988-83d2-a82ed8604aca
2687 (do not change this comment) */