1 /* ftfont.c -- FreeType font driver.
2 Copyright (C) 2006-2016 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 <http://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
))
771 /* We come here because of unexpected error in fontconfig API call
772 (usually insufficient memory). */
775 FcPatternDestroy (pattern
);
780 if ((*otspec
)->nfeatures
[0] > 0)
781 free ((*otspec
)->features
[0]);
782 if ((*otspec
)->nfeatures
[1] > 0)
783 free ((*otspec
)->features
[1]);
789 if (langset
) FcLangSetDestroy (langset
);
790 if (charset
&& fc_charset_idx
< 0) FcCharSetDestroy (charset
);
795 ftfont_list (struct frame
*f
, Lisp_Object spec
)
797 Lisp_Object val
= Qnil
, family
, adstyle
;
800 FcFontSet
*fontset
= NULL
;
801 FcObjectSet
*objset
= NULL
;
803 Lisp_Object chars
= Qnil
;
804 char otlayout
[15]; /* For "otlayout:XXXX" */
805 struct OpenTypeSpec
*otspec
= NULL
;
807 const char *langname
= NULL
;
809 if (! fc_initialized
)
815 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
818 if (FcPatternGetCharSet (pattern
, FC_CHARSET
, 0, &charset
) != FcResultMatch
)
820 val
= assq_no_quit (QCscript
, AREF (spec
, FONT_EXTRA_INDEX
));
823 val
= assq_no_quit (XCDR (val
), Vscript_representative_chars
);
824 if (CONSP (val
) && VECTORP (XCDR (val
)))
829 if (INTEGERP (AREF (spec
, FONT_SPACING_INDEX
)))
830 spacing
= XINT (AREF (spec
, FONT_SPACING_INDEX
));
831 family
= AREF (spec
, FONT_FAMILY_INDEX
);
834 Lisp_Object resolved
;
836 resolved
= ftfont_resolve_generic_family (family
, pattern
);
837 if (! NILP (resolved
))
839 FcPatternDel (pattern
, FC_FAMILY
);
840 if (! FcPatternAddString (pattern
, FC_FAMILY
,
841 SYMBOL_FcChar8 (resolved
)))
845 adstyle
= AREF (spec
, FONT_ADSTYLE_INDEX
);
846 if (! NILP (adstyle
) && SBYTES (SYMBOL_NAME (adstyle
)) == 0)
848 objset
= FcObjectSetBuild (FC_FOUNDRY
, FC_FAMILY
, FC_WEIGHT
, FC_SLANT
,
849 FC_WIDTH
, FC_PIXEL_SIZE
, FC_SPACING
, FC_SCALABLE
,
850 FC_STYLE
, FC_FILE
, FC_INDEX
,
853 #endif /* FC_CAPABILITY */
861 FcObjectSetAdd (objset
, FC_CHARSET
);
863 fontset
= FcFontList (NULL
, pattern
, objset
);
864 if (! fontset
|| fontset
->nfont
== 0)
867 /* Need fix because this finds any fonts. */
868 if (fontset
->nfont
== 0 && ! NILP (family
))
870 /* Try matching with configuration. For instance, the
871 configuration may specify "Nimbus Mono L" as an alias of
873 FcPattern
*pat
= FcPatternBuild (0, FC_FAMILY
, FcTypeString
,
874 SYMBOL_FcChar8 (family
), NULL
);
877 if (FcConfigSubstitute (NULL
, pat
, FcMatchPattern
) == FcTrue
)
880 FcPatternGetString (pat
, FC_FAMILY
, i
, &fam
) == FcResultMatch
;
883 FcPatternDel (pattern
, FC_FAMILY
);
884 FcPatternAddString (pattern
, FC_FAMILY
, fam
);
885 FcFontSetDestroy (fontset
);
886 fontset
= FcFontList (NULL
, pattern
, objset
);
887 if (fontset
&& fontset
->nfont
> 0)
893 for (i
= 0; i
< fontset
->nfont
; i
++)
901 if ((FcPatternGetInteger (fontset
->fonts
[i
], FC_SPACING
, 0, &this)
912 if (FcPatternGetString (fontset
->fonts
[i
], FC_CAPABILITY
, 0, &this)
914 || ! strstr ((char *) this, otlayout
))
917 #endif /* FC_CAPABILITY */
925 if (FcPatternGetString (fontset
->fonts
[i
], FC_FILE
, 0, &file
)
928 otf
= OTF_open ((char *) file
);
931 passed
= (OTF_check_features (otf
, 1, otspec
->script_tag
,
934 otspec
->nfeatures
[0]) == 1
935 && OTF_check_features (otf
, 0, otspec
->script_tag
,
938 otspec
->nfeatures
[1]) == 1);
943 #endif /* HAVE_LIBOTF */
948 if (FcPatternGetCharSet (fontset
->fonts
[i
], FC_CHARSET
, 0, &charset
)
951 for (j
= 0; j
< ASIZE (chars
); j
++)
952 if (TYPE_RANGED_INTEGERP (FcChar32
, AREF (chars
, j
))
953 && FcCharSetHasChar (charset
, XFASTINT (AREF (chars
, j
))))
955 if (j
== ASIZE (chars
))
958 if (! NILP (adstyle
) || langname
)
960 Lisp_Object this_adstyle
= get_adstyle_property (fontset
->fonts
[i
]);
963 && (NILP (this_adstyle
)
964 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle
)),
965 SSDATA (SYMBOL_NAME (this_adstyle
))) != 0))
968 && ! NILP (this_adstyle
)
969 && xstrcasecmp (langname
, SSDATA (SYMBOL_NAME (this_adstyle
))))
972 entity
= ftfont_pattern_entity (fontset
->fonts
[i
],
973 AREF (spec
, FONT_EXTRA_INDEX
));
975 val
= Fcons (entity
, val
);
977 val
= Fnreverse (val
);
981 /* We come here because of unexpected error in fontconfig API call
982 (usually insufficient memory). */
986 FONT_ADD_LOG ("ftfont-list", spec
, val
);
987 if (objset
) FcObjectSetDestroy (objset
);
988 if (fontset
) FcFontSetDestroy (fontset
);
989 if (pattern
) FcPatternDestroy (pattern
);
994 ftfont_match (struct frame
*f
, Lisp_Object spec
)
996 Lisp_Object entity
= Qnil
;
997 FcPattern
*pattern
, *match
= NULL
;
999 char otlayout
[15]; /* For "otlayout:XXXX" */
1000 struct OpenTypeSpec
*otspec
= NULL
;
1001 const char *langname
= NULL
;
1003 if (! fc_initialized
)
1009 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
1013 if (INTEGERP (AREF (spec
, FONT_SIZE_INDEX
)))
1017 value
.type
= FcTypeDouble
;
1018 value
.u
.d
= XINT (AREF (spec
, FONT_SIZE_INDEX
));
1019 FcPatternAdd (pattern
, FC_PIXEL_SIZE
, value
, FcFalse
);
1021 if (FcConfigSubstitute (NULL
, pattern
, FcMatchPattern
) == FcTrue
)
1023 FcDefaultSubstitute (pattern
);
1024 match
= FcFontMatch (NULL
, pattern
, &result
);
1027 entity
= ftfont_pattern_entity (match
, AREF (spec
, FONT_EXTRA_INDEX
));
1028 FcPatternDestroy (match
);
1029 if (! NILP (AREF (spec
, FONT_FAMILY_INDEX
))
1030 && NILP (assq_no_quit (AREF (spec
, FONT_FAMILY_INDEX
),
1031 ftfont_generic_family_list
))
1032 && NILP (Fstring_equal (AREF (spec
, FONT_FAMILY_INDEX
),
1033 AREF (entity
, FONT_FAMILY_INDEX
))))
1037 FcPatternDestroy (pattern
);
1039 FONT_ADD_LOG ("ftfont-match", spec
, entity
);
1044 ftfont_list_family (struct frame
*f
)
1046 Lisp_Object list
= Qnil
;
1047 FcPattern
*pattern
= NULL
;
1048 FcFontSet
*fontset
= NULL
;
1049 FcObjectSet
*objset
= NULL
;
1052 if (! fc_initialized
)
1058 pattern
= FcPatternCreate ();
1061 objset
= FcObjectSetBuild (FC_FAMILY
, NULL
);
1064 fontset
= FcFontList (NULL
, pattern
, objset
);
1068 for (i
= 0; i
< fontset
->nfont
; i
++)
1070 FcPattern
*pat
= fontset
->fonts
[i
];
1073 if (FcPatternGetString (pat
, FC_FAMILY
, 0, &str
) == FcResultMatch
)
1074 list
= Fcons (intern ((char *) str
), list
);
1078 if (objset
) FcObjectSetDestroy (objset
);
1079 if (fontset
) FcFontSetDestroy (fontset
);
1080 if (pattern
) FcPatternDestroy (pattern
);
1087 ftfont_open2 (struct frame
*f
,
1090 Lisp_Object font_object
)
1092 struct ftfont_info
*ftfont_info
;
1094 struct ftfont_cache_data
*cache_data
;
1098 Lisp_Object val
, filename
, idx
, cache
;
1104 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
1108 cache
= ftfont_lookup_cache (entity
, FTFONT_CACHE_FOR_FACE
);
1111 filename
= XCAR (val
);
1114 cache_data
= XSAVE_POINTER (XCDR (cache
), 0);
1115 ft_face
= cache_data
->ft_face
;
1116 if (XSAVE_INTEGER (val
, 1) > 0)
1118 /* FT_Face in this cache is already used by the different size. */
1119 if (FT_New_Size (ft_face
, &ft_size
) != 0)
1121 if (FT_Activate_Size (ft_size
) != 0)
1123 FT_Done_Size (ft_size
);
1127 set_save_integer (val
, 1, XSAVE_INTEGER (val
, 1) + 1);
1128 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
1131 if (FT_Set_Pixel_Sizes (ft_face
, size
, size
) != 0)
1133 if (XSAVE_INTEGER (val
, 1) == 0)
1134 FT_Done_Face (ft_face
);
1138 ASET (font_object
, FONT_FILE_INDEX
, filename
);
1139 font
= XFONT_OBJECT (font_object
);
1140 ftfont_info
= (struct ftfont_info
*) font
;
1141 ftfont_info
->ft_size
= ft_face
->size
;
1142 ftfont_info
->index
= XINT (idx
);
1144 ftfont_info
->maybe_otf
= (ft_face
->face_flags
& FT_FACE_FLAG_SFNT
) != 0;
1145 ftfont_info
->otf
= NULL
;
1146 #endif /* HAVE_LIBOTF */
1147 /* This means that there's no need of transformation. */
1148 ftfont_info
->matrix
.xx
= 0;
1149 font
->pixel_size
= size
;
1150 font
->driver
= &ftfont_driver
;
1151 font
->encoding_charset
= font
->repertory_charset
= -1;
1153 upEM
= ft_face
->units_per_EM
;
1154 scalable
= (INTEGERP (AREF (entity
, FONT_AVGWIDTH_INDEX
))
1155 && XINT (AREF (entity
, FONT_AVGWIDTH_INDEX
)) == 0);
1158 font
->ascent
= ft_face
->ascender
* size
/ upEM
+ 0.5;
1159 font
->descent
= - ft_face
->descender
* size
/ upEM
+ 0.5;
1160 font
->height
= ft_face
->height
* size
/ upEM
+ 0.5;
1164 font
->ascent
= ft_face
->size
->metrics
.ascender
>> 6;
1165 font
->descent
= - ft_face
->size
->metrics
.descender
>> 6;
1166 font
->height
= ft_face
->size
->metrics
.height
>> 6;
1168 if (INTEGERP (AREF (entity
, FONT_SPACING_INDEX
)))
1169 spacing
= XINT (AREF (entity
, FONT_SPACING_INDEX
));
1171 spacing
= FC_PROPORTIONAL
;
1172 if (spacing
!= FC_PROPORTIONAL
1174 && spacing
!= FC_DUAL
1175 #endif /* FC_DUAL */
1177 font
->min_width
= font
->average_width
= font
->space_width
1178 = (scalable
? ft_face
->max_advance_width
* size
/ upEM
+ 0.5
1179 : ft_face
->size
->metrics
.max_advance
>> 6);
1184 font
->min_width
= font
->average_width
= font
->space_width
= 0;
1185 for (i
= 32, n
= 0; i
< 127; i
++)
1186 if (FT_Load_Char (ft_face
, i
, FT_LOAD_DEFAULT
) == 0)
1188 int this_width
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1191 && (! font
->min_width
|| font
->min_width
> this_width
))
1192 font
->min_width
= this_width
;
1194 font
->space_width
= this_width
;
1195 font
->average_width
+= this_width
;
1199 font
->average_width
/= n
;
1202 font
->baseline_offset
= 0;
1203 font
->relative_compose
= 0;
1204 font
->default_ascent
= 0;
1205 font
->vertical_centering
= 0;
1208 font
->underline_position
= (-ft_face
->underline_position
* size
/ upEM
1210 font
->underline_thickness
= (ft_face
->underline_thickness
* size
/ upEM
1215 font
->underline_position
= -1;
1216 font
->underline_thickness
= 0;
1223 ftfont_open (struct frame
*f
, Lisp_Object entity
, int pixel_size
)
1225 Lisp_Object font_object
;
1227 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
1230 font_object
= font_build_object (VECSIZE (struct ftfont_info
),
1231 Qfreetype
, entity
, size
);
1232 return ftfont_open2 (f
, entity
, pixel_size
, font_object
);
1236 ftfont_close (struct font
*font
)
1238 /* FIXME: Although this function can be called while garbage-collecting,
1239 the function assumes that Lisp data structures are properly-formed.
1240 This invalid assumption can lead to core dumps (Bug#20890). */
1242 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1243 Lisp_Object val
, cache
;
1245 val
= Fcons (font
->props
[FONT_FILE_INDEX
], make_number (ftfont_info
->index
));
1246 cache
= ftfont_lookup_cache (val
, FTFONT_CACHE_FOR_FACE
);
1247 eassert (CONSP (cache
));
1249 set_save_integer (val
, 1, XSAVE_INTEGER (val
, 1) - 1);
1250 if (XSAVE_INTEGER (val
, 1) == 0)
1252 struct ftfont_cache_data
*cache_data
= XSAVE_POINTER (val
, 0);
1254 FT_Done_Face (cache_data
->ft_face
);
1256 if (ftfont_info
->otf
)
1257 OTF_close (ftfont_info
->otf
);
1259 cache_data
->ft_face
= NULL
;
1262 FT_Done_Size (ftfont_info
->ft_size
);
1266 ftfont_has_char (Lisp_Object font
, int c
)
1268 struct charset
*cs
= NULL
;
1270 if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qja
)
1271 && charset_jisx0208
>= 0)
1272 cs
= CHARSET_FROM_ID (charset_jisx0208
);
1273 else if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qko
)
1274 && charset_ksc5601
>= 0)
1275 cs
= CHARSET_FROM_ID (charset_ksc5601
);
1277 return (ENCODE_CHAR (cs
, c
) != CHARSET_INVALID_CODE (cs
));
1279 if (FONT_ENTITY_P (font
))
1281 FcCharSet
*charset
= ftfont_get_fc_charset (font
);
1283 return (FcCharSetHasChar (charset
, c
) == FcTrue
);
1287 struct ftfont_info
*ftfont_info
;
1289 ftfont_info
= (struct ftfont_info
*) XFONT_OBJECT (font
);
1290 return (FT_Get_Char_Index (ftfont_info
->ft_size
->face
, (FT_ULong
) c
)
1296 ftfont_encode_char (struct font
*font
, int c
)
1298 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1299 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1300 FT_ULong charcode
= c
;
1301 FT_UInt code
= FT_Get_Char_Index (ft_face
, charcode
);
1303 return (code
> 0 ? code
: FONT_INVALID_CODE
);
1307 ftfont_text_extents (struct font
*font
, unsigned int *code
,
1308 int nglyphs
, struct font_metrics
*metrics
)
1310 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1311 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1315 if (ftfont_info
->ft_size
!= ft_face
->size
)
1316 FT_Activate_Size (ftfont_info
->ft_size
);
1318 for (i
= 0, first
= 1; i
< nglyphs
; i
++)
1320 if (FT_Load_Glyph (ft_face
, code
[i
], FT_LOAD_DEFAULT
) == 0)
1322 FT_Glyph_Metrics
*m
= &ft_face
->glyph
->metrics
;
1326 metrics
->lbearing
= m
->horiBearingX
>> 6;
1327 metrics
->rbearing
= (m
->horiBearingX
+ m
->width
) >> 6;
1328 metrics
->ascent
= m
->horiBearingY
>> 6;
1329 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1332 if (metrics
->lbearing
> width
+ (m
->horiBearingX
>> 6))
1333 metrics
->lbearing
= width
+ (m
->horiBearingX
>> 6);
1334 if (metrics
->rbearing
1335 < width
+ ((m
->horiBearingX
+ m
->width
) >> 6))
1337 = width
+ ((m
->horiBearingX
+ m
->width
) >> 6);
1338 if (metrics
->ascent
< (m
->horiBearingY
>> 6))
1339 metrics
->ascent
= m
->horiBearingY
>> 6;
1340 if (metrics
->descent
> ((m
->height
- m
->horiBearingY
) >> 6))
1341 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1342 width
+= m
->horiAdvance
>> 6;
1345 width
+= font
->space_width
;
1347 metrics
->width
= width
;
1351 ftfont_get_bitmap (struct font
*font
, unsigned int code
, struct font_bitmap
*bitmap
, int bits_per_pixel
)
1353 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1354 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1355 FT_Int32 load_flags
= FT_LOAD_RENDER
;
1357 if (ftfont_info
->ft_size
!= ft_face
->size
)
1358 FT_Activate_Size (ftfont_info
->ft_size
);
1359 if (bits_per_pixel
== 1)
1361 #ifdef FT_LOAD_TARGET_MONO
1362 load_flags
|= FT_LOAD_TARGET_MONO
;
1364 load_flags
|= FT_LOAD_MONOCHROME
;
1367 else if (bits_per_pixel
!= 8)
1368 /* We don't support such a rendering. */
1371 if (FT_Load_Glyph (ft_face
, code
, load_flags
) != 0)
1373 bitmap
->bits_per_pixel
1374 = (ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_MONO
? 1
1375 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
? 8
1376 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD
? 8
1377 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD_V
? 8
1379 if (bitmap
->bits_per_pixel
< 0)
1380 /* We don't support that kind of pixel mode. */
1382 bitmap
->rows
= ft_face
->glyph
->bitmap
.rows
;
1383 bitmap
->width
= ft_face
->glyph
->bitmap
.width
;
1384 bitmap
->pitch
= ft_face
->glyph
->bitmap
.pitch
;
1385 bitmap
->buffer
= ft_face
->glyph
->bitmap
.buffer
;
1386 bitmap
->left
= ft_face
->glyph
->bitmap_left
;
1387 bitmap
->top
= ft_face
->glyph
->bitmap_top
;
1388 bitmap
->advance
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1394 ftfont_anchor_point (struct font
*font
, unsigned int code
, int idx
,
1397 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1398 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1400 if (ftfont_info
->ft_size
!= ft_face
->size
)
1401 FT_Activate_Size (ftfont_info
->ft_size
);
1402 if (FT_Load_Glyph (ft_face
, code
, FT_LOAD_DEFAULT
) != 0)
1404 if (ft_face
->glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
1406 if (idx
>= ft_face
->glyph
->outline
.n_points
)
1408 *x
= ft_face
->glyph
->outline
.points
[idx
].x
;
1409 *y
= ft_face
->glyph
->outline
.points
[idx
].y
;
1416 ftfont_otf_features (OTF_GSUB_GPOS
*gsub_gpos
)
1418 Lisp_Object scripts
, langsyses
, features
, sym
;
1421 for (scripts
= Qnil
, i
= gsub_gpos
->ScriptList
.ScriptCount
- 1; i
>= 0; i
--)
1423 OTF_Script
*otf_script
= gsub_gpos
->ScriptList
.Script
+ i
;
1425 for (langsyses
= Qnil
, j
= otf_script
->LangSysCount
- 1; j
>= -1; j
--)
1427 OTF_LangSys
*otf_langsys
;
1430 otf_langsys
= otf_script
->LangSys
+ j
;
1431 else if (otf_script
->DefaultLangSysOffset
)
1432 otf_langsys
= &otf_script
->DefaultLangSys
;
1436 for (features
= Qnil
, k
= otf_langsys
->FeatureCount
- 1; k
>= 0; k
--)
1438 l
= otf_langsys
->FeatureIndex
[k
];
1439 if (l
>= gsub_gpos
->FeatureList
.FeatureCount
)
1441 OTF_TAG_SYM (sym
, gsub_gpos
->FeatureList
.Feature
[l
].FeatureTag
);
1442 features
= Fcons (sym
, features
);
1445 OTF_TAG_SYM (sym
, otf_script
->LangSysRecord
[j
].LangSysTag
);
1448 langsyses
= Fcons (Fcons (sym
, features
), langsyses
);
1451 OTF_TAG_SYM (sym
, gsub_gpos
->ScriptList
.Script
[i
].ScriptTag
);
1452 scripts
= Fcons (Fcons (sym
, langsyses
), scripts
);
1460 ftfont_otf_capability (struct font
*font
)
1462 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1463 OTF
*otf
= ftfont_get_otf (ftfont_info
);
1464 Lisp_Object gsub_gpos
;
1468 gsub_gpos
= Fcons (Qnil
, Qnil
);
1469 if (OTF_get_table (otf
, "GSUB") == 0
1470 && otf
->gsub
->FeatureList
.FeatureCount
> 0)
1471 XSETCAR (gsub_gpos
, ftfont_otf_features (otf
->gsub
));
1472 if (OTF_get_table (otf
, "GPOS") == 0
1473 && otf
->gpos
->FeatureList
.FeatureCount
> 0)
1474 XSETCDR (gsub_gpos
, ftfont_otf_features (otf
->gpos
));
1478 #ifdef HAVE_M17N_FLT
1480 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1481 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1482 /* We can use the new feature of libotf and m17n-flt to handle the
1483 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1484 some Agian scripts. */
1485 #define M17N_FLT_USE_NEW_FEATURE
1497 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1498 We use this structure instead of MFLTGlyph to utilize the new
1499 feature of libotf ver.0.9.15 which requires saving and restoring
1500 the value of OTF_GlyphString.positioning_type in the succeeding
1501 calls of the callback function MFLTFont.drive_otf (which is set to
1502 ftfont_drive_otf). */
1506 unsigned int libotf_positioning_type
;
1510 ftfont_get_glyph_id (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1513 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1514 FT_Face ft_face
= flt_font_ft
->ft_face
;
1517 for (g
= (MFLTGlyphFT
*) (gstring
->glyphs
) + from
; from
< to
; g
++, from
++)
1520 FT_UInt code
= FT_Get_Char_Index (ft_face
, g
->g
.code
);
1522 g
->g
.code
= code
> 0 ? code
: FONT_INVALID_CODE
;
1528 /* Operators for 26.6 fixed fractional pixel format */
1530 #define FLOOR(x) ((x) & -64)
1531 #define CEIL(x) (((x)+63) & -64)
1532 #define ROUND(x) (((x)+32) & -64)
1535 ftfont_get_metrics (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1538 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1539 FT_Face ft_face
= flt_font_ft
->ft_face
;
1542 for (g
= (MFLTGlyphFT
*) (gstring
->glyphs
) + from
; from
< to
; g
++, from
++)
1543 if (! g
->g
.measured
)
1545 if (g
->g
.code
!= FONT_INVALID_CODE
)
1547 FT_Glyph_Metrics
*m
;
1549 if (FT_Load_Glyph (ft_face
, g
->g
.code
, FT_LOAD_DEFAULT
) != 0)
1551 m
= &ft_face
->glyph
->metrics
;
1552 if (flt_font_ft
->matrix
)
1557 v
[0].x
= v
[1].x
= m
->horiBearingX
;
1558 v
[2].x
= v
[3].x
= m
->horiBearingX
+ m
->width
;
1559 v
[0].y
= v
[2].y
= m
->horiBearingY
;
1560 v
[1].y
= v
[3].y
= m
->horiBearingY
- m
->height
;
1561 for (i
= 0; i
< 4; i
++)
1562 FT_Vector_Transform (v
+ i
, flt_font_ft
->matrix
);
1563 g
->g
.lbearing
= v
[0].x
< v
[1].x
? FLOOR (v
[0].x
) : FLOOR (v
[1].x
);
1564 g
->g
.rbearing
= v
[2].x
> v
[3].x
? CEIL (v
[2].x
) : CEIL (v
[3].x
);
1565 g
->g
.ascent
= v
[0].y
> v
[2].y
? CEIL (v
[0].y
) : CEIL (v
[2].y
);
1566 g
->g
.descent
= v
[1].y
< v
[3].y
? - FLOOR (v
[1].y
) : - FLOOR (v
[3].y
);
1570 g
->g
.lbearing
= FLOOR (m
->horiBearingX
);
1571 g
->g
.rbearing
= CEIL (m
->horiBearingX
+ m
->width
);
1572 g
->g
.ascent
= CEIL (m
->horiBearingY
);
1573 g
->g
.descent
= - FLOOR (m
->horiBearingY
- m
->height
);
1575 g
->g
.xadv
= ROUND (ft_face
->glyph
->advance
.x
);
1580 g
->g
.rbearing
= g
->g
.xadv
= flt_font_ft
->font
->space_width
<< 6;
1581 g
->g
.ascent
= flt_font_ft
->font
->ascent
<< 6;
1582 g
->g
.descent
= flt_font_ft
->font
->descent
<< 6;
1591 ftfont_check_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
)
1593 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1595 #define FEATURE_ANY(IDX) \
1596 (spec->features[IDX] \
1597 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1599 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1600 OTF
*otf
= flt_font_ft
->otf
;
1605 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1606 /* Return true iff any of GSUB or GPOS support the script (and
1609 && (OTF_check_features (otf
, 0, spec
->script
, spec
->langsys
,
1611 || OTF_check_features (otf
, 1, spec
->script
, spec
->langsys
,
1614 for (i
= 0; i
< 2; i
++)
1615 if (! FEATURE_ANY (i
))
1617 if (FEATURE_NONE (i
))
1620 && OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1625 if (spec
->features
[i
][0] == 0xFFFFFFFF)
1628 || OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1634 for (n
= 1; spec
->features
[i
][n
]; n
++);
1636 SAFE_NALLOCA (tags
, 1, n
);
1637 for (n
= 0, negative
= 0; spec
->features
[i
][n
]; n
++)
1639 if (spec
->features
[i
][n
] == 0xFFFFFFFF)
1642 tags
[n
- 1] = spec
->features
[i
][n
] | 0x80000000;
1644 tags
[n
] = spec
->features
[i
][n
];
1647 #ifndef M17N_FLT_USE_NEW_FEATURE
1648 passed
= n
- negative
> 0;
1651 passed
= (OTF_check_features (otf
, i
== 0, spec
->script
,
1652 spec
->langsys
, tags
, n
- negative
)
1663 #define DEVICE_DELTA(table, size) \
1664 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1665 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1669 adjust_anchor (FT_Face ft_face
, OTF_Anchor
*anchor
,
1670 unsigned code
, int x_ppem
, int y_ppem
, int *x
, int *y
)
1672 if (anchor
->AnchorFormat
== 2)
1674 FT_Outline
*outline
;
1675 int ap
= anchor
->f
.f1
.AnchorPoint
;
1677 FT_Load_Glyph (ft_face
, (FT_UInt
) code
, FT_LOAD_MONOCHROME
);
1678 outline
= &ft_face
->glyph
->outline
;
1679 if (ap
< outline
->n_points
)
1681 *x
= outline
->points
[ap
].x
<< 6;
1682 *y
= outline
->points
[ap
].y
<< 6;
1685 else if (anchor
->AnchorFormat
== 3)
1687 if (anchor
->f
.f2
.XDeviceTable
.offset
1688 && anchor
->f
.f2
.XDeviceTable
.DeltaValue
)
1689 *x
+= DEVICE_DELTA (anchor
->f
.f2
.XDeviceTable
, x_ppem
);
1690 if (anchor
->f
.f2
.YDeviceTable
.offset
1691 && anchor
->f
.f2
.YDeviceTable
.DeltaValue
)
1692 *y
+= DEVICE_DELTA (anchor
->f
.f2
.YDeviceTable
, y_ppem
);
1696 static OTF_GlyphString otf_gstring
;
1699 setup_otf_gstring (int size
)
1701 if (otf_gstring
.size
< size
)
1703 ptrdiff_t new_size
= otf_gstring
.size
;
1704 xfree (otf_gstring
.glyphs
);
1705 otf_gstring
.glyphs
= xpalloc (NULL
, &new_size
, size
- otf_gstring
.size
,
1706 INT_MAX
, sizeof *otf_gstring
.glyphs
);
1707 otf_gstring
.size
= new_size
;
1709 otf_gstring
.used
= size
;
1710 memset (otf_gstring
.glyphs
, 0, sizeof (OTF_Glyph
) * size
);
1713 #ifdef M17N_FLT_USE_NEW_FEATURE
1715 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1716 #define PACK_OTF_TAG(TAG) \
1717 ((((TAG) & 0x7F000000) >> 3) \
1718 | (((TAG) & 0x7F0000) >> 2) \
1719 | (((TAG) & 0x7F00) >> 1) \
1722 /* Assuming that FONT is an OpenType font, apply OpenType features
1723 specified in SPEC on glyphs between FROM and TO of IN, and record
1724 the lastly applied feature in each glyph of IN. If OUT is not
1725 NULL, append the resulting glyphs to OUT while storing glyph
1726 position adjustment information in ADJUSTMENT. */
1729 ftfont_drive_otf (MFLTFont
*font
,
1731 MFLTGlyphString
*in
,
1734 MFLTGlyphString
*out
,
1735 MFLTGlyphAdjustment
*adjustment
)
1737 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1738 MFLTGlyphFT
*in_glyphs
= (MFLTGlyphFT
*) (in
->glyphs
) + from
;
1739 MFLTGlyphFT
*out_glyphs
= out
? (MFLTGlyphFT
*) (out
->glyphs
) : NULL
;
1740 FT_Face ft_face
= flt_font_ft
->ft_face
;
1741 OTF
*otf
= flt_font_ft
->otf
;
1742 int len
= to
- from
;
1745 char script
[5], *langsys
= NULL
;
1746 char *gsub_features
= NULL
, *gpos_features
= NULL
;
1747 OTF_Feature
*features
;
1751 OTF_tag_name (spec
->script
, script
);
1756 langsys
= langsysbuf
;
1757 OTF_tag_name (spec
->langsys
, langsys
);
1761 for (i
= 0; i
< 2; i
++)
1765 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
1767 for (j
= 0; spec
->features
[i
][j
]; j
++);
1768 SAFE_NALLOCA (p
, 6, j
);
1773 for (j
= 0; spec
->features
[i
][j
]; j
++)
1775 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
1776 *p
++ = '*', *p
++ = ',';
1779 OTF_tag_name (spec
->features
[i
][j
], p
);
1788 setup_otf_gstring (len
);
1789 for (i
= 0; i
< len
; i
++)
1791 otf_gstring
.glyphs
[i
].c
= in_glyphs
[i
].g
.c
& 0x11FFFF;
1792 otf_gstring
.glyphs
[i
].glyph_id
= in_glyphs
[i
].g
.code
;
1793 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1794 otf_gstring
.glyphs
[i
].positioning_type
= in_glyphs
[i
].libotf_positioning_type
;
1798 OTF_drive_gdef (otf
, &otf_gstring
);
1799 gidx
= out
? out
->used
: from
;
1801 if (gsub_features
&& out
)
1803 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1804 if (OTF_drive_gsub_features (otf
, &otf_gstring
, script
, langsys
,
1808 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1812 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
1817 features
= otf
->gsub
->FeatureList
.Feature
;
1818 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
1821 int min_from
, max_to
;
1824 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1825 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1827 feature_idx
= otfg
->positioning_type
>> 4;
1829 g
= out_glyphs
+ out
->used
;
1830 *g
= in_glyphs
[otfg
->f
.index
.from
];
1831 if (g
->g
.code
!= otfg
->glyph_id
)
1834 g
->g
.code
= otfg
->glyph_id
;
1838 min_from
= g
->g
.from
;
1840 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
1842 /* OTFG substitutes multiple glyphs in IN. */
1843 for (j
= otfg
->f
.index
.from
+ 1; j
<= otfg
->f
.index
.to
; j
++)
1845 if (min_from
> in_glyphs
[j
].g
.from
)
1846 min_from
= in_glyphs
[j
].g
.from
;
1847 if (max_to
< in_glyphs
[j
].g
.to
)
1848 max_to
= in_glyphs
[j
].g
.to
;
1850 g
->g
.from
= min_from
;
1855 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1856 tag
= PACK_OTF_TAG (tag
);
1857 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1859 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1860 g
->libotf_positioning_type
1861 = otfg
->positioning_type
& OTF_positioning_type_components_mask
;
1863 for (i
++, otfg
++; (i
< otf_gstring
.used
1864 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
1867 g
= out_glyphs
+ out
->used
;
1868 *g
= in_glyphs
[otfg
->f
.index
.to
];
1869 if (g
->g
.code
!= otfg
->glyph_id
)
1872 g
->g
.code
= otfg
->glyph_id
;
1875 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1876 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1878 feature_idx
= otfg
->positioning_type
>> 4;
1882 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1883 tag
= PACK_OTF_TAG (tag
);
1884 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1886 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1887 g
->libotf_positioning_type
1888 = otfg
->positioning_type
& OTF_positioning_type_components_mask
;
1894 else if (gsub_features
)
1896 /* Just for checking which features will be applied. */
1897 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1898 if (OTF_drive_gsub_features (otf
, &otf_gstring
, script
, langsys
,
1902 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1906 features
= otf
->gsub
->FeatureList
.Feature
;
1907 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; i
++,
1911 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1912 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1914 feature_idx
= otfg
->positioning_type
>> 4;
1918 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1919 tag
= PACK_OTF_TAG (tag
);
1920 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
1922 MFLTGlyphFT
*g
= in_glyphs
+ j
;
1923 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1930 if (out
->allocated
< out
->used
+ len
)
1935 for (i
= 0; i
< len
; i
++)
1936 out_glyphs
[out
->used
++] = in_glyphs
[i
];
1939 if (gpos_features
&& out
)
1941 MFLTGlyphFT
*base
= NULL
, *mark
= NULL
, *g
;
1942 int x_ppem
, y_ppem
, x_scale
, y_scale
;
1944 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1945 if (OTF_drive_gpos_features (otf
, &otf_gstring
, script
, langsys
,
1952 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
1959 features
= otf
->gpos
->FeatureList
.Feature
;
1960 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
1961 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
1962 x_scale
= ft_face
->size
->metrics
.x_scale
;
1963 y_scale
= ft_face
->size
->metrics
.y_scale
;
1965 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out_glyphs
+ gidx
;
1966 i
< otf_gstring
.used
; i
++, otfg
++)
1968 MFLTGlyphAdjustment
*adjust
= adjustment
;
1970 int positioning_type
, feature_idx
;
1972 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1973 positioning_type
= OTF_POSITIONING_TYPE_GET_FORMAT (otfg
);
1974 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1976 positioning_type
= otfg
->positioning_type
& 0xF;
1977 feature_idx
= otfg
->positioning_type
>> 4;
1981 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1982 tag
= PACK_OTF_TAG (tag
);
1983 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1986 if (! otfg
->glyph_id
)
1987 /* This is a pseudo glyph that contains positioning
1988 information to be accumulated to a real glyph. */
1990 switch (positioning_type
)
1994 case 1: /* Single */
1997 int format
= otfg
->f
.f1
.format
;
1999 if (format
& OTF_XPlacement
)
2001 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
2002 if (format
& OTF_XPlaDevice
)
2004 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
2005 if (format
& OTF_YPlacement
)
2007 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
2008 if (format
& OTF_YPlaDevice
)
2010 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
2011 if (format
& OTF_XAdvance
)
2013 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
2014 if (format
& OTF_XAdvDevice
)
2016 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
2017 if (format
& OTF_YAdvance
)
2019 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
2020 if (format
& OTF_YAdvDevice
)
2022 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
2026 case 3: /* Cursive */
2027 /* Not yet supported. */
2029 case 4: /* Mark-to-Base */
2030 case 5: /* Mark-to-Ligature */
2034 goto label_adjust_anchor
;
2035 default: /* i.e. case 6 Mark-to-Mark */
2039 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2041 int distance
= OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg
);
2045 prev
= g
- distance
;
2046 if (prev
< out_glyphs
)
2052 label_adjust_anchor
:
2054 int base_x
, base_y
, mark_x
, mark_y
;
2055 int this_from
, this_to
;
2057 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
2058 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
2059 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
2060 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
2062 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
2063 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
, prev
->g
.code
,
2064 x_ppem
, y_ppem
, &base_x
, &base_y
);
2065 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
2066 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->g
.code
,
2067 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2068 adjust
->xoff
= (base_x
- mark_x
);
2069 adjust
->yoff
= - (base_y
- mark_y
);
2070 adjust
->back
= (g
- prev
);
2072 adjust
->advance_is_absolute
= 1;
2074 this_from
= g
->g
.from
;
2076 for (j
= 0; prev
+ j
< g
; j
++)
2078 if (this_from
> prev
[j
].g
.from
)
2079 this_from
= prev
[j
].g
.from
;
2080 if (this_to
< prev
[j
].g
.to
)
2081 this_to
= prev
[j
].g
.to
;
2083 for (; prev
<= g
; prev
++)
2085 prev
->g
.from
= this_from
;
2086 prev
->g
.to
= this_to
;
2092 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2094 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2102 else if (gpos_features
)
2104 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
2110 features
= otf
->gpos
->FeatureList
.Feature
;
2111 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
;
2113 if (otfg
->positioning_type
& 0xF)
2115 int feature_idx
= otfg
->positioning_type
>> 4;
2119 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
2120 tag
= PACK_OTF_TAG (tag
);
2121 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
2123 MFLTGlyphFT
*g
= in_glyphs
+ j
;
2124 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
2136 if (out
->allocated
< out
->used
+ len
)
2138 font
->get_metrics (font
, in
, from
, to
);
2139 memcpy (out
->glyphs
+ out
->used
, in_glyphs
, sizeof (MFLTGlyphFT
) * len
);
2145 ftfont_try_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
,
2146 MFLTGlyphString
*in
, int from
, int to
)
2148 return ftfont_drive_otf (font
, spec
, in
, from
, to
, NULL
, NULL
);
2151 #else /* not M17N_FLT_USE_NEW_FEATURE */
2154 ftfont_drive_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
, MFLTGlyphString
*in
,
2156 MFLTGlyphString
*out
, MFLTGlyphAdjustment
*adjustment
)
2158 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
2159 MFLTGlyphFT
*in_glyphs
= (MFLTGlyphFT
*) (in
->glyphs
) + from
;
2160 MFLTGlyphFT
*out_glyphs
= out
? (MFLTGlyphFT
*) (out
->glyphs
) : NULL
;
2161 FT_Face ft_face
= flt_font_ft
->ft_face
;
2162 OTF
*otf
= flt_font_ft
->otf
;
2163 int len
= to
- from
;
2166 char script
[5], *langsys
= NULL
;
2167 char *gsub_features
= NULL
, *gpos_features
= NULL
;
2171 OTF_tag_name (spec
->script
, script
);
2176 langsys
= langsysbuf
;
2177 OTF_tag_name (spec
->langsys
, langsys
);
2181 for (i
= 0; i
< 2; i
++)
2185 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
2187 for (j
= 0; spec
->features
[i
][j
]; j
++);
2188 SAFE_NALLOCA (p
, 6, j
);
2193 for (j
= 0; spec
->features
[i
][j
]; j
++)
2195 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
2196 *p
++ = '*', *p
++ = ',';
2199 OTF_tag_name (spec
->features
[i
][j
], p
);
2208 setup_otf_gstring (len
);
2209 for (i
= 0; i
< len
; i
++)
2211 otf_gstring
.glyphs
[i
].c
= in_glyphs
[i
].g
.c
;
2212 otf_gstring
.glyphs
[i
].glyph_id
= in_glyphs
[i
].g
.code
;
2215 OTF_drive_gdef (otf
, &otf_gstring
);
2220 if (OTF_drive_gsub (otf
, &otf_gstring
, script
, langsys
, gsub_features
)
2223 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
2228 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
2231 int min_from
, max_to
;
2234 g
= out_glyphs
+ out
->used
;
2235 *g
= in_glyphs
[otfg
->f
.index
.from
];
2236 if (g
->g
.code
!= otfg
->glyph_id
)
2239 g
->g
.code
= otfg
->glyph_id
;
2243 min_from
= g
->g
.from
;
2245 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
2247 /* OTFG substitutes multiple glyphs in IN. */
2248 for (j
= from
+ otfg
->f
.index
.from
+ 1;
2249 j
<= from
+ otfg
->f
.index
.to
; j
++)
2251 if (min_from
> in
->glyphs
[j
].from
)
2252 min_from
= in
->glyphs
[j
].from
;
2253 if (max_to
< in
->glyphs
[j
].to
)
2254 max_to
= in
->glyphs
[j
].to
;
2256 g
->g
.from
= min_from
;
2259 for (i
++, otfg
++; (i
< otf_gstring
.used
2260 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
2263 g
= out_glyphs
+ out
->used
;
2264 *g
= in_glyphs
[otfg
->f
.index
.to
];
2265 if (g
->g
.code
!= otfg
->glyph_id
)
2268 g
->g
.code
= otfg
->glyph_id
;
2277 if (out
->allocated
< out
->used
+ len
)
2282 for (i
= 0; i
< len
; i
++)
2283 out_glyphs
[out
->used
++] = in_glyphs
[i
];
2288 MFLTGlyphFT
*base
= NULL
, *mark
= NULL
, *g
;
2289 int x_ppem
, y_ppem
, x_scale
, y_scale
;
2291 if (OTF_drive_gpos (otf
, &otf_gstring
, script
, langsys
, gpos_features
)
2298 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2299 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2300 x_scale
= ft_face
->size
->metrics
.x_scale
;
2301 y_scale
= ft_face
->size
->metrics
.y_scale
;
2303 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out_glyphs
+ gidx
;
2304 i
< otf_gstring
.used
; i
++, otfg
++, g
++)
2308 if (! otfg
->glyph_id
)
2310 switch (otfg
->positioning_type
)
2314 case 1: /* Single */
2317 int format
= otfg
->f
.f1
.format
;
2319 if (format
& OTF_XPlacement
)
2321 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
2322 if (format
& OTF_XPlaDevice
)
2324 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
2325 if (format
& OTF_YPlacement
)
2327 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
2328 if (format
& OTF_YPlaDevice
)
2330 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
2331 if (format
& OTF_XAdvance
)
2333 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
2334 if (format
& OTF_XAdvDevice
)
2336 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
2337 if (format
& OTF_YAdvance
)
2339 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
2340 if (format
& OTF_YAdvDevice
)
2342 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
2343 adjustment
[i
].set
= 1;
2346 case 3: /* Cursive */
2347 /* Not yet supported. */
2349 case 4: /* Mark-to-Base */
2350 case 5: /* Mark-to-Ligature */
2354 goto label_adjust_anchor
;
2355 default: /* i.e. case 6 Mark-to-Mark */
2360 label_adjust_anchor
:
2362 int base_x
, base_y
, mark_x
, mark_y
;
2363 int this_from
, this_to
;
2365 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
2366 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
2367 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
2368 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
2370 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
2371 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
, prev
->g
.code
,
2372 x_ppem
, y_ppem
, &base_x
, &base_y
);
2373 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
2374 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->g
.code
,
2375 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2376 adjustment
[i
].xoff
= (base_x
- mark_x
);
2377 adjustment
[i
].yoff
= - (base_y
- mark_y
);
2378 adjustment
[i
].back
= (g
- prev
);
2379 adjustment
[i
].xadv
= 0;
2380 adjustment
[i
].advance_is_absolute
= 1;
2381 adjustment
[i
].set
= 1;
2382 this_from
= g
->g
.from
;
2384 for (j
= 0; prev
+ j
< g
; j
++)
2386 if (this_from
> prev
[j
].g
.from
)
2387 this_from
= prev
[j
].g
.from
;
2388 if (this_to
< prev
[j
].g
.to
)
2389 this_to
= prev
[j
].g
.to
;
2391 for (; prev
<= g
; prev
++)
2393 prev
->g
.from
= this_from
;
2394 prev
->g
.to
= this_to
;
2398 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2400 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2411 if (out
->allocated
< out
->used
+ len
)
2413 font
->get_metrics (font
, in
, from
, to
);
2414 memcpy (out_glyphs
+ out
->used
, in_glyphs
,
2415 sizeof (MFLTGlyphFT
) * len
);
2420 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2422 static MFLTGlyphString gstring
;
2424 static bool m17n_flt_initialized
;
2427 ftfont_shape_by_flt (Lisp_Object lgstring
, struct font
*font
,
2428 FT_Face ft_face
, OTF
*otf
, FT_Matrix
*matrix
)
2430 ptrdiff_t len
= LGSTRING_GLYPH_LEN (lgstring
);
2432 struct MFLTFontFT flt_font_ft
;
2434 bool with_variation_selector
= false;
2436 if (! m17n_flt_initialized
)
2439 #ifdef M17N_FLT_USE_NEW_FEATURE
2440 mflt_enable_new_feature
= 1;
2441 mflt_try_otf
= ftfont_try_otf
;
2442 #endif /* M17N_FLT_USE_NEW_FEATURE */
2443 m17n_flt_initialized
= 1;
2446 for (i
= 0; i
< len
; i
++)
2448 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2453 c
= LGLYPH_CHAR (g
);
2454 if (CHAR_VARIATION_SELECTOR_P (c
))
2455 with_variation_selector
= true;
2460 if (otf
&& with_variation_selector
)
2462 setup_otf_gstring (len
);
2463 for (i
= 0; i
< len
; i
++)
2465 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2467 otf_gstring
.glyphs
[i
].c
= LGLYPH_CHAR (g
);
2468 otf_gstring
.glyphs
[i
].f
.index
.from
= LGLYPH_FROM (g
);
2469 otf_gstring
.glyphs
[i
].f
.index
.to
= LGLYPH_TO (g
);
2471 OTF_drive_cmap (otf
, &otf_gstring
);
2472 for (i
= 0; i
< otf_gstring
.used
; i
++)
2474 OTF_Glyph
*otfg
= otf_gstring
.glyphs
+ i
;
2475 Lisp_Object g0
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.from
);
2476 Lisp_Object g1
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.to
);
2478 LGLYPH_SET_CODE (g0
, otfg
->glyph_id
);
2479 LGLYPH_SET_TO (g0
, LGLYPH_TO (g1
));
2480 LGSTRING_SET_GLYPH (lgstring
, i
, g0
);
2482 if (len
> otf_gstring
.used
)
2484 len
= otf_gstring
.used
;
2485 LGSTRING_SET_GLYPH (lgstring
, len
, Qnil
);
2490 Lisp_Object family
= Ffont_get (LGSTRING_FONT (lgstring
), QCfamily
);
2493 flt_font_ft
.flt_font
.family
= Mnil
;
2495 flt_font_ft
.flt_font
.family
2496 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family
))));
2498 flt_font_ft
.flt_font
.x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2499 flt_font_ft
.flt_font
.y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2500 flt_font_ft
.flt_font
.get_glyph_id
= ftfont_get_glyph_id
;
2501 flt_font_ft
.flt_font
.get_metrics
= ftfont_get_metrics
;
2502 flt_font_ft
.flt_font
.check_otf
= ftfont_check_otf
;
2503 flt_font_ft
.flt_font
.drive_otf
= ftfont_drive_otf
;
2504 flt_font_ft
.flt_font
.internal
= NULL
;
2505 flt_font_ft
.font
= font
;
2506 flt_font_ft
.ft_face
= ft_face
;
2507 flt_font_ft
.otf
= otf
;
2508 flt_font_ft
.matrix
= matrix
->xx
!= 0 ? matrix
: 0;
2512 /* A little bit ad hoc. Perhaps, shaper must get script and
2513 language information, and select a proper flt for them
2515 int c1
= LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, 1));
2516 /* For the combining characters in the range U+300..U+36F,
2517 "combining" is the sole FLT provided by the m17n-lib. In
2518 addition, it is the sole FLT that can handle the other
2519 combining characters with non-OTF fonts. */
2520 if ((0x300 <= c1
&& c1
<= 0x36F)
2521 || (! otf
&& CHAR_HAS_CATEGORY (c1
, '^')))
2522 flt
= mflt_get (msymbol ("combining"));
2526 flt
= mflt_find (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, 0)),
2527 &flt_font_ft
.flt_font
);
2529 return make_number (0);
2532 MFLTGlyphFT
*glyphs
= (MFLTGlyphFT
*) gstring
.glyphs
;
2533 ptrdiff_t allocated
= gstring
.allocated
;
2534 ptrdiff_t incr_min
= len
- allocated
;
2541 glyphs
= xpalloc (NULL
, &allocated
, incr_min
, INT_MAX
, sizeof *glyphs
);
2545 for (i
= 0; i
< len
; i
++)
2547 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2548 memset (&glyphs
[i
], 0, sizeof glyphs
[i
]);
2549 glyphs
[i
].g
.c
= LGLYPH_CHAR (g
);
2550 if (with_variation_selector
)
2552 glyphs
[i
].g
.code
= LGLYPH_CODE (g
);
2553 glyphs
[i
].g
.encoded
= 1;
2557 gstring
.glyph_size
= sizeof *glyphs
;
2558 gstring
.glyphs
= (MFLTGlyph
*) glyphs
;
2559 gstring
.allocated
= allocated
;
2563 while (mflt_run (&gstring
, 0, len
, &flt_font_ft
.flt_font
, flt
) == -2);
2565 if (gstring
.used
> LGSTRING_GLYPH_LEN (lgstring
))
2567 for (i
= 0; i
< gstring
.used
; i
++)
2569 MFLTGlyphFT
*g
= (MFLTGlyphFT
*) (gstring
.glyphs
) + i
;
2571 g
->g
.from
= LGLYPH_FROM (LGSTRING_GLYPH (lgstring
, g
->g
.from
));
2572 g
->g
.to
= LGLYPH_TO (LGSTRING_GLYPH (lgstring
, g
->g
.to
));
2575 for (i
= 0; i
< gstring
.used
; i
++)
2577 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
, i
);
2578 MFLTGlyphFT
*g
= (MFLTGlyphFT
*) (gstring
.glyphs
) + i
;
2582 lglyph
= LGLYPH_NEW ();
2583 LGSTRING_SET_GLYPH (lgstring
, i
, lglyph
);
2585 LGLYPH_SET_FROM (lglyph
, g
->g
.from
);
2586 LGLYPH_SET_TO (lglyph
, g
->g
.to
);
2587 LGLYPH_SET_CHAR (lglyph
, g
->g
.c
);
2588 LGLYPH_SET_CODE (lglyph
, g
->g
.code
);
2589 LGLYPH_SET_WIDTH (lglyph
, g
->g
.xadv
>> 6);
2590 LGLYPH_SET_LBEARING (lglyph
, g
->g
.lbearing
>> 6);
2591 LGLYPH_SET_RBEARING (lglyph
, g
->g
.rbearing
>> 6);
2592 LGLYPH_SET_ASCENT (lglyph
, g
->g
.ascent
>> 6);
2593 LGLYPH_SET_DESCENT (lglyph
, g
->g
.descent
>> 6);
2596 Lisp_Object vec
= make_uninit_vector (3);
2598 ASET (vec
, 0, make_number (g
->g
.xoff
>> 6));
2599 ASET (vec
, 1, make_number (g
->g
.yoff
>> 6));
2600 ASET (vec
, 2, make_number (g
->g
.xadv
>> 6));
2601 LGLYPH_SET_ADJUSTMENT (lglyph
, vec
);
2604 return make_number (i
);
2608 ftfont_shape (Lisp_Object lgstring
)
2610 struct font
*font
= CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring
));
2611 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
2612 OTF
*otf
= ftfont_get_otf (ftfont_info
);
2614 return ftfont_shape_by_flt (lgstring
, font
, ftfont_info
->ft_size
->face
, otf
,
2615 &ftfont_info
->matrix
);
2618 #endif /* HAVE_M17N_FLT */
2620 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2623 ftfont_variation_glyphs (struct font
*font
, int c
, unsigned variations
[256])
2625 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
2626 OTF
*otf
= ftfont_get_otf (ftfont_info
);
2630 return OTF_get_variation_glyphs (otf
, c
, variations
);
2633 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2634 #endif /* HAVE_LIBOTF */
2636 static const char *const ftfont_booleans
[] = {
2649 static const char *const ftfont_non_booleans
[] = {
2681 ftfont_filter_properties (Lisp_Object font
, Lisp_Object alist
)
2683 font_filter_properties (font
, alist
, ftfont_booleans
, ftfont_non_booleans
);
2688 ftfont_combining_capability (struct font
*font
)
2690 #ifdef HAVE_M17N_FLT
2697 static struct font_driver
const ftfont_driver
=
2699 /* We can't draw a text without device dependent functions. */
2700 .type
= LISPSYM_INITIALLY (Qfreetype
),
2701 .get_cache
= ftfont_get_cache
,
2702 .list
= ftfont_list
,
2703 .match
= ftfont_match
,
2704 .list_family
= ftfont_list_family
,
2705 .open
= ftfont_open
,
2706 .close
= ftfont_close
,
2707 .has_char
= ftfont_has_char
,
2708 .encode_char
= ftfont_encode_char
,
2709 .text_extents
= ftfont_text_extents
,
2710 .get_bitmap
= ftfont_get_bitmap
,
2711 .anchor_point
= ftfont_anchor_point
,
2713 .otf_capability
= ftfont_otf_capability
,
2715 #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
2716 .shape
= ftfont_shape
,
2718 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2719 .get_variation_glyphs
= ftfont_variation_glyphs
,
2721 .filter_properties
= ftfont_filter_properties
,
2722 .combining_capability
= ftfont_combining_capability
,
2726 syms_of_ftfont (void)
2728 /* Symbolic type of this font-driver. */
2729 DEFSYM (Qfreetype
, "freetype");
2731 /* Fontconfig's generic families and their aliases. */
2732 DEFSYM (Qmonospace
, "monospace");
2733 DEFSYM (Qsans_serif
, "sans-serif");
2734 DEFSYM (Qsans
, "sans");
2735 DEFSYM (Qsans__serif
, "sans serif");
2737 staticpro (&freetype_font_cache
);
2738 freetype_font_cache
= list1 (Qt
);
2740 staticpro (&ftfont_generic_family_list
);
2741 ftfont_generic_family_list
= list3 (Fcons (Qmonospace
, Qt
),
2742 Fcons (Qsans_serif
, Qt
),
2745 staticpro (&ft_face_cache
);
2746 ft_face_cache
= Qnil
;
2748 register_font_driver (&ftfont_driver
, NULL
);