1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2018 Free Software Foundation, Inc.
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
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 (at
12 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 <https://www.gnu.org/licenses/>. */
24 #include <fontconfig/fontconfig.h>
25 #include <fontconfig/fcfreetype.h>
27 #include <c-strcase.h>
30 #include "dispextern.h"
31 #include "character.h"
34 #include "composite.h"
38 static struct font_driver
const ftfont_driver
;
40 /* Flag to tell if FcInit is already called or not. */
41 static bool fc_initialized
;
43 /* Handle to a FreeType library instance. */
44 static FT_Library ft_library
;
46 /* Cache for FreeType fonts. */
47 static Lisp_Object freetype_font_cache
;
49 /* Cache for FT_Face and FcCharSet. */
50 static Lisp_Object ft_face_cache
;
52 /* The actual structure for FreeType font that can be cast to struct
59 /* The following four members must be here in this order to be
60 compatible with struct xftfont_info (in xftfont.c). */
61 bool maybe_otf
; /* Flag to tell if this may be OTF or not. */
63 #endif /* HAVE_LIBOTF */
69 size_t ftfont_info_size
= sizeof (struct ftfont_info
);
73 FTFONT_CACHE_FOR_FACE
,
74 FTFONT_CACHE_FOR_CHARSET
,
75 FTFONT_CACHE_FOR_ENTITY
78 static Lisp_Object
ftfont_lookup_cache (Lisp_Object
,
79 enum ftfont_cache_for
);
81 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
87 /* characters to distinguish the charset from the others */
89 /* additional constraint by language */
92 FcCharSet
*fc_charset
;
93 } fc_charset_table
[] =
94 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
95 { "iso8859-2", { 0x00A0, 0x010E }},
96 { "iso8859-3", { 0x00A0, 0x0108 }},
97 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
98 { "iso8859-5", { 0x00A0, 0x0401 }},
99 { "iso8859-6", { 0x00A0, 0x060C }},
100 { "iso8859-7", { 0x00A0, 0x0384 }},
101 { "iso8859-8", { 0x00A0, 0x05D0 }},
102 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
103 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
104 { "iso8859-11", { 0x00A0, 0x0E01 }},
105 { "iso8859-13", { 0x00A0, 0x201C }},
106 { "iso8859-14", { 0x00A0, 0x0174 }},
107 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
108 { "iso8859-16", { 0x00A0, 0x0218}},
109 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
110 { "big5-0", { 0xF6B1 }, "zh-tw" },
111 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
112 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
113 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
114 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
115 { "cns11643.1992-3", { 0x201A9 }},
116 { "cns11643.1992-4", { 0x20057 }},
117 { "cns11643.1992-5", { 0x20000 }},
118 { "cns11643.1992-6", { 0x20003 }},
119 { "cns11643.1992-7", { 0x20055 }},
120 { "gbk-0", { 0x4E06 }, "zh-cn"},
121 { "jisx0212.1990-0", { 0x4E44 }},
122 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
123 { "jisx0213.2000-2", { 0xFA49 }},
124 { "jisx0213.2004-1", { 0x20B9F }},
125 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
126 { "tis620.2529-1", { 0x0E01 }, "th"},
127 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
128 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
129 { "mulelao-1", { 0x0E81 }, "lo"},
130 { "unicode-sip", { 0x20000 }},
135 matching_prefix (char const *str
, ptrdiff_t len
, char const *pat
)
137 return len
== strlen (pat
) && c_strncasecmp (str
, pat
, len
) == 0;
140 /* Dirty hack for handing ADSTYLE property.
142 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
143 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
144 "Oblique", "Italic", or any non-normal SWIDTH property names
145 (e.g. SemiCondensed) are appended. In addition, if there's no
146 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
147 "Regular" is used for FC_STYLE (see the function
148 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
150 Unfortunately this behavior is not documented, so the following
151 code may fail if FreeType changes the behavior in the future. */
154 get_adstyle_property (FcPattern
*p
)
161 if ((FcPatternGetString (p
, FC_FONTFORMAT
, 0, &fcstr
) == FcResultMatch
)
162 && xstrcasecmp ((char *) fcstr
, "bdf") != 0
163 && xstrcasecmp ((char *) fcstr
, "pcf") != 0)
164 /* Not a BDF nor PCF font. */
167 if (FcPatternGetString (p
, FC_STYLE
, 0, &fcstr
) != FcResultMatch
)
169 str
= (char *) fcstr
;
170 for (end
= str
; *end
&& *end
!= ' '; end
++);
171 if (matching_prefix (str
, end
- str
, "Regular")
172 || matching_prefix (str
, end
- str
, "Bold")
173 || matching_prefix (str
, end
- str
, "Oblique")
174 || matching_prefix (str
, end
- str
, "Italic"))
176 adstyle
= font_intern_prop (str
, end
- str
, 1);
177 if (font_style_to_value (FONT_WIDTH_INDEX
, adstyle
, 0) >= 0)
183 ftfont_pattern_entity (FcPattern
*p
, Lisp_Object extra
)
185 Lisp_Object key
, cache
, entity
;
193 if (FcPatternGetString (p
, FC_FILE
, 0, &str
) != FcResultMatch
)
195 if (FcPatternGetInteger (p
, FC_INDEX
, 0, &idx
) != FcResultMatch
)
199 key
= Fcons (build_unibyte_string (file
), make_number (idx
));
200 cache
= ftfont_lookup_cache (key
, FTFONT_CACHE_FOR_ENTITY
);
201 entity
= XCAR (cache
);
204 Lisp_Object val
= font_make_entity ();
207 for (i
= 0; i
< FONT_OBJLIST_INDEX
; i
++)
208 ASET (val
, i
, AREF (entity
, i
));
210 ASET (val
, FONT_EXTRA_INDEX
, Fcopy_sequence (extra
));
211 font_put_extra (val
, QCfont_entity
, key
);
215 entity
= font_make_entity ();
216 XSETCAR (cache
, entity
);
218 ASET (entity
, FONT_TYPE_INDEX
, Qfreetype
);
219 ASET (entity
, FONT_REGISTRY_INDEX
, Qiso10646_1
);
221 if (FcPatternGetString (p
, FC_FOUNDRY
, 0, &str
) == FcResultMatch
)
223 char *s
= (char *) str
;
224 ASET (entity
, FONT_FOUNDRY_INDEX
, font_intern_prop (s
, strlen (s
), 1));
226 if (FcPatternGetString (p
, FC_FAMILY
, 0, &str
) == FcResultMatch
)
228 char *s
= (char *) str
;
229 ASET (entity
, FONT_FAMILY_INDEX
, font_intern_prop (s
, strlen (s
), 1));
231 if (FcPatternGetInteger (p
, FC_WEIGHT
, 0, &numeric
) == FcResultMatch
)
233 if (numeric
>= FC_WEIGHT_REGULAR
&& numeric
< FC_WEIGHT_MEDIUM
)
234 numeric
= FC_WEIGHT_MEDIUM
;
235 FONT_SET_STYLE (entity
, FONT_WEIGHT_INDEX
, make_number (numeric
));
237 if (FcPatternGetInteger (p
, FC_SLANT
, 0, &numeric
) == FcResultMatch
)
240 FONT_SET_STYLE (entity
, FONT_SLANT_INDEX
, make_number (numeric
));
242 if (FcPatternGetInteger (p
, FC_WIDTH
, 0, &numeric
) == FcResultMatch
)
244 FONT_SET_STYLE (entity
, FONT_WIDTH_INDEX
, make_number (numeric
));
246 if (FcPatternGetDouble (p
, FC_PIXEL_SIZE
, 0, &dbl
) == FcResultMatch
)
248 ASET (entity
, FONT_SIZE_INDEX
, make_number (dbl
));
251 ASET (entity
, FONT_SIZE_INDEX
, make_number (0));
252 if (FcPatternGetInteger (p
, FC_SPACING
, 0, &numeric
) == FcResultMatch
)
253 ASET (entity
, FONT_SPACING_INDEX
, make_number (numeric
));
254 if (FcPatternGetDouble (p
, FC_DPI
, 0, &dbl
) == FcResultMatch
)
257 ASET (entity
, FONT_DPI_INDEX
, make_number (dpi
));
259 if (FcPatternGetBool (p
, FC_SCALABLE
, 0, &b
) == FcResultMatch
262 ASET (entity
, FONT_SIZE_INDEX
, make_number (0));
263 ASET (entity
, FONT_AVGWIDTH_INDEX
, make_number (0));
267 /* As this font is not scalable, perhaps this is a BDF or PCF
271 ASET (entity
, FONT_ADSTYLE_INDEX
, get_adstyle_property (p
));
272 if ((ft_library
|| FT_Init_FreeType (&ft_library
) == 0)
273 && FT_New_Face (ft_library
, file
, idx
, &ft_face
) == 0)
277 if (FT_Get_BDF_Property (ft_face
, "AVERAGE_WIDTH", &rec
) == 0
278 && rec
.type
== BDF_PROPERTY_TYPE_INTEGER
)
279 ASET (entity
, FONT_AVGWIDTH_INDEX
, make_number (rec
.u
.integer
));
280 FT_Done_Face (ft_face
);
284 ASET (entity
, FONT_EXTRA_INDEX
, Fcopy_sequence (extra
));
285 font_put_extra (entity
, QCfont_entity
, key
);
290 static Lisp_Object ftfont_generic_family_list
;
293 ftfont_resolve_generic_family (Lisp_Object family
, FcPattern
*pattern
)
300 family
= Fintern (Fdowncase (SYMBOL_NAME (family
)), Qnil
);
301 if (EQ (family
, Qmono
))
303 else if (EQ (family
, Qsans
) || EQ (family
, Qsans__serif
))
304 family
= Qsans_serif
;
305 slot
= assq_no_quit (family
, ftfont_generic_family_list
);
308 if (! EQ (XCDR (slot
), Qt
))
310 pattern
= FcPatternDuplicate (pattern
);
313 FcPatternDel (pattern
, FC_FOUNDRY
);
314 FcPatternDel (pattern
, FC_FAMILY
);
315 FcPatternAddString (pattern
, FC_FAMILY
, SYMBOL_FcChar8 (family
));
316 if (FcPatternGetLangSet (pattern
, FC_LANG
, 0, &langset
) != FcResultMatch
)
318 /* This is to avoid the effect of locale. */
319 static const FcChar8 lang
[] = "en";
320 langset
= FcLangSetCreate ();
321 FcLangSetAdd (langset
, lang
);
322 FcPatternAddLangSet (pattern
, FC_LANG
, langset
);
323 FcLangSetDestroy (langset
);
325 FcConfigSubstitute (NULL
, pattern
, FcMatchPattern
);
326 FcDefaultSubstitute (pattern
);
327 match
= FcFontMatch (NULL
, pattern
, &result
);
332 if (FcPatternGetString (match
, FC_FAMILY
, 0, &fam
) == FcResultMatch
)
333 family
= intern ((char *) fam
);
337 XSETCDR (slot
, family
);
338 if (match
) FcPatternDestroy (match
);
340 if (pattern
) FcPatternDestroy (pattern
);
344 struct ftfont_cache_data
347 FcCharSet
*fc_charset
;
351 ftfont_lookup_cache (Lisp_Object key
, enum ftfont_cache_for cache_for
)
353 Lisp_Object cache
, val
, entity
;
354 struct ftfont_cache_data
*cache_data
;
356 if (FONT_ENTITY_P (key
))
359 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
360 eassert (CONSP (val
));
366 if (NILP (ft_face_cache
))
369 cache
= Fgethash (key
, ft_face_cache
, Qnil
);
372 if (NILP (ft_face_cache
))
373 ft_face_cache
= CALLN (Fmake_hash_table
, QCtest
, Qequal
);
374 cache_data
= xmalloc (sizeof *cache_data
);
375 cache_data
->ft_face
= NULL
;
376 cache_data
->fc_charset
= NULL
;
377 val
= make_save_ptr_int (cache_data
, 0);
378 cache
= Fcons (Qnil
, val
);
379 Fputhash (key
, cache
, ft_face_cache
);
384 cache_data
= XSAVE_POINTER (val
, 0);
387 if (cache_for
== FTFONT_CACHE_FOR_ENTITY
)
390 if (cache_for
== FTFONT_CACHE_FOR_FACE
391 ? ! cache_data
->ft_face
: ! cache_data
->fc_charset
)
393 char *filename
= SSDATA (XCAR (key
));
394 int idx
= XINT (XCDR (key
));
396 if (cache_for
== FTFONT_CACHE_FOR_FACE
)
399 && FT_Init_FreeType (&ft_library
) != 0)
401 if (FT_New_Face (ft_library
, filename
, idx
, &cache_data
->ft_face
)
407 FcPattern
*pat
= NULL
;
408 FcFontSet
*fontset
= NULL
;
409 FcObjectSet
*objset
= NULL
;
410 FcCharSet
*charset
= NULL
;
412 pat
= FcPatternBuild (0, FC_FILE
, FcTypeString
, (FcChar8
*) filename
,
413 FC_INDEX
, FcTypeInteger
, idx
, NULL
);
416 objset
= FcObjectSetBuild (FC_CHARSET
, FC_STYLE
, NULL
);
419 fontset
= FcFontList (NULL
, pat
, objset
);
422 if (fontset
&& fontset
->nfont
> 0
423 && (FcPatternGetCharSet (fontset
->fonts
[0], FC_CHARSET
, 0,
426 cache_data
->fc_charset
= FcCharSetCopy (charset
);
428 cache_data
->fc_charset
= FcCharSetCreate ();
432 FcFontSetDestroy (fontset
);
434 FcObjectSetDestroy (objset
);
436 FcPatternDestroy (pat
);
443 ftfont_get_fc_charset (Lisp_Object entity
)
445 Lisp_Object val
, cache
;
446 struct ftfont_cache_data
*cache_data
;
448 cache
= ftfont_lookup_cache (entity
, FTFONT_CACHE_FOR_CHARSET
);
450 cache_data
= XSAVE_POINTER (val
, 0);
451 return cache_data
->fc_charset
;
456 ftfont_get_otf (struct ftfont_info
*ftfont_info
)
460 if (ftfont_info
->otf
)
461 return ftfont_info
->otf
;
462 if (! ftfont_info
->maybe_otf
)
464 otf
= OTF_open_ft_face (ftfont_info
->ft_size
->face
);
465 if (! otf
|| OTF_get_table (otf
, "head") < 0)
469 ftfont_info
->maybe_otf
= 0;
472 ftfont_info
->otf
= otf
;
475 #endif /* HAVE_LIBOTF */
478 ftfont_get_cache (struct frame
*f
)
480 return freetype_font_cache
;
484 ftfont_get_charset (Lisp_Object registry
)
486 char *str
= SSDATA (SYMBOL_NAME (registry
));
488 char *re
= SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry
)) * 2 + 1);
491 for (i
= j
= 0; i
< SBYTES (SYMBOL_NAME (registry
)); i
++, j
++)
495 else if (str
[i
] == '*')
502 AUTO_STRING_WITH_LEN (regexp
, re
, j
);
503 for (i
= 0; fc_charset_table
[i
].name
; i
++)
504 if (fast_c_string_match_ignore_case
505 (regexp
, fc_charset_table
[i
].name
,
506 strlen (fc_charset_table
[i
].name
)) >= 0)
509 if (! fc_charset_table
[i
].name
)
511 if (! fc_charset_table
[i
].fc_charset
)
513 FcCharSet
*charset
= FcCharSetCreate ();
514 int *uniquifier
= fc_charset_table
[i
].uniquifier
;
518 for (j
= 0; uniquifier
[j
]; j
++)
519 if (! FcCharSetAddChar (charset
, uniquifier
[j
]))
521 FcCharSetDestroy (charset
);
524 fc_charset_table
[i
].fc_charset
= charset
;
532 unsigned int script_tag
, langsys_tag
;
534 unsigned int *features
[2];
537 #define OTF_SYM_TAG(SYM, TAG) \
539 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
540 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
543 #define OTF_TAG_STR(TAG, P) \
545 (P)[0] = (char) (TAG >> 24); \
546 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
547 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
548 (P)[3] = (char) (TAG & 0xFF); \
553 #define OTF_TAG_SYM(SYM, TAG) \
557 OTF_TAG_STR (TAG, str); \
558 (SYM) = font_intern_prop (str, 4, 1); \
563 static struct OpenTypeSpec
*
564 ftfont_get_open_type_spec (Lisp_Object otf_spec
)
566 struct OpenTypeSpec
*spec
= malloc (sizeof *spec
);
573 spec
->script
= XCAR (otf_spec
);
574 if (! NILP (spec
->script
))
576 OTF_SYM_TAG (spec
->script
, spec
->script_tag
);
577 val
= assq_no_quit (spec
->script
, Votf_script_alist
);
578 if (CONSP (val
) && SYMBOLP (XCDR (val
)))
579 spec
->script
= XCDR (val
);
584 spec
->script_tag
= 0x44464C54; /* "DFLT" */
585 otf_spec
= XCDR (otf_spec
);
586 spec
->langsys_tag
= 0;
587 if (! NILP (otf_spec
))
589 val
= XCAR (otf_spec
);
591 OTF_SYM_TAG (val
, spec
->langsys_tag
);
592 otf_spec
= XCDR (otf_spec
);
594 spec
->nfeatures
[0] = spec
->nfeatures
[1] = 0;
595 for (i
= 0; i
< 2 && ! NILP (otf_spec
); i
++, otf_spec
= XCDR (otf_spec
))
599 val
= XCAR (otf_spec
);
604 (min (PTRDIFF_MAX
, SIZE_MAX
) / sizeof (int) < XINT (len
)
606 : malloc (XINT (len
) * sizeof *spec
->features
[i
]));
607 if (! spec
->features
[i
])
609 if (i
> 0 && spec
->features
[0])
610 free (spec
->features
[0]);
614 for (j
= 0, negative
= 0; CONSP (val
); val
= XCDR (val
))
616 if (NILP (XCAR (val
)))
622 OTF_SYM_TAG (XCAR (val
), tag
);
623 spec
->features
[i
][j
++] = negative
? tag
& 0x80000000 : tag
;
626 spec
->nfeatures
[i
] = j
;
632 ftfont_spec_pattern (Lisp_Object spec
, char *otlayout
, struct OpenTypeSpec
**otspec
, const char **langname
)
634 Lisp_Object tmp
, extra
;
635 FcPattern
*pattern
= NULL
;
636 FcCharSet
*charset
= NULL
;
637 FcLangSet
*langset
= NULL
;
641 Lisp_Object script
= Qnil
;
642 Lisp_Object registry
;
645 if ((n
= FONT_SLANT_NUMERIC (spec
)) >= 0
647 /* Fontconfig doesn't support reverse-italic/oblique. */
650 if (INTEGERP (AREF (spec
, FONT_DPI_INDEX
)))
651 dpi
= XINT (AREF (spec
, FONT_DPI_INDEX
));
652 if (INTEGERP (AREF (spec
, FONT_AVGWIDTH_INDEX
))
653 && XINT (AREF (spec
, FONT_AVGWIDTH_INDEX
)) == 0)
656 registry
= AREF (spec
, FONT_REGISTRY_INDEX
);
658 || EQ (registry
, Qascii_0
)
659 || EQ (registry
, Qiso10646_1
)
660 || EQ (registry
, Qunicode_bmp
))
666 fc_charset_idx
= ftfont_get_charset (registry
);
667 if (fc_charset_idx
< 0)
669 charset
= fc_charset_table
[fc_charset_idx
].fc_charset
;
670 *langname
= fc_charset_table
[fc_charset_idx
].lang
;
671 lang
= (FcChar8
*) *langname
;
674 langset
= FcLangSetCreate ();
677 FcLangSetAdd (langset
, lang
);
682 for (extra
= AREF (spec
, FONT_EXTRA_INDEX
);
683 CONSP (extra
); extra
= XCDR (extra
))
685 Lisp_Object key
, val
;
687 key
= XCAR (XCAR (extra
)), val
= XCDR (XCAR (extra
));
693 else if (EQ (key
, QClang
))
696 langset
= FcLangSetCreate ();
701 if (! FcLangSetAdd (langset
, SYMBOL_FcChar8 (val
)))
705 for (; CONSP (val
); val
= XCDR (val
))
706 if (SYMBOLP (XCAR (val
))
707 && ! FcLangSetAdd (langset
, SYMBOL_FcChar8 (XCAR (val
))))
710 else if (EQ (key
, QCotf
))
714 *otspec
= ftfont_get_open_type_spec (val
);
717 strcpy (otlayout
, "otlayout:");
718 OTF_TAG_STR ((*otspec
)->script_tag
, otlayout
+ 9);
719 script
= (*otspec
)->script
;
722 else if (EQ (key
, QCscript
))
724 else if (EQ (key
, QCscalable
))
725 scalable
= ! NILP (val
);
728 if (! NILP (script
) && ! charset
)
730 Lisp_Object chars
= assq_no_quit (script
, Vscript_representative_chars
);
732 if (CONSP (chars
) && CONSP (CDR (chars
)))
734 charset
= FcCharSetCreate ();
737 for (chars
= XCDR (chars
); CONSP (chars
); chars
= XCDR (chars
))
738 if (CHARACTERP (XCAR (chars
))
739 && ! FcCharSetAddChar (charset
, XFASTINT (XCAR (chars
))))
744 pattern
= FcPatternCreate ();
747 tmp
= AREF (spec
, FONT_FOUNDRY_INDEX
);
749 && ! FcPatternAddString (pattern
, FC_FOUNDRY
, SYMBOL_FcChar8 (tmp
)))
751 tmp
= AREF (spec
, FONT_FAMILY_INDEX
);
753 && ! FcPatternAddString (pattern
, FC_FAMILY
, SYMBOL_FcChar8 (tmp
)))
756 && ! FcPatternAddCharSet (pattern
, FC_CHARSET
, charset
))
759 && ! FcPatternAddLangSet (pattern
, FC_LANG
, langset
))
762 && ! FcPatternAddDouble (pattern
, FC_DPI
, dpi
))
765 && ! FcPatternAddBool (pattern
, FC_SCALABLE
, scalable
? FcTrue
: FcFalse
))
767 #if defined HAVE_XFT && defined FC_COLOR
768 /* We really don't like color fonts, they cause Xft crashes. See
770 if (Vxft_ignore_color_fonts
771 && ! FcPatternAddBool (pattern
, FC_COLOR
, FcFalse
))
778 /* We come here because of unexpected error in fontconfig API call
779 (usually insufficient memory). */
782 FcPatternDestroy (pattern
);
787 if ((*otspec
)->nfeatures
[0] > 0)
788 free ((*otspec
)->features
[0]);
789 if ((*otspec
)->nfeatures
[1] > 0)
790 free ((*otspec
)->features
[1]);
796 if (langset
) FcLangSetDestroy (langset
);
797 if (charset
&& fc_charset_idx
< 0) FcCharSetDestroy (charset
);
802 ftfont_list (struct frame
*f
, Lisp_Object spec
)
804 Lisp_Object val
= Qnil
, family
, adstyle
;
807 FcFontSet
*fontset
= NULL
;
808 FcObjectSet
*objset
= NULL
;
810 Lisp_Object chars
= Qnil
;
811 char otlayout
[15]; /* For "otlayout:XXXX" */
812 struct OpenTypeSpec
*otspec
= NULL
;
814 const char *langname
= NULL
;
816 if (! fc_initialized
)
822 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
825 if (FcPatternGetCharSet (pattern
, FC_CHARSET
, 0, &charset
) != FcResultMatch
)
827 val
= assq_no_quit (QCscript
, AREF (spec
, FONT_EXTRA_INDEX
));
830 val
= assq_no_quit (XCDR (val
), Vscript_representative_chars
);
831 if (CONSP (val
) && VECTORP (XCDR (val
)))
836 if (INTEGERP (AREF (spec
, FONT_SPACING_INDEX
)))
837 spacing
= XINT (AREF (spec
, FONT_SPACING_INDEX
));
838 family
= AREF (spec
, FONT_FAMILY_INDEX
);
841 Lisp_Object resolved
;
843 resolved
= ftfont_resolve_generic_family (family
, pattern
);
844 if (! NILP (resolved
))
846 FcPatternDel (pattern
, FC_FAMILY
);
847 if (! FcPatternAddString (pattern
, FC_FAMILY
,
848 SYMBOL_FcChar8 (resolved
)))
852 adstyle
= AREF (spec
, FONT_ADSTYLE_INDEX
);
853 if (! NILP (adstyle
) && SBYTES (SYMBOL_NAME (adstyle
)) == 0)
855 objset
= FcObjectSetBuild (FC_FOUNDRY
, FC_FAMILY
, FC_WEIGHT
, FC_SLANT
,
856 FC_WIDTH
, FC_PIXEL_SIZE
, FC_SPACING
, FC_SCALABLE
,
857 FC_STYLE
, FC_FILE
, FC_INDEX
,
860 #endif /* FC_CAPABILITY */
868 FcObjectSetAdd (objset
, FC_CHARSET
);
870 fontset
= FcFontList (NULL
, pattern
, objset
);
871 if (! fontset
|| fontset
->nfont
== 0)
874 /* Need fix because this finds any fonts. */
875 if (fontset
->nfont
== 0 && ! NILP (family
))
877 /* Try matching with configuration. For instance, the
878 configuration may specify "Nimbus Mono L" as an alias of
880 FcPattern
*pat
= FcPatternBuild (0, FC_FAMILY
, FcTypeString
,
881 SYMBOL_FcChar8 (family
), NULL
);
884 if (FcConfigSubstitute (NULL
, pat
, FcMatchPattern
) == FcTrue
)
887 FcPatternGetString (pat
, FC_FAMILY
, i
, &fam
) == FcResultMatch
;
890 FcPatternDel (pattern
, FC_FAMILY
);
891 FcPatternAddString (pattern
, FC_FAMILY
, fam
);
892 FcFontSetDestroy (fontset
);
893 fontset
= FcFontList (NULL
, pattern
, objset
);
894 if (fontset
&& fontset
->nfont
> 0)
900 for (i
= 0; i
< fontset
->nfont
; i
++)
908 if ((FcPatternGetInteger (fontset
->fonts
[i
], FC_SPACING
, 0, &this)
919 if (FcPatternGetString (fontset
->fonts
[i
], FC_CAPABILITY
, 0, &this)
921 || ! strstr ((char *) this, otlayout
))
924 #endif /* FC_CAPABILITY */
932 if (FcPatternGetString (fontset
->fonts
[i
], FC_FILE
, 0, &file
)
935 otf
= OTF_open ((char *) file
);
938 passed
= (OTF_check_features (otf
, 1, otspec
->script_tag
,
941 otspec
->nfeatures
[0]) == 1
942 && OTF_check_features (otf
, 0, otspec
->script_tag
,
945 otspec
->nfeatures
[1]) == 1);
950 #endif /* HAVE_LIBOTF */
955 if (FcPatternGetCharSet (fontset
->fonts
[i
], FC_CHARSET
, 0, &charset
)
958 for (j
= 0; j
< ASIZE (chars
); j
++)
959 if (TYPE_RANGED_INTEGERP (FcChar32
, AREF (chars
, j
))
960 && FcCharSetHasChar (charset
, XFASTINT (AREF (chars
, j
))))
962 if (j
== ASIZE (chars
))
965 if (! NILP (adstyle
) || langname
)
967 Lisp_Object this_adstyle
= get_adstyle_property (fontset
->fonts
[i
]);
970 && (NILP (this_adstyle
)
971 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle
)),
972 SSDATA (SYMBOL_NAME (this_adstyle
))) != 0))
975 && ! NILP (this_adstyle
)
976 && xstrcasecmp (langname
, SSDATA (SYMBOL_NAME (this_adstyle
))))
979 entity
= ftfont_pattern_entity (fontset
->fonts
[i
],
980 AREF (spec
, FONT_EXTRA_INDEX
));
982 val
= Fcons (entity
, val
);
984 val
= Fnreverse (val
);
988 /* We come here because of unexpected error in fontconfig API call
989 (usually insufficient memory). */
993 FONT_ADD_LOG ("ftfont-list", spec
, val
);
994 if (objset
) FcObjectSetDestroy (objset
);
995 if (fontset
) FcFontSetDestroy (fontset
);
996 if (pattern
) FcPatternDestroy (pattern
);
1001 ftfont_match (struct frame
*f
, Lisp_Object spec
)
1003 Lisp_Object entity
= Qnil
;
1004 FcPattern
*pattern
, *match
= NULL
;
1006 char otlayout
[15]; /* For "otlayout:XXXX" */
1007 struct OpenTypeSpec
*otspec
= NULL
;
1008 const char *langname
= NULL
;
1010 if (! fc_initialized
)
1016 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
1020 if (INTEGERP (AREF (spec
, FONT_SIZE_INDEX
)))
1024 value
.type
= FcTypeDouble
;
1025 value
.u
.d
= XINT (AREF (spec
, FONT_SIZE_INDEX
));
1026 FcPatternAdd (pattern
, FC_PIXEL_SIZE
, value
, FcFalse
);
1028 if (FcConfigSubstitute (NULL
, pattern
, FcMatchPattern
) == FcTrue
)
1030 FcDefaultSubstitute (pattern
);
1031 match
= FcFontMatch (NULL
, pattern
, &result
);
1034 entity
= ftfont_pattern_entity (match
, AREF (spec
, FONT_EXTRA_INDEX
));
1035 FcPatternDestroy (match
);
1036 if (! NILP (AREF (spec
, FONT_FAMILY_INDEX
))
1037 && NILP (assq_no_quit (AREF (spec
, FONT_FAMILY_INDEX
),
1038 ftfont_generic_family_list
))
1039 && NILP (Fstring_equal (AREF (spec
, FONT_FAMILY_INDEX
),
1040 AREF (entity
, FONT_FAMILY_INDEX
))))
1044 FcPatternDestroy (pattern
);
1046 FONT_ADD_LOG ("ftfont-match", spec
, entity
);
1051 ftfont_list_family (struct frame
*f
)
1053 Lisp_Object list
= Qnil
;
1054 FcPattern
*pattern
= NULL
;
1055 FcFontSet
*fontset
= NULL
;
1056 FcObjectSet
*objset
= NULL
;
1059 if (! fc_initialized
)
1065 pattern
= FcPatternCreate ();
1068 objset
= FcObjectSetBuild (FC_FAMILY
, NULL
);
1071 fontset
= FcFontList (NULL
, pattern
, objset
);
1075 for (i
= 0; i
< fontset
->nfont
; i
++)
1077 FcPattern
*pat
= fontset
->fonts
[i
];
1080 if (FcPatternGetString (pat
, FC_FAMILY
, 0, &str
) == FcResultMatch
)
1081 list
= Fcons (intern ((char *) str
), list
);
1085 if (objset
) FcObjectSetDestroy (objset
);
1086 if (fontset
) FcFontSetDestroy (fontset
);
1087 if (pattern
) FcPatternDestroy (pattern
);
1094 ftfont_open2 (struct frame
*f
,
1097 Lisp_Object font_object
)
1099 struct ftfont_info
*ftfont_info
;
1101 struct ftfont_cache_data
*cache_data
;
1105 Lisp_Object val
, filename
, idx
, cache
;
1111 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
1115 cache
= ftfont_lookup_cache (entity
, FTFONT_CACHE_FOR_FACE
);
1118 filename
= XCAR (val
);
1121 cache_data
= XSAVE_POINTER (XCDR (cache
), 0);
1122 ft_face
= cache_data
->ft_face
;
1123 if (XSAVE_INTEGER (val
, 1) > 0)
1125 /* FT_Face in this cache is already used by the different size. */
1126 if (FT_New_Size (ft_face
, &ft_size
) != 0)
1128 if (FT_Activate_Size (ft_size
) != 0)
1130 FT_Done_Size (ft_size
);
1134 set_save_integer (val
, 1, XSAVE_INTEGER (val
, 1) + 1);
1135 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
1138 if (FT_Set_Pixel_Sizes (ft_face
, size
, size
) != 0)
1140 if (XSAVE_INTEGER (val
, 1) == 0)
1141 FT_Done_Face (ft_face
);
1145 ASET (font_object
, FONT_FILE_INDEX
, filename
);
1146 font
= XFONT_OBJECT (font_object
);
1147 ftfont_info
= (struct ftfont_info
*) font
;
1148 ftfont_info
->ft_size
= ft_face
->size
;
1149 ftfont_info
->index
= XINT (idx
);
1151 ftfont_info
->maybe_otf
= (ft_face
->face_flags
& FT_FACE_FLAG_SFNT
) != 0;
1152 ftfont_info
->otf
= NULL
;
1153 #endif /* HAVE_LIBOTF */
1154 /* This means that there's no need of transformation. */
1155 ftfont_info
->matrix
.xx
= 0;
1156 font
->pixel_size
= size
;
1157 font
->driver
= &ftfont_driver
;
1158 font
->encoding_charset
= font
->repertory_charset
= -1;
1160 upEM
= ft_face
->units_per_EM
;
1161 scalable
= (INTEGERP (AREF (entity
, FONT_AVGWIDTH_INDEX
))
1162 && XINT (AREF (entity
, FONT_AVGWIDTH_INDEX
)) == 0);
1165 font
->ascent
= ft_face
->ascender
* size
/ upEM
+ 0.5;
1166 font
->descent
= - ft_face
->descender
* size
/ upEM
+ 0.5;
1167 font
->height
= ft_face
->height
* size
/ upEM
+ 0.5;
1171 font
->ascent
= ft_face
->size
->metrics
.ascender
>> 6;
1172 font
->descent
= - ft_face
->size
->metrics
.descender
>> 6;
1173 font
->height
= ft_face
->size
->metrics
.height
>> 6;
1175 if (INTEGERP (AREF (entity
, FONT_SPACING_INDEX
)))
1176 spacing
= XINT (AREF (entity
, FONT_SPACING_INDEX
));
1178 spacing
= FC_PROPORTIONAL
;
1179 if (spacing
!= FC_PROPORTIONAL
1181 && spacing
!= FC_DUAL
1182 #endif /* FC_DUAL */
1184 font
->min_width
= font
->average_width
= font
->space_width
1185 = (scalable
? ft_face
->max_advance_width
* size
/ upEM
+ 0.5
1186 : ft_face
->size
->metrics
.max_advance
>> 6);
1191 font
->min_width
= font
->average_width
= font
->space_width
= 0;
1192 for (i
= 32, n
= 0; i
< 127; i
++)
1193 if (FT_Load_Char (ft_face
, i
, FT_LOAD_DEFAULT
) == 0)
1195 int this_width
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1198 && (! font
->min_width
|| font
->min_width
> this_width
))
1199 font
->min_width
= this_width
;
1201 font
->space_width
= this_width
;
1202 font
->average_width
+= this_width
;
1206 font
->average_width
/= n
;
1209 font
->baseline_offset
= 0;
1210 font
->relative_compose
= 0;
1211 font
->default_ascent
= 0;
1212 font
->vertical_centering
= 0;
1215 font
->underline_position
= (-ft_face
->underline_position
* size
/ upEM
1217 font
->underline_thickness
= (ft_face
->underline_thickness
* size
/ upEM
1222 font
->underline_position
= -1;
1223 font
->underline_thickness
= 0;
1230 ftfont_open (struct frame
*f
, Lisp_Object entity
, int pixel_size
)
1232 Lisp_Object font_object
;
1234 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
1237 font_object
= font_build_object (VECSIZE (struct ftfont_info
),
1238 Qfreetype
, entity
, size
);
1239 return ftfont_open2 (f
, entity
, pixel_size
, font_object
);
1243 ftfont_close (struct font
*font
)
1245 /* FIXME: Although this function can be called while garbage-collecting,
1246 the function assumes that Lisp data structures are properly-formed.
1247 This invalid assumption can lead to core dumps (Bug#20890). */
1249 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1250 Lisp_Object val
, cache
;
1252 val
= Fcons (font
->props
[FONT_FILE_INDEX
], make_number (ftfont_info
->index
));
1253 cache
= ftfont_lookup_cache (val
, FTFONT_CACHE_FOR_FACE
);
1254 eassert (CONSP (cache
));
1256 set_save_integer (val
, 1, XSAVE_INTEGER (val
, 1) - 1);
1257 if (XSAVE_INTEGER (val
, 1) == 0)
1259 struct ftfont_cache_data
*cache_data
= XSAVE_POINTER (val
, 0);
1261 FT_Done_Face (cache_data
->ft_face
);
1263 if (ftfont_info
->otf
)
1264 OTF_close (ftfont_info
->otf
);
1266 cache_data
->ft_face
= NULL
;
1269 FT_Done_Size (ftfont_info
->ft_size
);
1273 ftfont_has_char (Lisp_Object font
, int c
)
1275 struct charset
*cs
= NULL
;
1277 if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qja
)
1278 && charset_jisx0208
>= 0)
1279 cs
= CHARSET_FROM_ID (charset_jisx0208
);
1280 else if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qko
)
1281 && charset_ksc5601
>= 0)
1282 cs
= CHARSET_FROM_ID (charset_ksc5601
);
1284 return (ENCODE_CHAR (cs
, c
) != CHARSET_INVALID_CODE (cs
));
1286 if (FONT_ENTITY_P (font
))
1288 FcCharSet
*charset
= ftfont_get_fc_charset (font
);
1290 return (FcCharSetHasChar (charset
, c
) == FcTrue
);
1294 struct ftfont_info
*ftfont_info
;
1296 ftfont_info
= (struct ftfont_info
*) XFONT_OBJECT (font
);
1297 return (FT_Get_Char_Index (ftfont_info
->ft_size
->face
, (FT_ULong
) c
)
1303 ftfont_encode_char (struct font
*font
, int c
)
1305 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1306 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1307 FT_ULong charcode
= c
;
1308 FT_UInt code
= FT_Get_Char_Index (ft_face
, charcode
);
1310 return (code
> 0 ? code
: FONT_INVALID_CODE
);
1314 ftfont_text_extents (struct font
*font
, unsigned int *code
,
1315 int nglyphs
, struct font_metrics
*metrics
)
1317 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1318 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1322 if (ftfont_info
->ft_size
!= ft_face
->size
)
1323 FT_Activate_Size (ftfont_info
->ft_size
);
1325 for (i
= 0, first
= 1; i
< nglyphs
; i
++)
1327 if (FT_Load_Glyph (ft_face
, code
[i
], FT_LOAD_DEFAULT
) == 0)
1329 FT_Glyph_Metrics
*m
= &ft_face
->glyph
->metrics
;
1333 metrics
->lbearing
= m
->horiBearingX
>> 6;
1334 metrics
->rbearing
= (m
->horiBearingX
+ m
->width
) >> 6;
1335 metrics
->ascent
= m
->horiBearingY
>> 6;
1336 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1339 if (metrics
->lbearing
> width
+ (m
->horiBearingX
>> 6))
1340 metrics
->lbearing
= width
+ (m
->horiBearingX
>> 6);
1341 if (metrics
->rbearing
1342 < width
+ ((m
->horiBearingX
+ m
->width
) >> 6))
1344 = width
+ ((m
->horiBearingX
+ m
->width
) >> 6);
1345 if (metrics
->ascent
< (m
->horiBearingY
>> 6))
1346 metrics
->ascent
= m
->horiBearingY
>> 6;
1347 if (metrics
->descent
> ((m
->height
- m
->horiBearingY
) >> 6))
1348 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1349 width
+= m
->horiAdvance
>> 6;
1352 width
+= font
->space_width
;
1354 metrics
->width
= width
;
1358 ftfont_get_bitmap (struct font
*font
, unsigned int code
, struct font_bitmap
*bitmap
, int bits_per_pixel
)
1360 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1361 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1362 FT_Int32 load_flags
= FT_LOAD_RENDER
;
1364 if (ftfont_info
->ft_size
!= ft_face
->size
)
1365 FT_Activate_Size (ftfont_info
->ft_size
);
1366 if (bits_per_pixel
== 1)
1368 #ifdef FT_LOAD_TARGET_MONO
1369 load_flags
|= FT_LOAD_TARGET_MONO
;
1371 load_flags
|= FT_LOAD_MONOCHROME
;
1374 else if (bits_per_pixel
!= 8)
1375 /* We don't support such a rendering. */
1378 if (FT_Load_Glyph (ft_face
, code
, load_flags
) != 0)
1380 bitmap
->bits_per_pixel
1381 = (ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_MONO
? 1
1382 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
? 8
1383 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD
? 8
1384 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD_V
? 8
1386 if (bitmap
->bits_per_pixel
< 0)
1387 /* We don't support that kind of pixel mode. */
1389 bitmap
->rows
= ft_face
->glyph
->bitmap
.rows
;
1390 bitmap
->width
= ft_face
->glyph
->bitmap
.width
;
1391 bitmap
->pitch
= ft_face
->glyph
->bitmap
.pitch
;
1392 bitmap
->buffer
= ft_face
->glyph
->bitmap
.buffer
;
1393 bitmap
->left
= ft_face
->glyph
->bitmap_left
;
1394 bitmap
->top
= ft_face
->glyph
->bitmap_top
;
1395 bitmap
->advance
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1401 ftfont_anchor_point (struct font
*font
, unsigned int code
, int idx
,
1404 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1405 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1407 if (ftfont_info
->ft_size
!= ft_face
->size
)
1408 FT_Activate_Size (ftfont_info
->ft_size
);
1409 if (FT_Load_Glyph (ft_face
, code
, FT_LOAD_DEFAULT
) != 0)
1411 if (ft_face
->glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
1413 if (idx
>= ft_face
->glyph
->outline
.n_points
)
1415 *x
= ft_face
->glyph
->outline
.points
[idx
].x
;
1416 *y
= ft_face
->glyph
->outline
.points
[idx
].y
;
1423 ftfont_otf_features (OTF_GSUB_GPOS
*gsub_gpos
)
1425 Lisp_Object scripts
, langsyses
, features
, sym
;
1428 for (scripts
= Qnil
, i
= gsub_gpos
->ScriptList
.ScriptCount
- 1; i
>= 0; i
--)
1430 OTF_Script
*otf_script
= gsub_gpos
->ScriptList
.Script
+ i
;
1432 for (langsyses
= Qnil
, j
= otf_script
->LangSysCount
- 1; j
>= -1; j
--)
1434 OTF_LangSys
*otf_langsys
;
1437 otf_langsys
= otf_script
->LangSys
+ j
;
1438 else if (otf_script
->DefaultLangSysOffset
)
1439 otf_langsys
= &otf_script
->DefaultLangSys
;
1443 for (features
= Qnil
, k
= otf_langsys
->FeatureCount
- 1; k
>= 0; k
--)
1445 l
= otf_langsys
->FeatureIndex
[k
];
1446 if (l
>= gsub_gpos
->FeatureList
.FeatureCount
)
1448 OTF_TAG_SYM (sym
, gsub_gpos
->FeatureList
.Feature
[l
].FeatureTag
);
1449 features
= Fcons (sym
, features
);
1452 OTF_TAG_SYM (sym
, otf_script
->LangSysRecord
[j
].LangSysTag
);
1455 langsyses
= Fcons (Fcons (sym
, features
), langsyses
);
1458 OTF_TAG_SYM (sym
, gsub_gpos
->ScriptList
.Script
[i
].ScriptTag
);
1459 scripts
= Fcons (Fcons (sym
, langsyses
), scripts
);
1467 ftfont_otf_capability (struct font
*font
)
1469 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1470 OTF
*otf
= ftfont_get_otf (ftfont_info
);
1471 Lisp_Object gsub_gpos
;
1475 gsub_gpos
= Fcons (Qnil
, Qnil
);
1476 if (OTF_get_table (otf
, "GSUB") == 0
1477 && otf
->gsub
->FeatureList
.FeatureCount
> 0)
1478 XSETCAR (gsub_gpos
, ftfont_otf_features (otf
->gsub
));
1479 if (OTF_get_table (otf
, "GPOS") == 0
1480 && otf
->gpos
->FeatureList
.FeatureCount
> 0)
1481 XSETCDR (gsub_gpos
, ftfont_otf_features (otf
->gpos
));
1485 #ifdef HAVE_M17N_FLT
1487 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1488 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1489 /* We can use the new feature of libotf and m17n-flt to handle the
1490 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1491 some Agian scripts. */
1492 #define M17N_FLT_USE_NEW_FEATURE
1504 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1505 We use this structure instead of MFLTGlyph to utilize the new
1506 feature of libotf ver.0.9.15 which requires saving and restoring
1507 the value of OTF_GlyphString.positioning_type in the succeeding
1508 calls of the callback function MFLTFont.drive_otf (which is set to
1509 ftfont_drive_otf). */
1513 unsigned int libotf_positioning_type
;
1517 ftfont_get_glyph_id (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1520 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1521 FT_Face ft_face
= flt_font_ft
->ft_face
;
1524 for (g
= (MFLTGlyphFT
*) (gstring
->glyphs
) + from
; from
< to
; g
++, from
++)
1527 FT_UInt code
= FT_Get_Char_Index (ft_face
, g
->g
.code
);
1529 g
->g
.code
= code
> 0 ? code
: FONT_INVALID_CODE
;
1535 /* Operators for 26.6 fixed fractional pixel format */
1537 #define FLOOR(x) ((x) & -64)
1538 #define CEIL(x) (((x)+63) & -64)
1539 #define ROUND(x) (((x)+32) & -64)
1542 ftfont_get_metrics (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1545 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1546 FT_Face ft_face
= flt_font_ft
->ft_face
;
1549 for (g
= (MFLTGlyphFT
*) (gstring
->glyphs
) + from
; from
< to
; g
++, from
++)
1550 if (! g
->g
.measured
)
1552 if (g
->g
.code
!= FONT_INVALID_CODE
)
1554 FT_Glyph_Metrics
*m
;
1556 if (FT_Load_Glyph (ft_face
, g
->g
.code
, FT_LOAD_DEFAULT
) != 0
1557 && FT_Load_Glyph (ft_face
, g
->g
.code
, FT_LOAD_NO_HINTING
) != 0)
1559 m
= &ft_face
->glyph
->metrics
;
1560 if (flt_font_ft
->matrix
)
1565 v
[0].x
= v
[1].x
= m
->horiBearingX
;
1566 v
[2].x
= v
[3].x
= m
->horiBearingX
+ m
->width
;
1567 v
[0].y
= v
[2].y
= m
->horiBearingY
;
1568 v
[1].y
= v
[3].y
= m
->horiBearingY
- m
->height
;
1569 for (i
= 0; i
< 4; i
++)
1570 FT_Vector_Transform (v
+ i
, flt_font_ft
->matrix
);
1571 g
->g
.lbearing
= v
[0].x
< v
[1].x
? FLOOR (v
[0].x
) : FLOOR (v
[1].x
);
1572 g
->g
.rbearing
= v
[2].x
> v
[3].x
? CEIL (v
[2].x
) : CEIL (v
[3].x
);
1573 g
->g
.ascent
= v
[0].y
> v
[2].y
? CEIL (v
[0].y
) : CEIL (v
[2].y
);
1574 g
->g
.descent
= v
[1].y
< v
[3].y
? - FLOOR (v
[1].y
) : - FLOOR (v
[3].y
);
1578 g
->g
.lbearing
= FLOOR (m
->horiBearingX
);
1579 g
->g
.rbearing
= CEIL (m
->horiBearingX
+ m
->width
);
1580 g
->g
.ascent
= CEIL (m
->horiBearingY
);
1581 g
->g
.descent
= - FLOOR (m
->horiBearingY
- m
->height
);
1583 g
->g
.xadv
= ROUND (ft_face
->glyph
->advance
.x
);
1588 g
->g
.rbearing
= g
->g
.xadv
= flt_font_ft
->font
->space_width
<< 6;
1589 g
->g
.ascent
= flt_font_ft
->font
->ascent
<< 6;
1590 g
->g
.descent
= flt_font_ft
->font
->descent
<< 6;
1599 ftfont_check_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
)
1601 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1603 #define FEATURE_ANY(IDX) \
1604 (spec->features[IDX] \
1605 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1607 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1608 OTF
*otf
= flt_font_ft
->otf
;
1613 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1614 /* Return true iff any of GSUB or GPOS support the script (and
1617 && (OTF_check_features (otf
, 0, spec
->script
, spec
->langsys
,
1619 || OTF_check_features (otf
, 1, spec
->script
, spec
->langsys
,
1622 for (i
= 0; i
< 2; i
++)
1623 if (! FEATURE_ANY (i
))
1625 if (FEATURE_NONE (i
))
1628 && OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1633 if (spec
->features
[i
][0] == 0xFFFFFFFF)
1636 || OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1642 for (n
= 1; spec
->features
[i
][n
]; n
++);
1644 SAFE_NALLOCA (tags
, 1, n
);
1645 for (n
= 0, negative
= 0; spec
->features
[i
][n
]; n
++)
1647 if (spec
->features
[i
][n
] == 0xFFFFFFFF)
1650 tags
[n
- 1] = spec
->features
[i
][n
] | 0x80000000;
1652 tags
[n
] = spec
->features
[i
][n
];
1655 #ifndef M17N_FLT_USE_NEW_FEATURE
1656 passed
= n
- negative
> 0;
1659 passed
= (OTF_check_features (otf
, i
== 0, spec
->script
,
1660 spec
->langsys
, tags
, n
- negative
)
1671 #define DEVICE_DELTA(table, size) \
1672 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1673 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1677 adjust_anchor (FT_Face ft_face
, OTF_Anchor
*anchor
,
1678 unsigned code
, int x_ppem
, int y_ppem
, int *x
, int *y
)
1680 if (anchor
->AnchorFormat
== 2)
1682 FT_Outline
*outline
;
1683 int ap
= anchor
->f
.f1
.AnchorPoint
;
1685 FT_Load_Glyph (ft_face
, (FT_UInt
) code
, FT_LOAD_MONOCHROME
);
1686 outline
= &ft_face
->glyph
->outline
;
1687 if (ap
< outline
->n_points
)
1689 *x
= outline
->points
[ap
].x
<< 6;
1690 *y
= outline
->points
[ap
].y
<< 6;
1693 else if (anchor
->AnchorFormat
== 3)
1695 if (anchor
->f
.f2
.XDeviceTable
.offset
1696 && anchor
->f
.f2
.XDeviceTable
.DeltaValue
)
1697 *x
+= DEVICE_DELTA (anchor
->f
.f2
.XDeviceTable
, x_ppem
);
1698 if (anchor
->f
.f2
.YDeviceTable
.offset
1699 && anchor
->f
.f2
.YDeviceTable
.DeltaValue
)
1700 *y
+= DEVICE_DELTA (anchor
->f
.f2
.YDeviceTable
, y_ppem
);
1704 static OTF_GlyphString otf_gstring
;
1707 setup_otf_gstring (int size
)
1709 if (otf_gstring
.size
< size
)
1711 ptrdiff_t new_size
= otf_gstring
.size
;
1712 xfree (otf_gstring
.glyphs
);
1713 otf_gstring
.glyphs
= xpalloc (NULL
, &new_size
, size
- otf_gstring
.size
,
1714 INT_MAX
, sizeof *otf_gstring
.glyphs
);
1715 otf_gstring
.size
= new_size
;
1717 otf_gstring
.used
= size
;
1718 memset (otf_gstring
.glyphs
, 0, sizeof (OTF_Glyph
) * size
);
1721 #ifdef M17N_FLT_USE_NEW_FEATURE
1723 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1724 #define PACK_OTF_TAG(TAG) \
1725 ((((TAG) & 0x7F000000) >> 3) \
1726 | (((TAG) & 0x7F0000) >> 2) \
1727 | (((TAG) & 0x7F00) >> 1) \
1730 /* Assuming that FONT is an OpenType font, apply OpenType features
1731 specified in SPEC on glyphs between FROM and TO of IN, and record
1732 the lastly applied feature in each glyph of IN. If OUT is not
1733 NULL, append the resulting glyphs to OUT while storing glyph
1734 position adjustment information in ADJUSTMENT. */
1737 ftfont_drive_otf (MFLTFont
*font
,
1739 MFLTGlyphString
*in
,
1742 MFLTGlyphString
*out
,
1743 MFLTGlyphAdjustment
*adjustment
)
1745 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1746 MFLTGlyphFT
*in_glyphs
= (MFLTGlyphFT
*) (in
->glyphs
) + from
;
1747 MFLTGlyphFT
*out_glyphs
= out
? (MFLTGlyphFT
*) (out
->glyphs
) : NULL
;
1748 FT_Face ft_face
= flt_font_ft
->ft_face
;
1749 OTF
*otf
= flt_font_ft
->otf
;
1750 int len
= to
- from
;
1753 char script
[5], *langsys
= NULL
;
1754 char *gsub_features
= NULL
, *gpos_features
= NULL
;
1755 OTF_Feature
*features
;
1759 OTF_tag_name (spec
->script
, script
);
1764 langsys
= langsysbuf
;
1765 OTF_tag_name (spec
->langsys
, langsys
);
1769 for (i
= 0; i
< 2; i
++)
1773 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
1775 for (j
= 0; spec
->features
[i
][j
]; j
++);
1776 SAFE_NALLOCA (p
, 6, j
);
1781 for (j
= 0; spec
->features
[i
][j
]; j
++)
1783 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
1784 *p
++ = '*', *p
++ = ',';
1787 OTF_tag_name (spec
->features
[i
][j
], p
);
1796 setup_otf_gstring (len
);
1797 for (i
= 0; i
< len
; i
++)
1799 otf_gstring
.glyphs
[i
].c
= in_glyphs
[i
].g
.c
& 0x11FFFF;
1800 otf_gstring
.glyphs
[i
].glyph_id
= in_glyphs
[i
].g
.code
;
1801 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1802 otf_gstring
.glyphs
[i
].positioning_type
= in_glyphs
[i
].libotf_positioning_type
;
1806 OTF_drive_gdef (otf
, &otf_gstring
);
1807 gidx
= out
? out
->used
: from
;
1809 if (gsub_features
&& out
)
1811 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1812 if (OTF_drive_gsub_features (otf
, &otf_gstring
, script
, langsys
,
1816 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1820 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
1825 features
= otf
->gsub
->FeatureList
.Feature
;
1826 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
1829 int min_from
, max_to
;
1832 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1833 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1835 feature_idx
= otfg
->positioning_type
>> 4;
1837 g
= out_glyphs
+ out
->used
;
1838 *g
= in_glyphs
[otfg
->f
.index
.from
];
1839 if (g
->g
.code
!= otfg
->glyph_id
)
1842 g
->g
.code
= otfg
->glyph_id
;
1846 min_from
= g
->g
.from
;
1848 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
1850 /* OTFG substitutes multiple glyphs in IN. */
1851 for (j
= otfg
->f
.index
.from
+ 1; j
<= otfg
->f
.index
.to
; j
++)
1853 if (min_from
> in_glyphs
[j
].g
.from
)
1854 min_from
= in_glyphs
[j
].g
.from
;
1855 if (max_to
< in_glyphs
[j
].g
.to
)
1856 max_to
= in_glyphs
[j
].g
.to
;
1858 g
->g
.from
= min_from
;
1863 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1864 tag
= PACK_OTF_TAG (tag
);
1865 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1867 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1868 g
->libotf_positioning_type
1869 = otfg
->positioning_type
& OTF_positioning_type_components_mask
;
1871 for (i
++, otfg
++; (i
< otf_gstring
.used
1872 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
1875 g
= out_glyphs
+ out
->used
;
1876 *g
= in_glyphs
[otfg
->f
.index
.to
];
1877 if (g
->g
.code
!= otfg
->glyph_id
)
1880 g
->g
.code
= otfg
->glyph_id
;
1883 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1884 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1886 feature_idx
= otfg
->positioning_type
>> 4;
1890 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1891 tag
= PACK_OTF_TAG (tag
);
1892 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1894 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1895 g
->libotf_positioning_type
1896 = otfg
->positioning_type
& OTF_positioning_type_components_mask
;
1902 else if (gsub_features
)
1904 /* Just for checking which features will be applied. */
1905 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1906 if (OTF_drive_gsub_features (otf
, &otf_gstring
, script
, langsys
,
1910 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1914 features
= otf
->gsub
->FeatureList
.Feature
;
1915 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; i
++,
1919 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1920 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1922 feature_idx
= otfg
->positioning_type
>> 4;
1926 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1927 tag
= PACK_OTF_TAG (tag
);
1928 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
1930 MFLTGlyphFT
*g
= in_glyphs
+ j
;
1931 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1938 if (out
->allocated
< out
->used
+ len
)
1943 for (i
= 0; i
< len
; i
++)
1944 out_glyphs
[out
->used
++] = in_glyphs
[i
];
1947 if (gpos_features
&& out
)
1949 MFLTGlyphFT
*base
= NULL
, *mark
= NULL
, *g
;
1950 int x_ppem
, y_ppem
, x_scale
, y_scale
;
1952 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1953 if (OTF_drive_gpos_features (otf
, &otf_gstring
, script
, langsys
,
1960 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
1967 features
= otf
->gpos
->FeatureList
.Feature
;
1968 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
1969 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
1970 x_scale
= ft_face
->size
->metrics
.x_scale
;
1971 y_scale
= ft_face
->size
->metrics
.y_scale
;
1973 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out_glyphs
+ gidx
;
1974 i
< otf_gstring
.used
; i
++, otfg
++)
1976 MFLTGlyphAdjustment
*adjust
= adjustment
;
1978 int positioning_type
, feature_idx
;
1980 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1981 positioning_type
= OTF_POSITIONING_TYPE_GET_FORMAT (otfg
);
1982 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1984 positioning_type
= otfg
->positioning_type
& 0xF;
1985 feature_idx
= otfg
->positioning_type
>> 4;
1989 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1990 tag
= PACK_OTF_TAG (tag
);
1991 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1994 if (! otfg
->glyph_id
)
1995 /* This is a pseudo glyph that contains positioning
1996 information to be accumulated to a real glyph. */
1998 switch (positioning_type
)
2002 case 1: /* Single */
2005 int format
= otfg
->f
.f1
.format
;
2007 if (format
& OTF_XPlacement
)
2009 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
2010 if (format
& OTF_XPlaDevice
)
2012 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
2013 if (format
& OTF_YPlacement
)
2015 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
2016 if (format
& OTF_YPlaDevice
)
2018 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
2019 if (format
& OTF_XAdvance
)
2021 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
2022 if (format
& OTF_XAdvDevice
)
2024 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
2025 if (format
& OTF_YAdvance
)
2027 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
2028 if (format
& OTF_YAdvDevice
)
2030 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
2034 case 3: /* Cursive */
2035 /* Not yet supported. */
2037 case 4: /* Mark-to-Base */
2038 case 5: /* Mark-to-Ligature */
2042 goto label_adjust_anchor
;
2043 default: /* i.e. case 6 Mark-to-Mark */
2047 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2049 int distance
= OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg
);
2053 prev
= g
- distance
;
2054 if (prev
< out_glyphs
)
2060 label_adjust_anchor
:
2062 int base_x
, base_y
, mark_x
, mark_y
;
2063 int this_from
, this_to
;
2065 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
2066 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
2067 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
2068 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
2070 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
2071 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
, prev
->g
.code
,
2072 x_ppem
, y_ppem
, &base_x
, &base_y
);
2073 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
2074 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->g
.code
,
2075 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2076 adjust
->xoff
= (base_x
- mark_x
);
2077 adjust
->yoff
= - (base_y
- mark_y
);
2078 adjust
->back
= (g
- prev
);
2080 adjust
->advance_is_absolute
= 1;
2082 this_from
= g
->g
.from
;
2084 for (j
= 0; prev
+ j
< g
; j
++)
2086 if (this_from
> prev
[j
].g
.from
)
2087 this_from
= prev
[j
].g
.from
;
2088 if (this_to
< prev
[j
].g
.to
)
2089 this_to
= prev
[j
].g
.to
;
2091 for (; prev
<= g
; prev
++)
2093 prev
->g
.from
= this_from
;
2094 prev
->g
.to
= this_to
;
2100 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2102 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2110 else if (gpos_features
)
2112 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
2118 features
= otf
->gpos
->FeatureList
.Feature
;
2119 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
;
2121 if (otfg
->positioning_type
& 0xF)
2123 int feature_idx
= otfg
->positioning_type
>> 4;
2127 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
2128 tag
= PACK_OTF_TAG (tag
);
2129 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
2131 MFLTGlyphFT
*g
= in_glyphs
+ j
;
2132 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
2144 if (out
->allocated
< out
->used
+ len
)
2146 font
->get_metrics (font
, in
, from
, to
);
2147 memcpy (out
->glyphs
+ out
->used
, in_glyphs
, sizeof (MFLTGlyphFT
) * len
);
2153 ftfont_try_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
,
2154 MFLTGlyphString
*in
, int from
, int to
)
2156 return ftfont_drive_otf (font
, spec
, in
, from
, to
, NULL
, NULL
);
2159 #else /* not M17N_FLT_USE_NEW_FEATURE */
2162 ftfont_drive_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
, MFLTGlyphString
*in
,
2164 MFLTGlyphString
*out
, MFLTGlyphAdjustment
*adjustment
)
2166 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
2167 MFLTGlyphFT
*in_glyphs
= (MFLTGlyphFT
*) (in
->glyphs
) + from
;
2168 MFLTGlyphFT
*out_glyphs
= out
? (MFLTGlyphFT
*) (out
->glyphs
) : NULL
;
2169 FT_Face ft_face
= flt_font_ft
->ft_face
;
2170 OTF
*otf
= flt_font_ft
->otf
;
2171 int len
= to
- from
;
2174 char script
[5], *langsys
= NULL
;
2175 char *gsub_features
= NULL
, *gpos_features
= NULL
;
2179 OTF_tag_name (spec
->script
, script
);
2184 langsys
= langsysbuf
;
2185 OTF_tag_name (spec
->langsys
, langsys
);
2189 for (i
= 0; i
< 2; i
++)
2193 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
2195 for (j
= 0; spec
->features
[i
][j
]; j
++);
2196 SAFE_NALLOCA (p
, 6, j
);
2201 for (j
= 0; spec
->features
[i
][j
]; j
++)
2203 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
2204 *p
++ = '*', *p
++ = ',';
2207 OTF_tag_name (spec
->features
[i
][j
], p
);
2216 setup_otf_gstring (len
);
2217 for (i
= 0; i
< len
; i
++)
2219 otf_gstring
.glyphs
[i
].c
= in_glyphs
[i
].g
.c
;
2220 otf_gstring
.glyphs
[i
].glyph_id
= in_glyphs
[i
].g
.code
;
2223 OTF_drive_gdef (otf
, &otf_gstring
);
2228 if (OTF_drive_gsub (otf
, &otf_gstring
, script
, langsys
, gsub_features
)
2231 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
2236 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
2239 int min_from
, max_to
;
2242 g
= out_glyphs
+ out
->used
;
2243 *g
= in_glyphs
[otfg
->f
.index
.from
];
2244 if (g
->g
.code
!= otfg
->glyph_id
)
2247 g
->g
.code
= otfg
->glyph_id
;
2251 min_from
= g
->g
.from
;
2253 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
2255 /* OTFG substitutes multiple glyphs in IN. */
2256 for (j
= from
+ otfg
->f
.index
.from
+ 1;
2257 j
<= from
+ otfg
->f
.index
.to
; j
++)
2259 if (min_from
> in
->glyphs
[j
].from
)
2260 min_from
= in
->glyphs
[j
].from
;
2261 if (max_to
< in
->glyphs
[j
].to
)
2262 max_to
= in
->glyphs
[j
].to
;
2264 g
->g
.from
= min_from
;
2267 for (i
++, otfg
++; (i
< otf_gstring
.used
2268 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
2271 g
= out_glyphs
+ out
->used
;
2272 *g
= in_glyphs
[otfg
->f
.index
.to
];
2273 if (g
->g
.code
!= otfg
->glyph_id
)
2276 g
->g
.code
= otfg
->glyph_id
;
2285 if (out
->allocated
< out
->used
+ len
)
2290 for (i
= 0; i
< len
; i
++)
2291 out_glyphs
[out
->used
++] = in_glyphs
[i
];
2296 MFLTGlyphFT
*base
= NULL
, *mark
= NULL
, *g
;
2297 int x_ppem
, y_ppem
, x_scale
, y_scale
;
2299 if (OTF_drive_gpos (otf
, &otf_gstring
, script
, langsys
, gpos_features
)
2306 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2307 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2308 x_scale
= ft_face
->size
->metrics
.x_scale
;
2309 y_scale
= ft_face
->size
->metrics
.y_scale
;
2311 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out_glyphs
+ gidx
;
2312 i
< otf_gstring
.used
; i
++, otfg
++, g
++)
2316 if (! otfg
->glyph_id
)
2318 switch (otfg
->positioning_type
)
2322 case 1: /* Single */
2325 int format
= otfg
->f
.f1
.format
;
2327 if (format
& OTF_XPlacement
)
2329 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
2330 if (format
& OTF_XPlaDevice
)
2332 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
2333 if (format
& OTF_YPlacement
)
2335 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
2336 if (format
& OTF_YPlaDevice
)
2338 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
2339 if (format
& OTF_XAdvance
)
2341 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
2342 if (format
& OTF_XAdvDevice
)
2344 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
2345 if (format
& OTF_YAdvance
)
2347 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
2348 if (format
& OTF_YAdvDevice
)
2350 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
2351 adjustment
[i
].set
= 1;
2354 case 3: /* Cursive */
2355 /* Not yet supported. */
2357 case 4: /* Mark-to-Base */
2358 case 5: /* Mark-to-Ligature */
2362 goto label_adjust_anchor
;
2363 default: /* i.e. case 6 Mark-to-Mark */
2368 label_adjust_anchor
:
2370 int base_x
, base_y
, mark_x
, mark_y
;
2371 int this_from
, this_to
;
2373 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
2374 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
2375 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
2376 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
2378 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
2379 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
, prev
->g
.code
,
2380 x_ppem
, y_ppem
, &base_x
, &base_y
);
2381 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
2382 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->g
.code
,
2383 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2384 adjustment
[i
].xoff
= (base_x
- mark_x
);
2385 adjustment
[i
].yoff
= - (base_y
- mark_y
);
2386 adjustment
[i
].back
= (g
- prev
);
2387 adjustment
[i
].xadv
= 0;
2388 adjustment
[i
].advance_is_absolute
= 1;
2389 adjustment
[i
].set
= 1;
2390 this_from
= g
->g
.from
;
2392 for (j
= 0; prev
+ j
< g
; j
++)
2394 if (this_from
> prev
[j
].g
.from
)
2395 this_from
= prev
[j
].g
.from
;
2396 if (this_to
< prev
[j
].g
.to
)
2397 this_to
= prev
[j
].g
.to
;
2399 for (; prev
<= g
; prev
++)
2401 prev
->g
.from
= this_from
;
2402 prev
->g
.to
= this_to
;
2406 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2408 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2419 if (out
->allocated
< out
->used
+ len
)
2421 font
->get_metrics (font
, in
, from
, to
);
2422 memcpy (out_glyphs
+ out
->used
, in_glyphs
,
2423 sizeof (MFLTGlyphFT
) * len
);
2428 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2430 static MFLTGlyphString gstring
;
2432 static bool m17n_flt_initialized
;
2435 ftfont_shape_by_flt (Lisp_Object lgstring
, struct font
*font
,
2436 FT_Face ft_face
, OTF
*otf
, FT_Matrix
*matrix
)
2438 ptrdiff_t len
= LGSTRING_GLYPH_LEN (lgstring
);
2440 struct MFLTFontFT flt_font_ft
;
2442 bool with_variation_selector
= false;
2444 if (! m17n_flt_initialized
)
2447 #ifdef M17N_FLT_USE_NEW_FEATURE
2448 mflt_enable_new_feature
= 1;
2449 mflt_try_otf
= ftfont_try_otf
;
2450 #endif /* M17N_FLT_USE_NEW_FEATURE */
2451 m17n_flt_initialized
= 1;
2454 for (i
= 0; i
< len
; i
++)
2456 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2461 c
= LGLYPH_CHAR (g
);
2462 if (CHAR_VARIATION_SELECTOR_P (c
))
2463 with_variation_selector
= true;
2468 if (otf
&& with_variation_selector
)
2470 setup_otf_gstring (len
);
2471 for (i
= 0; i
< len
; i
++)
2473 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2475 otf_gstring
.glyphs
[i
].c
= LGLYPH_CHAR (g
);
2476 otf_gstring
.glyphs
[i
].f
.index
.from
= LGLYPH_FROM (g
);
2477 otf_gstring
.glyphs
[i
].f
.index
.to
= LGLYPH_TO (g
);
2479 OTF_drive_cmap (otf
, &otf_gstring
);
2480 for (i
= 0; i
< otf_gstring
.used
; i
++)
2482 OTF_Glyph
*otfg
= otf_gstring
.glyphs
+ i
;
2483 Lisp_Object g0
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.from
);
2484 Lisp_Object g1
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.to
);
2486 LGLYPH_SET_CODE (g0
, otfg
->glyph_id
);
2487 LGLYPH_SET_TO (g0
, LGLYPH_TO (g1
));
2488 LGSTRING_SET_GLYPH (lgstring
, i
, g0
);
2490 if (len
> otf_gstring
.used
)
2492 len
= otf_gstring
.used
;
2493 LGSTRING_SET_GLYPH (lgstring
, len
, Qnil
);
2498 Lisp_Object family
= Ffont_get (LGSTRING_FONT (lgstring
), QCfamily
);
2501 flt_font_ft
.flt_font
.family
= Mnil
;
2503 flt_font_ft
.flt_font
.family
2504 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family
))));
2506 flt_font_ft
.flt_font
.x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2507 flt_font_ft
.flt_font
.y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2508 flt_font_ft
.flt_font
.get_glyph_id
= ftfont_get_glyph_id
;
2509 flt_font_ft
.flt_font
.get_metrics
= ftfont_get_metrics
;
2510 flt_font_ft
.flt_font
.check_otf
= ftfont_check_otf
;
2511 flt_font_ft
.flt_font
.drive_otf
= ftfont_drive_otf
;
2512 flt_font_ft
.flt_font
.internal
= NULL
;
2513 flt_font_ft
.font
= font
;
2514 flt_font_ft
.ft_face
= ft_face
;
2515 flt_font_ft
.otf
= otf
;
2516 flt_font_ft
.matrix
= matrix
->xx
!= 0 ? matrix
: 0;
2520 /* A little bit ad hoc. Perhaps, shaper must get script and
2521 language information, and select a proper flt for them
2523 int c1
= LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, 1));
2524 /* For the combining characters in the range U+300..U+36F,
2525 "combining" is the sole FLT provided by the m17n-lib. In
2526 addition, it is the sole FLT that can handle the other
2527 combining characters with non-OTF fonts. */
2528 if ((0x300 <= c1
&& c1
<= 0x36F)
2529 || (! otf
&& CHAR_HAS_CATEGORY (c1
, '^')))
2530 flt
= mflt_get (msymbol ("combining"));
2534 flt
= mflt_find (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, 0)),
2535 &flt_font_ft
.flt_font
);
2537 return make_number (0);
2540 MFLTGlyphFT
*glyphs
= (MFLTGlyphFT
*) gstring
.glyphs
;
2541 ptrdiff_t allocated
= gstring
.allocated
;
2542 ptrdiff_t incr_min
= len
- allocated
;
2549 glyphs
= xpalloc (NULL
, &allocated
, incr_min
, INT_MAX
, sizeof *glyphs
);
2553 for (i
= 0; i
< len
; i
++)
2555 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2556 memset (&glyphs
[i
], 0, sizeof glyphs
[i
]);
2557 glyphs
[i
].g
.c
= LGLYPH_CHAR (g
);
2558 if (with_variation_selector
)
2560 glyphs
[i
].g
.code
= LGLYPH_CODE (g
);
2561 glyphs
[i
].g
.encoded
= 1;
2565 gstring
.glyph_size
= sizeof *glyphs
;
2566 gstring
.glyphs
= (MFLTGlyph
*) glyphs
;
2567 gstring
.allocated
= allocated
;
2571 while (mflt_run (&gstring
, 0, len
, &flt_font_ft
.flt_font
, flt
) == -2);
2573 if (gstring
.used
> LGSTRING_GLYPH_LEN (lgstring
))
2575 for (i
= 0; i
< gstring
.used
; i
++)
2577 MFLTGlyphFT
*g
= (MFLTGlyphFT
*) (gstring
.glyphs
) + i
;
2579 g
->g
.from
= LGLYPH_FROM (LGSTRING_GLYPH (lgstring
, g
->g
.from
));
2580 g
->g
.to
= LGLYPH_TO (LGSTRING_GLYPH (lgstring
, g
->g
.to
));
2583 for (i
= 0; i
< gstring
.used
; i
++)
2585 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
, i
);
2586 MFLTGlyphFT
*g
= (MFLTGlyphFT
*) (gstring
.glyphs
) + i
;
2590 lglyph
= LGLYPH_NEW ();
2591 LGSTRING_SET_GLYPH (lgstring
, i
, lglyph
);
2593 LGLYPH_SET_FROM (lglyph
, g
->g
.from
);
2594 LGLYPH_SET_TO (lglyph
, g
->g
.to
);
2595 LGLYPH_SET_CHAR (lglyph
, g
->g
.c
);
2596 LGLYPH_SET_CODE (lglyph
, g
->g
.code
);
2597 LGLYPH_SET_WIDTH (lglyph
, g
->g
.xadv
>> 6);
2598 LGLYPH_SET_LBEARING (lglyph
, g
->g
.lbearing
>> 6);
2599 LGLYPH_SET_RBEARING (lglyph
, g
->g
.rbearing
>> 6);
2600 LGLYPH_SET_ASCENT (lglyph
, g
->g
.ascent
>> 6);
2601 LGLYPH_SET_DESCENT (lglyph
, g
->g
.descent
>> 6);
2604 Lisp_Object vec
= make_uninit_vector (3);
2606 ASET (vec
, 0, make_number (g
->g
.xoff
>> 6));
2607 ASET (vec
, 1, make_number (g
->g
.yoff
>> 6));
2608 ASET (vec
, 2, make_number (g
->g
.xadv
>> 6));
2609 LGLYPH_SET_ADJUSTMENT (lglyph
, vec
);
2612 return make_number (i
);
2616 ftfont_shape (Lisp_Object lgstring
)
2618 struct font
*font
= CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring
));
2619 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
2620 OTF
*otf
= ftfont_get_otf (ftfont_info
);
2622 return ftfont_shape_by_flt (lgstring
, font
, ftfont_info
->ft_size
->face
, otf
,
2623 &ftfont_info
->matrix
);
2626 #endif /* HAVE_M17N_FLT */
2628 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2631 ftfont_variation_glyphs (struct font
*font
, int c
, unsigned variations
[256])
2633 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
2634 OTF
*otf
= ftfont_get_otf (ftfont_info
);
2638 return OTF_get_variation_glyphs (otf
, c
, variations
);
2641 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2642 #endif /* HAVE_LIBOTF */
2644 static const char *const ftfont_booleans
[] = {
2657 static const char *const ftfont_non_booleans
[] = {
2689 ftfont_filter_properties (Lisp_Object font
, Lisp_Object alist
)
2691 font_filter_properties (font
, alist
, ftfont_booleans
, ftfont_non_booleans
);
2696 ftfont_combining_capability (struct font
*font
)
2698 #ifdef HAVE_M17N_FLT
2705 static struct font_driver
const ftfont_driver
=
2707 /* We can't draw a text without device dependent functions. */
2708 .type
= LISPSYM_INITIALLY (Qfreetype
),
2709 .get_cache
= ftfont_get_cache
,
2710 .list
= ftfont_list
,
2711 .match
= ftfont_match
,
2712 .list_family
= ftfont_list_family
,
2713 .open
= ftfont_open
,
2714 .close
= ftfont_close
,
2715 .has_char
= ftfont_has_char
,
2716 .encode_char
= ftfont_encode_char
,
2717 .text_extents
= ftfont_text_extents
,
2718 .get_bitmap
= ftfont_get_bitmap
,
2719 .anchor_point
= ftfont_anchor_point
,
2721 .otf_capability
= ftfont_otf_capability
,
2723 #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
2724 .shape
= ftfont_shape
,
2726 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2727 .get_variation_glyphs
= ftfont_variation_glyphs
,
2729 .filter_properties
= ftfont_filter_properties
,
2730 .combining_capability
= ftfont_combining_capability
,
2734 syms_of_ftfont (void)
2736 /* Symbolic type of this font-driver. */
2737 DEFSYM (Qfreetype
, "freetype");
2739 /* Fontconfig's generic families and their aliases. */
2740 DEFSYM (Qmonospace
, "monospace");
2741 DEFSYM (Qsans_serif
, "sans-serif");
2742 DEFSYM (Qsans
, "sans");
2743 DEFSYM (Qsans__serif
, "sans serif");
2745 staticpro (&freetype_font_cache
);
2746 freetype_font_cache
= list1 (Qt
);
2748 staticpro (&ftfont_generic_family_list
);
2749 ftfont_generic_family_list
= list3 (Fcons (Qmonospace
, Qt
),
2750 Fcons (Qsans_serif
, Qt
),
2753 staticpro (&ft_face_cache
);
2754 ft_face_cache
= Qnil
;
2756 register_font_driver (&ftfont_driver
, NULL
);