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
12 (at your option) any later version.
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
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 /* Flag to tell if FcInit is already called or not. */
39 static bool fc_initialized
;
41 /* Handle to a FreeType library instance. */
42 static FT_Library ft_library
;
44 /* Cache for FreeType fonts. */
45 static Lisp_Object freetype_font_cache
;
47 /* Cache for FT_Face and FcCharSet. */
48 static Lisp_Object ft_face_cache
;
50 /* The actual structure for FreeType font that can be cast to struct
57 /* The following four members must be here in this order to be
58 compatible with struct xftfont_info (in xftfont.c). */
59 bool maybe_otf
; /* Flag to tell if this may be OTF or not. */
61 #endif /* HAVE_LIBOTF */
67 size_t ftfont_info_size
= sizeof (struct ftfont_info
);
71 FTFONT_CACHE_FOR_FACE
,
72 FTFONT_CACHE_FOR_CHARSET
,
73 FTFONT_CACHE_FOR_ENTITY
76 static Lisp_Object
ftfont_pattern_entity (FcPattern
*, Lisp_Object
);
78 static Lisp_Object
ftfont_resolve_generic_family (Lisp_Object
,
80 static Lisp_Object
ftfont_lookup_cache (Lisp_Object
,
81 enum ftfont_cache_for
);
83 static void ftfont_filter_properties (Lisp_Object font
, Lisp_Object alist
);
85 static Lisp_Object
ftfont_combining_capability (struct font
*);
87 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
93 /* characters to distinguish the charset from the others */
95 /* additional constraint by language */
98 FcCharSet
*fc_charset
;
99 } fc_charset_table
[] =
100 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
101 { "iso8859-2", { 0x00A0, 0x010E }},
102 { "iso8859-3", { 0x00A0, 0x0108 }},
103 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
104 { "iso8859-5", { 0x00A0, 0x0401 }},
105 { "iso8859-6", { 0x00A0, 0x060C }},
106 { "iso8859-7", { 0x00A0, 0x0384 }},
107 { "iso8859-8", { 0x00A0, 0x05D0 }},
108 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
109 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
110 { "iso8859-11", { 0x00A0, 0x0E01 }},
111 { "iso8859-13", { 0x00A0, 0x201C }},
112 { "iso8859-14", { 0x00A0, 0x0174 }},
113 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
114 { "iso8859-16", { 0x00A0, 0x0218}},
115 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
116 { "big5-0", { 0xF6B1 }, "zh-tw" },
117 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
118 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
119 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
120 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
121 { "cns11643.1992-3", { 0x201A9 }},
122 { "cns11643.1992-4", { 0x20057 }},
123 { "cns11643.1992-5", { 0x20000 }},
124 { "cns11643.1992-6", { 0x20003 }},
125 { "cns11643.1992-7", { 0x20055 }},
126 { "gbk-0", { 0x4E06 }, "zh-cn"},
127 { "jisx0212.1990-0", { 0x4E44 }},
128 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
129 { "jisx0213.2000-2", { 0xFA49 }},
130 { "jisx0213.2004-1", { 0x20B9F }},
131 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
132 { "tis620.2529-1", { 0x0E01 }, "th"},
133 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
134 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
135 { "mulelao-1", { 0x0E81 }, "lo"},
136 { "unicode-sip", { 0x20000 }},
141 matching_prefix (char const *str
, ptrdiff_t len
, char const *pat
)
143 return len
== strlen (pat
) && c_strncasecmp (str
, pat
, len
) == 0;
146 /* Dirty hack for handing ADSTYLE property.
148 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
149 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
150 "Oblique", "Italic", or any non-normal SWIDTH property names
151 (e.g. SemiCondensed) are appended. In addition, if there's no
152 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
153 "Regular" is used for FC_STYLE (see the function
154 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
156 Unfortunately this behavior is not documented, so the following
157 code may fail if FreeType changes the behavior in the future. */
160 get_adstyle_property (FcPattern
*p
)
167 if ((FcPatternGetString (p
, FC_FONTFORMAT
, 0, &fcstr
) == FcResultMatch
)
168 && xstrcasecmp ((char *) fcstr
, "bdf") != 0
169 && xstrcasecmp ((char *) fcstr
, "pcf") != 0)
170 /* Not a BDF nor PCF font. */
173 if (FcPatternGetString (p
, FC_STYLE
, 0, &fcstr
) != FcResultMatch
)
175 str
= (char *) fcstr
;
176 for (end
= str
; *end
&& *end
!= ' '; end
++);
177 if (matching_prefix (str
, end
- str
, "Regular")
178 || matching_prefix (str
, end
- str
, "Bold")
179 || matching_prefix (str
, end
- str
, "Oblique")
180 || matching_prefix (str
, end
- str
, "Italic"))
182 adstyle
= font_intern_prop (str
, end
- str
, 1);
183 if (font_style_to_value (FONT_WIDTH_INDEX
, adstyle
, 0) >= 0)
189 ftfont_pattern_entity (FcPattern
*p
, Lisp_Object extra
)
191 Lisp_Object key
, cache
, entity
;
199 if (FcPatternGetString (p
, FC_FILE
, 0, &str
) != FcResultMatch
)
201 if (FcPatternGetInteger (p
, FC_INDEX
, 0, &idx
) != FcResultMatch
)
205 key
= Fcons (build_unibyte_string (file
), make_number (idx
));
206 cache
= ftfont_lookup_cache (key
, FTFONT_CACHE_FOR_ENTITY
);
207 entity
= XCAR (cache
);
210 Lisp_Object val
= font_make_entity ();
213 for (i
= 0; i
< FONT_OBJLIST_INDEX
; i
++)
214 ASET (val
, i
, AREF (entity
, i
));
216 ASET (val
, FONT_EXTRA_INDEX
, Fcopy_sequence (extra
));
217 font_put_extra (val
, QCfont_entity
, key
);
221 entity
= font_make_entity ();
222 XSETCAR (cache
, entity
);
224 ASET (entity
, FONT_TYPE_INDEX
, Qfreetype
);
225 ASET (entity
, FONT_REGISTRY_INDEX
, Qiso10646_1
);
227 if (FcPatternGetString (p
, FC_FOUNDRY
, 0, &str
) == FcResultMatch
)
229 char *s
= (char *) str
;
230 ASET (entity
, FONT_FOUNDRY_INDEX
, font_intern_prop (s
, strlen (s
), 1));
232 if (FcPatternGetString (p
, FC_FAMILY
, 0, &str
) == FcResultMatch
)
234 char *s
= (char *) str
;
235 ASET (entity
, FONT_FAMILY_INDEX
, font_intern_prop (s
, strlen (s
), 1));
237 if (FcPatternGetInteger (p
, FC_WEIGHT
, 0, &numeric
) == FcResultMatch
)
239 if (numeric
>= FC_WEIGHT_REGULAR
&& numeric
< FC_WEIGHT_MEDIUM
)
240 numeric
= FC_WEIGHT_MEDIUM
;
241 FONT_SET_STYLE (entity
, FONT_WEIGHT_INDEX
, make_number (numeric
));
243 if (FcPatternGetInteger (p
, FC_SLANT
, 0, &numeric
) == FcResultMatch
)
246 FONT_SET_STYLE (entity
, FONT_SLANT_INDEX
, make_number (numeric
));
248 if (FcPatternGetInteger (p
, FC_WIDTH
, 0, &numeric
) == FcResultMatch
)
250 FONT_SET_STYLE (entity
, FONT_WIDTH_INDEX
, make_number (numeric
));
252 if (FcPatternGetDouble (p
, FC_PIXEL_SIZE
, 0, &dbl
) == FcResultMatch
)
254 ASET (entity
, FONT_SIZE_INDEX
, make_number (dbl
));
257 ASET (entity
, FONT_SIZE_INDEX
, make_number (0));
258 if (FcPatternGetInteger (p
, FC_SPACING
, 0, &numeric
) == FcResultMatch
)
259 ASET (entity
, FONT_SPACING_INDEX
, make_number (numeric
));
260 if (FcPatternGetDouble (p
, FC_DPI
, 0, &dbl
) == FcResultMatch
)
263 ASET (entity
, FONT_DPI_INDEX
, make_number (dpi
));
265 if (FcPatternGetBool (p
, FC_SCALABLE
, 0, &b
) == FcResultMatch
268 ASET (entity
, FONT_SIZE_INDEX
, make_number (0));
269 ASET (entity
, FONT_AVGWIDTH_INDEX
, make_number (0));
273 /* As this font is not scalable, perhaps this is a BDF or PCF
277 ASET (entity
, FONT_ADSTYLE_INDEX
, get_adstyle_property (p
));
278 if ((ft_library
|| FT_Init_FreeType (&ft_library
) == 0)
279 && FT_New_Face (ft_library
, file
, idx
, &ft_face
) == 0)
283 if (FT_Get_BDF_Property (ft_face
, "AVERAGE_WIDTH", &rec
) == 0
284 && rec
.type
== BDF_PROPERTY_TYPE_INTEGER
)
285 ASET (entity
, FONT_AVGWIDTH_INDEX
, make_number (rec
.u
.integer
));
286 FT_Done_Face (ft_face
);
290 ASET (entity
, FONT_EXTRA_INDEX
, Fcopy_sequence (extra
));
291 font_put_extra (entity
, QCfont_entity
, key
);
296 static Lisp_Object ftfont_generic_family_list
;
299 ftfont_resolve_generic_family (Lisp_Object family
, FcPattern
*pattern
)
306 family
= Fintern (Fdowncase (SYMBOL_NAME (family
)), Qnil
);
307 if (EQ (family
, Qmono
))
309 else if (EQ (family
, Qsans
) || EQ (family
, Qsans__serif
))
310 family
= Qsans_serif
;
311 slot
= assq_no_quit (family
, ftfont_generic_family_list
);
314 if (! EQ (XCDR (slot
), Qt
))
316 pattern
= FcPatternDuplicate (pattern
);
319 FcPatternDel (pattern
, FC_FOUNDRY
);
320 FcPatternDel (pattern
, FC_FAMILY
);
321 FcPatternAddString (pattern
, FC_FAMILY
, SYMBOL_FcChar8 (family
));
322 if (FcPatternGetLangSet (pattern
, FC_LANG
, 0, &langset
) != FcResultMatch
)
324 /* This is to avoid the effect of locale. */
325 static const FcChar8 lang
[] = "en";
326 langset
= FcLangSetCreate ();
327 FcLangSetAdd (langset
, lang
);
328 FcPatternAddLangSet (pattern
, FC_LANG
, langset
);
329 FcLangSetDestroy (langset
);
331 FcConfigSubstitute (NULL
, pattern
, FcMatchPattern
);
332 FcDefaultSubstitute (pattern
);
333 match
= FcFontMatch (NULL
, pattern
, &result
);
338 if (FcPatternGetString (match
, FC_FAMILY
, 0, &fam
) == FcResultMatch
)
339 family
= intern ((char *) fam
);
343 XSETCDR (slot
, family
);
344 if (match
) FcPatternDestroy (match
);
346 if (pattern
) FcPatternDestroy (pattern
);
350 struct ftfont_cache_data
353 FcCharSet
*fc_charset
;
357 ftfont_lookup_cache (Lisp_Object key
, enum ftfont_cache_for cache_for
)
359 Lisp_Object cache
, val
, entity
;
360 struct ftfont_cache_data
*cache_data
;
362 if (FONT_ENTITY_P (key
))
365 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
366 eassert (CONSP (val
));
372 if (NILP (ft_face_cache
))
375 cache
= Fgethash (key
, ft_face_cache
, Qnil
);
378 if (NILP (ft_face_cache
))
379 ft_face_cache
= CALLN (Fmake_hash_table
, QCtest
, Qequal
);
380 cache_data
= xmalloc (sizeof *cache_data
);
381 cache_data
->ft_face
= NULL
;
382 cache_data
->fc_charset
= NULL
;
383 val
= make_save_ptr_int (cache_data
, 0);
384 cache
= Fcons (Qnil
, val
);
385 Fputhash (key
, cache
, ft_face_cache
);
390 cache_data
= XSAVE_POINTER (val
, 0);
393 if (cache_for
== FTFONT_CACHE_FOR_ENTITY
)
396 if (cache_for
== FTFONT_CACHE_FOR_FACE
397 ? ! cache_data
->ft_face
: ! cache_data
->fc_charset
)
399 char *filename
= SSDATA (XCAR (key
));
400 int idx
= XINT (XCDR (key
));
402 if (cache_for
== FTFONT_CACHE_FOR_FACE
)
405 && FT_Init_FreeType (&ft_library
) != 0)
407 if (FT_New_Face (ft_library
, filename
, idx
, &cache_data
->ft_face
)
413 FcPattern
*pat
= NULL
;
414 FcFontSet
*fontset
= NULL
;
415 FcObjectSet
*objset
= NULL
;
416 FcCharSet
*charset
= NULL
;
418 pat
= FcPatternBuild (0, FC_FILE
, FcTypeString
, (FcChar8
*) filename
,
419 FC_INDEX
, FcTypeInteger
, idx
, NULL
);
422 objset
= FcObjectSetBuild (FC_CHARSET
, FC_STYLE
, NULL
);
425 fontset
= FcFontList (NULL
, pat
, objset
);
428 if (fontset
&& fontset
->nfont
> 0
429 && (FcPatternGetCharSet (fontset
->fonts
[0], FC_CHARSET
, 0,
432 cache_data
->fc_charset
= FcCharSetCopy (charset
);
434 cache_data
->fc_charset
= FcCharSetCreate ();
438 FcFontSetDestroy (fontset
);
440 FcObjectSetDestroy (objset
);
442 FcPatternDestroy (pat
);
449 ftfont_get_fc_charset (Lisp_Object entity
)
451 Lisp_Object val
, cache
;
452 struct ftfont_cache_data
*cache_data
;
454 cache
= ftfont_lookup_cache (entity
, FTFONT_CACHE_FOR_CHARSET
);
456 cache_data
= XSAVE_POINTER (val
, 0);
457 return cache_data
->fc_charset
;
462 ftfont_get_otf (struct ftfont_info
*ftfont_info
)
466 if (ftfont_info
->otf
)
467 return ftfont_info
->otf
;
468 if (! ftfont_info
->maybe_otf
)
470 otf
= OTF_open_ft_face (ftfont_info
->ft_size
->face
);
471 if (! otf
|| OTF_get_table (otf
, "head") < 0)
475 ftfont_info
->maybe_otf
= 0;
478 ftfont_info
->otf
= otf
;
481 #endif /* HAVE_LIBOTF */
483 static Lisp_Object
ftfont_get_cache (struct frame
*);
484 static Lisp_Object
ftfont_list (struct frame
*, Lisp_Object
);
485 static Lisp_Object
ftfont_match (struct frame
*, Lisp_Object
);
486 static Lisp_Object
ftfont_list_family (struct frame
*);
487 static Lisp_Object
ftfont_open (struct frame
*, Lisp_Object
, int);
488 static void ftfont_close (struct font
*);
489 static int ftfont_has_char (Lisp_Object
, int);
490 static unsigned ftfont_encode_char (struct font
*, int);
491 static void ftfont_text_extents (struct font
*, unsigned *, int,
492 struct font_metrics
*);
493 static int ftfont_get_bitmap (struct font
*, unsigned,
494 struct font_bitmap
*, int);
495 static int ftfont_anchor_point (struct font
*, unsigned, int,
498 static Lisp_Object
ftfont_otf_capability (struct font
*);
499 # ifdef HAVE_M17N_FLT
500 static Lisp_Object
ftfont_shape (Lisp_Object
);
504 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
505 static int ftfont_variation_glyphs (struct font
*, int c
,
506 unsigned variations
[256]);
507 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
509 struct font_driver ftfont_driver
=
511 LISP_INITIALLY_ZERO
, /* Qfreetype */
512 0, /* case insensitive */
517 NULL
, /* free_entity */
520 /* We can't draw a text without device dependent functions. */
521 NULL
, /* prepare_face */
522 NULL
, /* done_face */
526 /* We can't draw a text without device dependent functions. */
529 NULL
, /* free_bitmap */
532 ftfont_otf_capability
,
533 #else /* not HAVE_LIBOTF */
535 #endif /* not HAVE_LIBOTF */
536 NULL
, /* otf_drive */
537 NULL
, /* start_for_frame */
538 NULL
, /* end_for_frame */
539 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
541 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
543 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
546 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
547 ftfont_variation_glyphs
,
552 ftfont_filter_properties
, /* filter_properties */
554 NULL
, /* cached_font_ok */
556 ftfont_combining_capability
,
560 ftfont_get_cache (struct frame
*f
)
562 return freetype_font_cache
;
566 ftfont_get_charset (Lisp_Object registry
)
568 char *str
= SSDATA (SYMBOL_NAME (registry
));
570 char *re
= SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry
)) * 2 + 1);
574 for (i
= j
= 0; i
< SBYTES (SYMBOL_NAME (registry
)); i
++, j
++)
578 else if (str
[i
] == '*')
585 regexp
= make_unibyte_string (re
, j
);
587 for (i
= 0; fc_charset_table
[i
].name
; i
++)
588 if (fast_c_string_match_ignore_case
589 (regexp
, fc_charset_table
[i
].name
,
590 strlen (fc_charset_table
[i
].name
)) >= 0)
592 if (! fc_charset_table
[i
].name
)
594 if (! fc_charset_table
[i
].fc_charset
)
596 FcCharSet
*charset
= FcCharSetCreate ();
597 int *uniquifier
= fc_charset_table
[i
].uniquifier
;
601 for (j
= 0; uniquifier
[j
]; j
++)
602 if (! FcCharSetAddChar (charset
, uniquifier
[j
]))
604 FcCharSetDestroy (charset
);
607 fc_charset_table
[i
].fc_charset
= charset
;
615 unsigned int script_tag
, langsys_tag
;
617 unsigned int *features
[2];
620 #define OTF_SYM_TAG(SYM, TAG) \
622 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
623 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
626 #define OTF_TAG_STR(TAG, P) \
628 (P)[0] = (char) (TAG >> 24); \
629 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
630 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
631 (P)[3] = (char) (TAG & 0xFF); \
636 #define OTF_TAG_SYM(SYM, TAG) \
640 OTF_TAG_STR (TAG, str); \
641 (SYM) = font_intern_prop (str, 4, 1); \
646 static struct OpenTypeSpec
*
647 ftfont_get_open_type_spec (Lisp_Object otf_spec
)
649 struct OpenTypeSpec
*spec
= malloc (sizeof *spec
);
656 spec
->script
= XCAR (otf_spec
);
657 if (! NILP (spec
->script
))
659 OTF_SYM_TAG (spec
->script
, spec
->script_tag
);
660 val
= assq_no_quit (spec
->script
, Votf_script_alist
);
661 if (CONSP (val
) && SYMBOLP (XCDR (val
)))
662 spec
->script
= XCDR (val
);
667 spec
->script_tag
= 0x44464C54; /* "DFLT" */
668 otf_spec
= XCDR (otf_spec
);
669 spec
->langsys_tag
= 0;
670 if (! NILP (otf_spec
))
672 val
= XCAR (otf_spec
);
674 OTF_SYM_TAG (val
, spec
->langsys_tag
);
675 otf_spec
= XCDR (otf_spec
);
677 spec
->nfeatures
[0] = spec
->nfeatures
[1] = 0;
678 for (i
= 0; i
< 2 && ! NILP (otf_spec
); i
++, otf_spec
= XCDR (otf_spec
))
682 val
= XCAR (otf_spec
);
687 (min (PTRDIFF_MAX
, SIZE_MAX
) / sizeof (int) < XINT (len
)
689 : malloc (XINT (len
) * sizeof *spec
->features
[i
]));
690 if (! spec
->features
[i
])
692 if (i
> 0 && spec
->features
[0])
693 free (spec
->features
[0]);
697 for (j
= 0, negative
= 0; CONSP (val
); val
= XCDR (val
))
699 if (NILP (XCAR (val
)))
705 OTF_SYM_TAG (XCAR (val
), tag
);
706 spec
->features
[i
][j
++] = negative
? tag
& 0x80000000 : tag
;
709 spec
->nfeatures
[i
] = j
;
715 ftfont_spec_pattern (Lisp_Object spec
, char *otlayout
, struct OpenTypeSpec
**otspec
, const char **langname
)
717 Lisp_Object tmp
, extra
;
718 FcPattern
*pattern
= NULL
;
719 FcCharSet
*charset
= NULL
;
720 FcLangSet
*langset
= NULL
;
724 Lisp_Object script
= Qnil
;
725 Lisp_Object registry
;
728 if ((n
= FONT_SLANT_NUMERIC (spec
)) >= 0
730 /* Fontconfig doesn't support reverse-italic/oblique. */
733 if (INTEGERP (AREF (spec
, FONT_DPI_INDEX
)))
734 dpi
= XINT (AREF (spec
, FONT_DPI_INDEX
));
735 if (INTEGERP (AREF (spec
, FONT_AVGWIDTH_INDEX
))
736 && XINT (AREF (spec
, FONT_AVGWIDTH_INDEX
)) == 0)
739 registry
= AREF (spec
, FONT_REGISTRY_INDEX
);
741 || EQ (registry
, Qascii_0
)
742 || EQ (registry
, Qiso10646_1
)
743 || EQ (registry
, Qunicode_bmp
))
749 fc_charset_idx
= ftfont_get_charset (registry
);
750 if (fc_charset_idx
< 0)
752 charset
= fc_charset_table
[fc_charset_idx
].fc_charset
;
753 *langname
= fc_charset_table
[fc_charset_idx
].lang
;
754 lang
= (FcChar8
*) *langname
;
757 langset
= FcLangSetCreate ();
760 FcLangSetAdd (langset
, lang
);
765 for (extra
= AREF (spec
, FONT_EXTRA_INDEX
);
766 CONSP (extra
); extra
= XCDR (extra
))
768 Lisp_Object key
, val
;
770 key
= XCAR (XCAR (extra
)), val
= XCDR (XCAR (extra
));
776 else if (EQ (key
, QClang
))
779 langset
= FcLangSetCreate ();
784 if (! FcLangSetAdd (langset
, SYMBOL_FcChar8 (val
)))
788 for (; CONSP (val
); val
= XCDR (val
))
789 if (SYMBOLP (XCAR (val
))
790 && ! FcLangSetAdd (langset
, SYMBOL_FcChar8 (XCAR (val
))))
793 else if (EQ (key
, QCotf
))
797 *otspec
= ftfont_get_open_type_spec (val
);
800 strcpy (otlayout
, "otlayout:");
801 OTF_TAG_STR ((*otspec
)->script_tag
, otlayout
+ 9);
802 script
= (*otspec
)->script
;
805 else if (EQ (key
, QCscript
))
807 else if (EQ (key
, QCscalable
))
808 scalable
= ! NILP (val
);
811 if (! NILP (script
) && ! charset
)
813 Lisp_Object chars
= assq_no_quit (script
, Vscript_representative_chars
);
815 if (CONSP (chars
) && CONSP (CDR (chars
)))
817 charset
= FcCharSetCreate ();
820 for (chars
= XCDR (chars
); CONSP (chars
); chars
= XCDR (chars
))
821 if (CHARACTERP (XCAR (chars
))
822 && ! FcCharSetAddChar (charset
, XFASTINT (XCAR (chars
))))
827 pattern
= FcPatternCreate ();
830 tmp
= AREF (spec
, FONT_FOUNDRY_INDEX
);
832 && ! FcPatternAddString (pattern
, FC_FOUNDRY
, SYMBOL_FcChar8 (tmp
)))
834 tmp
= AREF (spec
, FONT_FAMILY_INDEX
);
836 && ! FcPatternAddString (pattern
, FC_FAMILY
, SYMBOL_FcChar8 (tmp
)))
839 && ! FcPatternAddCharSet (pattern
, FC_CHARSET
, charset
))
842 && ! FcPatternAddLangSet (pattern
, FC_LANG
, langset
))
845 && ! FcPatternAddDouble (pattern
, FC_DPI
, dpi
))
848 && ! FcPatternAddBool (pattern
, FC_SCALABLE
, scalable
? FcTrue
: FcFalse
))
854 /* We come here because of unexpected error in fontconfig API call
855 (usually insufficient memory). */
858 FcPatternDestroy (pattern
);
863 if ((*otspec
)->nfeatures
[0] > 0)
864 free ((*otspec
)->features
[0]);
865 if ((*otspec
)->nfeatures
[1] > 0)
866 free ((*otspec
)->features
[1]);
872 if (langset
) FcLangSetDestroy (langset
);
873 if (charset
&& fc_charset_idx
< 0) FcCharSetDestroy (charset
);
878 ftfont_list (struct frame
*f
, Lisp_Object spec
)
880 Lisp_Object val
= Qnil
, family
, adstyle
;
883 FcFontSet
*fontset
= NULL
;
884 FcObjectSet
*objset
= NULL
;
886 Lisp_Object chars
= Qnil
;
887 char otlayout
[15]; /* For "otlayout:XXXX" */
888 struct OpenTypeSpec
*otspec
= NULL
;
890 const char *langname
= NULL
;
892 if (! fc_initialized
)
898 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
901 if (FcPatternGetCharSet (pattern
, FC_CHARSET
, 0, &charset
) != FcResultMatch
)
903 val
= assq_no_quit (QCscript
, AREF (spec
, FONT_EXTRA_INDEX
));
906 val
= assq_no_quit (XCDR (val
), Vscript_representative_chars
);
907 if (CONSP (val
) && VECTORP (XCDR (val
)))
912 if (INTEGERP (AREF (spec
, FONT_SPACING_INDEX
)))
913 spacing
= XINT (AREF (spec
, FONT_SPACING_INDEX
));
914 family
= AREF (spec
, FONT_FAMILY_INDEX
);
917 Lisp_Object resolved
;
919 resolved
= ftfont_resolve_generic_family (family
, pattern
);
920 if (! NILP (resolved
))
922 FcPatternDel (pattern
, FC_FAMILY
);
923 if (! FcPatternAddString (pattern
, FC_FAMILY
,
924 SYMBOL_FcChar8 (resolved
)))
928 adstyle
= AREF (spec
, FONT_ADSTYLE_INDEX
);
929 if (! NILP (adstyle
) && SBYTES (SYMBOL_NAME (adstyle
)) == 0)
931 objset
= FcObjectSetBuild (FC_FOUNDRY
, FC_FAMILY
, FC_WEIGHT
, FC_SLANT
,
932 FC_WIDTH
, FC_PIXEL_SIZE
, FC_SPACING
, FC_SCALABLE
,
933 FC_STYLE
, FC_FILE
, FC_INDEX
,
936 #endif /* FC_CAPABILITY */
944 FcObjectSetAdd (objset
, FC_CHARSET
);
946 fontset
= FcFontList (NULL
, pattern
, objset
);
947 if (! fontset
|| fontset
->nfont
== 0)
950 /* Need fix because this finds any fonts. */
951 if (fontset
->nfont
== 0 && ! NILP (family
))
953 /* Try matching with configuration. For instance, the
954 configuration may specify "Nimbus Mono L" as an alias of
956 FcPattern
*pat
= FcPatternBuild (0, FC_FAMILY
, FcTypeString
,
957 SYMBOL_FcChar8 (family
), NULL
);
960 if (FcConfigSubstitute (NULL
, pat
, FcMatchPattern
) == FcTrue
)
963 FcPatternGetString (pat
, FC_FAMILY
, i
, &fam
) == FcResultMatch
;
966 FcPatternDel (pattern
, FC_FAMILY
);
967 FcPatternAddString (pattern
, FC_FAMILY
, fam
);
968 FcFontSetDestroy (fontset
);
969 fontset
= FcFontList (NULL
, pattern
, objset
);
970 if (fontset
&& fontset
->nfont
> 0)
976 for (i
= 0; i
< fontset
->nfont
; i
++)
984 if ((FcPatternGetInteger (fontset
->fonts
[i
], FC_SPACING
, 0, &this)
995 if (FcPatternGetString (fontset
->fonts
[i
], FC_CAPABILITY
, 0, &this)
997 || ! strstr ((char *) this, otlayout
))
1000 #endif /* FC_CAPABILITY */
1008 if (FcPatternGetString (fontset
->fonts
[i
], FC_FILE
, 0, &file
)
1011 otf
= OTF_open ((char *) file
);
1014 passed
= (OTF_check_features (otf
, 1, otspec
->script_tag
,
1015 otspec
->langsys_tag
,
1016 otspec
->features
[0],
1017 otspec
->nfeatures
[0]) == 1
1018 && OTF_check_features (otf
, 0, otspec
->script_tag
,
1019 otspec
->langsys_tag
,
1020 otspec
->features
[1],
1021 otspec
->nfeatures
[1]) == 1);
1026 #endif /* HAVE_LIBOTF */
1027 if (VECTORP (chars
))
1031 if (FcPatternGetCharSet (fontset
->fonts
[i
], FC_CHARSET
, 0, &charset
)
1034 for (j
= 0; j
< ASIZE (chars
); j
++)
1035 if (TYPE_RANGED_INTEGERP (FcChar32
, AREF (chars
, j
))
1036 && FcCharSetHasChar (charset
, XFASTINT (AREF (chars
, j
))))
1038 if (j
== ASIZE (chars
))
1041 if (! NILP (adstyle
) || langname
)
1043 Lisp_Object this_adstyle
= get_adstyle_property (fontset
->fonts
[i
]);
1045 if (! NILP (adstyle
)
1046 && (NILP (this_adstyle
)
1047 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle
)),
1048 SSDATA (SYMBOL_NAME (this_adstyle
))) != 0))
1051 && ! NILP (this_adstyle
)
1052 && xstrcasecmp (langname
, SSDATA (SYMBOL_NAME (this_adstyle
))))
1055 entity
= ftfont_pattern_entity (fontset
->fonts
[i
],
1056 AREF (spec
, FONT_EXTRA_INDEX
));
1057 if (! NILP (entity
))
1058 val
= Fcons (entity
, val
);
1060 val
= Fnreverse (val
);
1064 /* We come here because of unexpected error in fontconfig API call
1065 (usually insufficient memory). */
1069 FONT_ADD_LOG ("ftfont-list", spec
, val
);
1070 if (objset
) FcObjectSetDestroy (objset
);
1071 if (fontset
) FcFontSetDestroy (fontset
);
1072 if (pattern
) FcPatternDestroy (pattern
);
1077 ftfont_match (struct frame
*f
, Lisp_Object spec
)
1079 Lisp_Object entity
= Qnil
;
1080 FcPattern
*pattern
, *match
= NULL
;
1082 char otlayout
[15]; /* For "otlayout:XXXX" */
1083 struct OpenTypeSpec
*otspec
= NULL
;
1084 const char *langname
= NULL
;
1086 if (! fc_initialized
)
1092 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
1096 if (INTEGERP (AREF (spec
, FONT_SIZE_INDEX
)))
1100 value
.type
= FcTypeDouble
;
1101 value
.u
.d
= XINT (AREF (spec
, FONT_SIZE_INDEX
));
1102 FcPatternAdd (pattern
, FC_PIXEL_SIZE
, value
, FcFalse
);
1104 if (FcConfigSubstitute (NULL
, pattern
, FcMatchPattern
) == FcTrue
)
1106 FcDefaultSubstitute (pattern
);
1107 match
= FcFontMatch (NULL
, pattern
, &result
);
1110 entity
= ftfont_pattern_entity (match
, AREF (spec
, FONT_EXTRA_INDEX
));
1111 FcPatternDestroy (match
);
1112 if (! NILP (AREF (spec
, FONT_FAMILY_INDEX
))
1113 && NILP (assq_no_quit (AREF (spec
, FONT_FAMILY_INDEX
),
1114 ftfont_generic_family_list
))
1115 && NILP (Fstring_equal (AREF (spec
, FONT_FAMILY_INDEX
),
1116 AREF (entity
, FONT_FAMILY_INDEX
))))
1120 FcPatternDestroy (pattern
);
1122 FONT_ADD_LOG ("ftfont-match", spec
, entity
);
1127 ftfont_list_family (struct frame
*f
)
1129 Lisp_Object list
= Qnil
;
1130 FcPattern
*pattern
= NULL
;
1131 FcFontSet
*fontset
= NULL
;
1132 FcObjectSet
*objset
= NULL
;
1135 if (! fc_initialized
)
1141 pattern
= FcPatternCreate ();
1144 objset
= FcObjectSetBuild (FC_FAMILY
, NULL
);
1147 fontset
= FcFontList (NULL
, pattern
, objset
);
1151 for (i
= 0; i
< fontset
->nfont
; i
++)
1153 FcPattern
*pat
= fontset
->fonts
[i
];
1156 if (FcPatternGetString (pat
, FC_FAMILY
, 0, &str
) == FcResultMatch
)
1157 list
= Fcons (intern ((char *) str
), list
);
1161 if (objset
) FcObjectSetDestroy (objset
);
1162 if (fontset
) FcFontSetDestroy (fontset
);
1163 if (pattern
) FcPatternDestroy (pattern
);
1170 ftfont_open2 (struct frame
*f
,
1173 Lisp_Object font_object
)
1175 struct ftfont_info
*ftfont_info
;
1177 struct ftfont_cache_data
*cache_data
;
1181 Lisp_Object val
, filename
, idx
, cache
;
1187 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
1191 cache
= ftfont_lookup_cache (entity
, FTFONT_CACHE_FOR_FACE
);
1194 filename
= XCAR (val
);
1197 cache_data
= XSAVE_POINTER (XCDR (cache
), 0);
1198 ft_face
= cache_data
->ft_face
;
1199 if (XSAVE_INTEGER (val
, 1) > 0)
1201 /* FT_Face in this cache is already used by the different size. */
1202 if (FT_New_Size (ft_face
, &ft_size
) != 0)
1204 if (FT_Activate_Size (ft_size
) != 0)
1206 FT_Done_Size (ft_size
);
1210 set_save_integer (val
, 1, XSAVE_INTEGER (val
, 1) + 1);
1211 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
1214 if (FT_Set_Pixel_Sizes (ft_face
, size
, size
) != 0)
1216 if (XSAVE_INTEGER (val
, 1) == 0)
1217 FT_Done_Face (ft_face
);
1221 ASET (font_object
, FONT_FILE_INDEX
, filename
);
1222 font
= XFONT_OBJECT (font_object
);
1223 ftfont_info
= (struct ftfont_info
*) font
;
1224 ftfont_info
->ft_size
= ft_face
->size
;
1225 ftfont_info
->index
= XINT (idx
);
1227 ftfont_info
->maybe_otf
= (ft_face
->face_flags
& FT_FACE_FLAG_SFNT
) != 0;
1228 ftfont_info
->otf
= NULL
;
1229 #endif /* HAVE_LIBOTF */
1230 /* This means that there's no need of transformation. */
1231 ftfont_info
->matrix
.xx
= 0;
1232 font
->pixel_size
= size
;
1233 font
->driver
= &ftfont_driver
;
1234 font
->encoding_charset
= font
->repertory_charset
= -1;
1236 upEM
= ft_face
->units_per_EM
;
1237 scalable
= (INTEGERP (AREF (entity
, FONT_AVGWIDTH_INDEX
))
1238 && XINT (AREF (entity
, FONT_AVGWIDTH_INDEX
)) == 0);
1241 font
->ascent
= ft_face
->ascender
* size
/ upEM
+ 0.5;
1242 font
->descent
= - ft_face
->descender
* size
/ upEM
+ 0.5;
1243 font
->height
= ft_face
->height
* size
/ upEM
+ 0.5;
1247 font
->ascent
= ft_face
->size
->metrics
.ascender
>> 6;
1248 font
->descent
= - ft_face
->size
->metrics
.descender
>> 6;
1249 font
->height
= ft_face
->size
->metrics
.height
>> 6;
1251 if (INTEGERP (AREF (entity
, FONT_SPACING_INDEX
)))
1252 spacing
= XINT (AREF (entity
, FONT_SPACING_INDEX
));
1254 spacing
= FC_PROPORTIONAL
;
1255 if (spacing
!= FC_PROPORTIONAL
1257 && spacing
!= FC_DUAL
1258 #endif /* FC_DUAL */
1260 font
->min_width
= font
->average_width
= font
->space_width
1261 = (scalable
? ft_face
->max_advance_width
* size
/ upEM
+ 0.5
1262 : ft_face
->size
->metrics
.max_advance
>> 6);
1267 font
->min_width
= font
->average_width
= font
->space_width
= 0;
1268 for (i
= 32, n
= 0; i
< 127; i
++)
1269 if (FT_Load_Char (ft_face
, i
, FT_LOAD_DEFAULT
) == 0)
1271 int this_width
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1274 && (! font
->min_width
|| font
->min_width
> this_width
))
1275 font
->min_width
= this_width
;
1277 font
->space_width
= this_width
;
1278 font
->average_width
+= this_width
;
1282 font
->average_width
/= n
;
1285 font
->baseline_offset
= 0;
1286 font
->relative_compose
= 0;
1287 font
->default_ascent
= 0;
1288 font
->vertical_centering
= 0;
1291 font
->underline_position
= (-ft_face
->underline_position
* size
/ upEM
1293 font
->underline_thickness
= (ft_face
->underline_thickness
* size
/ upEM
1298 font
->underline_position
= -1;
1299 font
->underline_thickness
= 0;
1306 ftfont_open (struct frame
*f
, Lisp_Object entity
, int pixel_size
)
1308 Lisp_Object font_object
;
1310 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
1313 font_object
= font_build_object (VECSIZE (struct ftfont_info
),
1314 Qfreetype
, entity
, size
);
1315 return ftfont_open2 (f
, entity
, pixel_size
, font_object
);
1319 ftfont_close (struct font
*font
)
1321 /* FIXME: Although this function can be called while garbage-collecting,
1322 the function assumes that Lisp data structures are properly-formed.
1323 This invalid assumption can lead to core dumps (Bug#20890). */
1325 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1326 Lisp_Object val
, cache
;
1328 val
= Fcons (font
->props
[FONT_FILE_INDEX
], make_number (ftfont_info
->index
));
1329 cache
= ftfont_lookup_cache (val
, FTFONT_CACHE_FOR_FACE
);
1330 eassert (CONSP (cache
));
1332 set_save_integer (val
, 1, XSAVE_INTEGER (val
, 1) - 1);
1333 if (XSAVE_INTEGER (val
, 1) == 0)
1335 struct ftfont_cache_data
*cache_data
= XSAVE_POINTER (val
, 0);
1337 FT_Done_Face (cache_data
->ft_face
);
1339 if (ftfont_info
->otf
)
1340 OTF_close (ftfont_info
->otf
);
1342 cache_data
->ft_face
= NULL
;
1345 FT_Done_Size (ftfont_info
->ft_size
);
1349 ftfont_has_char (Lisp_Object font
, int c
)
1351 struct charset
*cs
= NULL
;
1353 if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qja
)
1354 && charset_jisx0208
>= 0)
1355 cs
= CHARSET_FROM_ID (charset_jisx0208
);
1356 else if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qko
)
1357 && charset_ksc5601
>= 0)
1358 cs
= CHARSET_FROM_ID (charset_ksc5601
);
1360 return (ENCODE_CHAR (cs
, c
) != CHARSET_INVALID_CODE (cs
));
1362 if (FONT_ENTITY_P (font
))
1364 FcCharSet
*charset
= ftfont_get_fc_charset (font
);
1366 return (FcCharSetHasChar (charset
, c
) == FcTrue
);
1370 struct ftfont_info
*ftfont_info
;
1372 ftfont_info
= (struct ftfont_info
*) XFONT_OBJECT (font
);
1373 return (FT_Get_Char_Index (ftfont_info
->ft_size
->face
, (FT_ULong
) c
)
1379 ftfont_encode_char (struct font
*font
, int c
)
1381 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1382 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1383 FT_ULong charcode
= c
;
1384 FT_UInt code
= FT_Get_Char_Index (ft_face
, charcode
);
1386 return (code
> 0 ? code
: FONT_INVALID_CODE
);
1390 ftfont_text_extents (struct font
*font
, unsigned int *code
,
1391 int nglyphs
, struct font_metrics
*metrics
)
1393 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1394 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1398 if (ftfont_info
->ft_size
!= ft_face
->size
)
1399 FT_Activate_Size (ftfont_info
->ft_size
);
1401 for (i
= 0, first
= 1; i
< nglyphs
; i
++)
1403 if (FT_Load_Glyph (ft_face
, code
[i
], FT_LOAD_DEFAULT
) == 0)
1405 FT_Glyph_Metrics
*m
= &ft_face
->glyph
->metrics
;
1409 metrics
->lbearing
= m
->horiBearingX
>> 6;
1410 metrics
->rbearing
= (m
->horiBearingX
+ m
->width
) >> 6;
1411 metrics
->ascent
= m
->horiBearingY
>> 6;
1412 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1415 if (metrics
->lbearing
> width
+ (m
->horiBearingX
>> 6))
1416 metrics
->lbearing
= width
+ (m
->horiBearingX
>> 6);
1417 if (metrics
->rbearing
1418 < width
+ ((m
->horiBearingX
+ m
->width
) >> 6))
1420 = width
+ ((m
->horiBearingX
+ m
->width
) >> 6);
1421 if (metrics
->ascent
< (m
->horiBearingY
>> 6))
1422 metrics
->ascent
= m
->horiBearingY
>> 6;
1423 if (metrics
->descent
> ((m
->height
- m
->horiBearingY
) >> 6))
1424 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1425 width
+= m
->horiAdvance
>> 6;
1428 width
+= font
->space_width
;
1430 metrics
->width
= width
;
1434 ftfont_get_bitmap (struct font
*font
, unsigned int code
, struct font_bitmap
*bitmap
, int bits_per_pixel
)
1436 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1437 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1438 FT_Int32 load_flags
= FT_LOAD_RENDER
;
1440 if (ftfont_info
->ft_size
!= ft_face
->size
)
1441 FT_Activate_Size (ftfont_info
->ft_size
);
1442 if (bits_per_pixel
== 1)
1444 #ifdef FT_LOAD_TARGET_MONO
1445 load_flags
|= FT_LOAD_TARGET_MONO
;
1447 load_flags
|= FT_LOAD_MONOCHROME
;
1450 else if (bits_per_pixel
!= 8)
1451 /* We don't support such a rendering. */
1454 if (FT_Load_Glyph (ft_face
, code
, load_flags
) != 0)
1456 bitmap
->bits_per_pixel
1457 = (ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_MONO
? 1
1458 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
? 8
1459 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD
? 8
1460 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD_V
? 8
1462 if (bitmap
->bits_per_pixel
< 0)
1463 /* We don't support that kind of pixel mode. */
1465 bitmap
->rows
= ft_face
->glyph
->bitmap
.rows
;
1466 bitmap
->width
= ft_face
->glyph
->bitmap
.width
;
1467 bitmap
->pitch
= ft_face
->glyph
->bitmap
.pitch
;
1468 bitmap
->buffer
= ft_face
->glyph
->bitmap
.buffer
;
1469 bitmap
->left
= ft_face
->glyph
->bitmap_left
;
1470 bitmap
->top
= ft_face
->glyph
->bitmap_top
;
1471 bitmap
->advance
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1477 ftfont_anchor_point (struct font
*font
, unsigned int code
, int idx
,
1480 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1481 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1483 if (ftfont_info
->ft_size
!= ft_face
->size
)
1484 FT_Activate_Size (ftfont_info
->ft_size
);
1485 if (FT_Load_Glyph (ft_face
, code
, FT_LOAD_DEFAULT
) != 0)
1487 if (ft_face
->glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
1489 if (idx
>= ft_face
->glyph
->outline
.n_points
)
1491 *x
= ft_face
->glyph
->outline
.points
[idx
].x
;
1492 *y
= ft_face
->glyph
->outline
.points
[idx
].y
;
1499 ftfont_otf_features (OTF_GSUB_GPOS
*gsub_gpos
)
1501 Lisp_Object scripts
, langsyses
, features
, sym
;
1504 for (scripts
= Qnil
, i
= gsub_gpos
->ScriptList
.ScriptCount
- 1; i
>= 0; i
--)
1506 OTF_Script
*otf_script
= gsub_gpos
->ScriptList
.Script
+ i
;
1508 for (langsyses
= Qnil
, j
= otf_script
->LangSysCount
- 1; j
>= -1; j
--)
1510 OTF_LangSys
*otf_langsys
;
1513 otf_langsys
= otf_script
->LangSys
+ j
;
1514 else if (otf_script
->DefaultLangSysOffset
)
1515 otf_langsys
= &otf_script
->DefaultLangSys
;
1519 for (features
= Qnil
, k
= otf_langsys
->FeatureCount
- 1; k
>= 0; k
--)
1521 l
= otf_langsys
->FeatureIndex
[k
];
1522 if (l
>= gsub_gpos
->FeatureList
.FeatureCount
)
1524 OTF_TAG_SYM (sym
, gsub_gpos
->FeatureList
.Feature
[l
].FeatureTag
);
1525 features
= Fcons (sym
, features
);
1528 OTF_TAG_SYM (sym
, otf_script
->LangSysRecord
[j
].LangSysTag
);
1531 langsyses
= Fcons (Fcons (sym
, features
), langsyses
);
1534 OTF_TAG_SYM (sym
, gsub_gpos
->ScriptList
.Script
[i
].ScriptTag
);
1535 scripts
= Fcons (Fcons (sym
, langsyses
), scripts
);
1543 ftfont_otf_capability (struct font
*font
)
1545 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1546 OTF
*otf
= ftfont_get_otf (ftfont_info
);
1547 Lisp_Object gsub_gpos
;
1551 gsub_gpos
= Fcons (Qnil
, Qnil
);
1552 if (OTF_get_table (otf
, "GSUB") == 0
1553 && otf
->gsub
->FeatureList
.FeatureCount
> 0)
1554 XSETCAR (gsub_gpos
, ftfont_otf_features (otf
->gsub
));
1555 if (OTF_get_table (otf
, "GPOS") == 0
1556 && otf
->gpos
->FeatureList
.FeatureCount
> 0)
1557 XSETCDR (gsub_gpos
, ftfont_otf_features (otf
->gpos
));
1561 #ifdef HAVE_M17N_FLT
1563 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1564 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1565 /* We can use the new feature of libotf and m17n-flt to handle the
1566 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1567 some Agian scripts. */
1568 #define M17N_FLT_USE_NEW_FEATURE
1580 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1581 We use this structure instead of MFLTGlyph to utilize the new
1582 feature of libotf ver.0.9.15 which requires saving and restoring
1583 the value of OTF_GlyphString.positioning_type in the succeeding
1584 calls of the callback function MFLTFont.drive_otf (which is set to
1585 ftfont_drive_otf). */
1589 unsigned int libotf_positioning_type
;
1593 ftfont_get_glyph_id (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1596 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1597 FT_Face ft_face
= flt_font_ft
->ft_face
;
1600 for (g
= (MFLTGlyphFT
*) (gstring
->glyphs
) + from
; from
< to
; g
++, from
++)
1603 FT_UInt code
= FT_Get_Char_Index (ft_face
, g
->g
.code
);
1605 g
->g
.code
= code
> 0 ? code
: FONT_INVALID_CODE
;
1611 /* Operators for 26.6 fixed fractional pixel format */
1613 #define FLOOR(x) ((x) & -64)
1614 #define CEIL(x) (((x)+63) & -64)
1615 #define ROUND(x) (((x)+32) & -64)
1618 ftfont_get_metrics (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1621 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1622 FT_Face ft_face
= flt_font_ft
->ft_face
;
1625 for (g
= (MFLTGlyphFT
*) (gstring
->glyphs
) + from
; from
< to
; g
++, from
++)
1626 if (! g
->g
.measured
)
1628 if (g
->g
.code
!= FONT_INVALID_CODE
)
1630 FT_Glyph_Metrics
*m
;
1632 if (FT_Load_Glyph (ft_face
, g
->g
.code
, FT_LOAD_DEFAULT
) != 0)
1634 m
= &ft_face
->glyph
->metrics
;
1635 if (flt_font_ft
->matrix
)
1640 v
[0].x
= v
[1].x
= m
->horiBearingX
;
1641 v
[2].x
= v
[3].x
= m
->horiBearingX
+ m
->width
;
1642 v
[0].y
= v
[2].y
= m
->horiBearingY
;
1643 v
[1].y
= v
[3].y
= m
->horiBearingY
- m
->height
;
1644 for (i
= 0; i
< 4; i
++)
1645 FT_Vector_Transform (v
+ i
, flt_font_ft
->matrix
);
1646 g
->g
.lbearing
= v
[0].x
< v
[1].x
? FLOOR (v
[0].x
) : FLOOR (v
[1].x
);
1647 g
->g
.rbearing
= v
[2].x
> v
[3].x
? CEIL (v
[2].x
) : CEIL (v
[3].x
);
1648 g
->g
.ascent
= v
[0].y
> v
[2].y
? CEIL (v
[0].y
) : CEIL (v
[2].y
);
1649 g
->g
.descent
= v
[1].y
< v
[3].y
? - FLOOR (v
[1].y
) : - FLOOR (v
[3].y
);
1653 g
->g
.lbearing
= FLOOR (m
->horiBearingX
);
1654 g
->g
.rbearing
= CEIL (m
->horiBearingX
+ m
->width
);
1655 g
->g
.ascent
= CEIL (m
->horiBearingY
);
1656 g
->g
.descent
= - FLOOR (m
->horiBearingY
- m
->height
);
1658 g
->g
.xadv
= ROUND (ft_face
->glyph
->advance
.x
);
1663 g
->g
.rbearing
= g
->g
.xadv
= flt_font_ft
->font
->space_width
<< 6;
1664 g
->g
.ascent
= flt_font_ft
->font
->ascent
<< 6;
1665 g
->g
.descent
= flt_font_ft
->font
->descent
<< 6;
1674 ftfont_check_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
)
1676 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1678 #define FEATURE_ANY(IDX) \
1679 (spec->features[IDX] \
1680 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1682 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1683 OTF
*otf
= flt_font_ft
->otf
;
1688 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1689 /* Return true iff any of GSUB or GPOS support the script (and
1692 && (OTF_check_features (otf
, 0, spec
->script
, spec
->langsys
,
1694 || OTF_check_features (otf
, 1, spec
->script
, spec
->langsys
,
1697 for (i
= 0; i
< 2; i
++)
1698 if (! FEATURE_ANY (i
))
1700 if (FEATURE_NONE (i
))
1703 && OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1708 if (spec
->features
[i
][0] == 0xFFFFFFFF)
1711 || OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1717 for (n
= 1; spec
->features
[i
][n
]; n
++);
1719 SAFE_NALLOCA (tags
, 1, n
);
1720 for (n
= 0, negative
= 0; spec
->features
[i
][n
]; n
++)
1722 if (spec
->features
[i
][n
] == 0xFFFFFFFF)
1725 tags
[n
- 1] = spec
->features
[i
][n
] | 0x80000000;
1727 tags
[n
] = spec
->features
[i
][n
];
1730 #ifndef M17N_FLT_USE_NEW_FEATURE
1731 passed
= n
- negative
> 0;
1734 passed
= (OTF_check_features (otf
, i
== 0, spec
->script
,
1735 spec
->langsys
, tags
, n
- negative
)
1746 #define DEVICE_DELTA(table, size) \
1747 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1748 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1752 adjust_anchor (FT_Face ft_face
, OTF_Anchor
*anchor
,
1753 unsigned code
, int x_ppem
, int y_ppem
, int *x
, int *y
)
1755 if (anchor
->AnchorFormat
== 2)
1757 FT_Outline
*outline
;
1758 int ap
= anchor
->f
.f1
.AnchorPoint
;
1760 FT_Load_Glyph (ft_face
, (FT_UInt
) code
, FT_LOAD_MONOCHROME
);
1761 outline
= &ft_face
->glyph
->outline
;
1762 if (ap
< outline
->n_points
)
1764 *x
= outline
->points
[ap
].x
<< 6;
1765 *y
= outline
->points
[ap
].y
<< 6;
1768 else if (anchor
->AnchorFormat
== 3)
1770 if (anchor
->f
.f2
.XDeviceTable
.offset
1771 && anchor
->f
.f2
.XDeviceTable
.DeltaValue
)
1772 *x
+= DEVICE_DELTA (anchor
->f
.f2
.XDeviceTable
, x_ppem
);
1773 if (anchor
->f
.f2
.YDeviceTable
.offset
1774 && anchor
->f
.f2
.YDeviceTable
.DeltaValue
)
1775 *y
+= DEVICE_DELTA (anchor
->f
.f2
.YDeviceTable
, y_ppem
);
1779 static OTF_GlyphString otf_gstring
;
1782 setup_otf_gstring (int size
)
1784 if (otf_gstring
.size
< size
)
1786 ptrdiff_t new_size
= otf_gstring
.size
;
1787 xfree (otf_gstring
.glyphs
);
1788 otf_gstring
.glyphs
= xpalloc (NULL
, &new_size
, size
- otf_gstring
.size
,
1789 INT_MAX
, sizeof *otf_gstring
.glyphs
);
1790 otf_gstring
.size
= new_size
;
1792 otf_gstring
.used
= size
;
1793 memset (otf_gstring
.glyphs
, 0, sizeof (OTF_Glyph
) * size
);
1796 #ifdef M17N_FLT_USE_NEW_FEATURE
1798 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1799 #define PACK_OTF_TAG(TAG) \
1800 ((((TAG) & 0x7F000000) >> 3) \
1801 | (((TAG) & 0x7F0000) >> 2) \
1802 | (((TAG) & 0x7F00) >> 1) \
1805 /* Assuming that FONT is an OpenType font, apply OpenType features
1806 specified in SPEC on glyphs between FROM and TO of IN, and record
1807 the lastly applied feature in each glyph of IN. If OUT is not
1808 NULL, append the resulting glyphs to OUT while storing glyph
1809 position adjustment information in ADJUSTMENT. */
1812 ftfont_drive_otf (MFLTFont
*font
,
1814 MFLTGlyphString
*in
,
1817 MFLTGlyphString
*out
,
1818 MFLTGlyphAdjustment
*adjustment
)
1820 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1821 MFLTGlyphFT
*in_glyphs
= (MFLTGlyphFT
*) (in
->glyphs
) + from
;
1822 MFLTGlyphFT
*out_glyphs
= out
? (MFLTGlyphFT
*) (out
->glyphs
) : NULL
;
1823 FT_Face ft_face
= flt_font_ft
->ft_face
;
1824 OTF
*otf
= flt_font_ft
->otf
;
1825 int len
= to
- from
;
1828 char script
[5], *langsys
= NULL
;
1829 char *gsub_features
= NULL
, *gpos_features
= NULL
;
1830 OTF_Feature
*features
;
1834 OTF_tag_name (spec
->script
, script
);
1839 langsys
= langsysbuf
;
1840 OTF_tag_name (spec
->langsys
, langsys
);
1844 for (i
= 0; i
< 2; i
++)
1848 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
1850 for (j
= 0; spec
->features
[i
][j
]; j
++);
1851 SAFE_NALLOCA (p
, 6, j
);
1856 for (j
= 0; spec
->features
[i
][j
]; j
++)
1858 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
1859 *p
++ = '*', *p
++ = ',';
1862 OTF_tag_name (spec
->features
[i
][j
], p
);
1871 setup_otf_gstring (len
);
1872 for (i
= 0; i
< len
; i
++)
1874 otf_gstring
.glyphs
[i
].c
= in_glyphs
[i
].g
.c
& 0x11FFFF;
1875 otf_gstring
.glyphs
[i
].glyph_id
= in_glyphs
[i
].g
.code
;
1876 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1877 otf_gstring
.glyphs
[i
].positioning_type
= in_glyphs
[i
].libotf_positioning_type
;
1881 OTF_drive_gdef (otf
, &otf_gstring
);
1882 gidx
= out
? out
->used
: from
;
1884 if (gsub_features
&& out
)
1886 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1887 if (OTF_drive_gsub_features (otf
, &otf_gstring
, script
, langsys
,
1891 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1895 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
1900 features
= otf
->gsub
->FeatureList
.Feature
;
1901 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
1904 int min_from
, max_to
;
1907 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1908 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1910 feature_idx
= otfg
->positioning_type
>> 4;
1912 g
= out_glyphs
+ out
->used
;
1913 *g
= in_glyphs
[otfg
->f
.index
.from
];
1914 if (g
->g
.code
!= otfg
->glyph_id
)
1917 g
->g
.code
= otfg
->glyph_id
;
1921 min_from
= g
->g
.from
;
1923 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
1925 /* OTFG substitutes multiple glyphs in IN. */
1926 for (j
= otfg
->f
.index
.from
+ 1; j
<= otfg
->f
.index
.to
; j
++)
1928 if (min_from
> in_glyphs
[j
].g
.from
)
1929 min_from
= in_glyphs
[j
].g
.from
;
1930 if (max_to
< in_glyphs
[j
].g
.to
)
1931 max_to
= in_glyphs
[j
].g
.to
;
1933 g
->g
.from
= min_from
;
1938 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1939 tag
= PACK_OTF_TAG (tag
);
1940 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1942 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1943 g
->libotf_positioning_type
1944 = otfg
->positioning_type
& OTF_positioning_type_components_mask
;
1946 for (i
++, otfg
++; (i
< otf_gstring
.used
1947 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
1950 g
= out_glyphs
+ out
->used
;
1951 *g
= in_glyphs
[otfg
->f
.index
.to
];
1952 if (g
->g
.code
!= otfg
->glyph_id
)
1955 g
->g
.code
= otfg
->glyph_id
;
1958 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1959 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1961 feature_idx
= otfg
->positioning_type
>> 4;
1965 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1966 tag
= PACK_OTF_TAG (tag
);
1967 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1969 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1970 g
->libotf_positioning_type
1971 = otfg
->positioning_type
& OTF_positioning_type_components_mask
;
1977 else if (gsub_features
)
1979 /* Just for checking which features will be applied. */
1980 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1981 if (OTF_drive_gsub_features (otf
, &otf_gstring
, script
, langsys
,
1985 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1989 features
= otf
->gsub
->FeatureList
.Feature
;
1990 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; i
++,
1994 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1995 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1997 feature_idx
= otfg
->positioning_type
>> 4;
2001 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
2002 tag
= PACK_OTF_TAG (tag
);
2003 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
2005 MFLTGlyphFT
*g
= in_glyphs
+ j
;
2006 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
2013 if (out
->allocated
< out
->used
+ len
)
2018 for (i
= 0; i
< len
; i
++)
2019 out_glyphs
[out
->used
++] = in_glyphs
[i
];
2022 if (gpos_features
&& out
)
2024 MFLTGlyphFT
*base
= NULL
, *mark
= NULL
, *g
;
2025 int x_ppem
, y_ppem
, x_scale
, y_scale
;
2027 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2028 if (OTF_drive_gpos_features (otf
, &otf_gstring
, script
, langsys
,
2035 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
2042 features
= otf
->gpos
->FeatureList
.Feature
;
2043 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2044 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2045 x_scale
= ft_face
->size
->metrics
.x_scale
;
2046 y_scale
= ft_face
->size
->metrics
.y_scale
;
2048 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out_glyphs
+ gidx
;
2049 i
< otf_gstring
.used
; i
++, otfg
++)
2051 MFLTGlyphAdjustment
*adjust
= adjustment
;
2053 int positioning_type
, feature_idx
;
2055 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2056 positioning_type
= OTF_POSITIONING_TYPE_GET_FORMAT (otfg
);
2057 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
2059 positioning_type
= otfg
->positioning_type
& 0xF;
2060 feature_idx
= otfg
->positioning_type
>> 4;
2064 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
2065 tag
= PACK_OTF_TAG (tag
);
2066 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
2069 if (! otfg
->glyph_id
)
2070 /* This is a pseudo glyph that contains positioning
2071 information to be accumulated to a real glyph. */
2073 switch (positioning_type
)
2077 case 1: /* Single */
2080 int format
= otfg
->f
.f1
.format
;
2082 if (format
& OTF_XPlacement
)
2084 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
2085 if (format
& OTF_XPlaDevice
)
2087 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
2088 if (format
& OTF_YPlacement
)
2090 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
2091 if (format
& OTF_YPlaDevice
)
2093 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
2094 if (format
& OTF_XAdvance
)
2096 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
2097 if (format
& OTF_XAdvDevice
)
2099 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
2100 if (format
& OTF_YAdvance
)
2102 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
2103 if (format
& OTF_YAdvDevice
)
2105 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
2109 case 3: /* Cursive */
2110 /* Not yet supported. */
2112 case 4: /* Mark-to-Base */
2113 case 5: /* Mark-to-Ligature */
2117 goto label_adjust_anchor
;
2118 default: /* i.e. case 6 Mark-to-Mark */
2122 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2124 int distance
= OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg
);
2128 prev
= g
- distance
;
2129 if (prev
< out_glyphs
)
2135 label_adjust_anchor
:
2137 int base_x
, base_y
, mark_x
, mark_y
;
2138 int this_from
, this_to
;
2140 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
2141 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
2142 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
2143 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
2145 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
2146 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
, prev
->g
.code
,
2147 x_ppem
, y_ppem
, &base_x
, &base_y
);
2148 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
2149 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->g
.code
,
2150 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2151 adjust
->xoff
= (base_x
- mark_x
);
2152 adjust
->yoff
= - (base_y
- mark_y
);
2153 adjust
->back
= (g
- prev
);
2155 adjust
->advance_is_absolute
= 1;
2157 this_from
= g
->g
.from
;
2159 for (j
= 0; prev
+ j
< g
; j
++)
2161 if (this_from
> prev
[j
].g
.from
)
2162 this_from
= prev
[j
].g
.from
;
2163 if (this_to
< prev
[j
].g
.to
)
2164 this_to
= prev
[j
].g
.to
;
2166 for (; prev
<= g
; prev
++)
2168 prev
->g
.from
= this_from
;
2169 prev
->g
.to
= this_to
;
2175 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2177 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2185 else if (gpos_features
)
2187 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
2193 features
= otf
->gpos
->FeatureList
.Feature
;
2194 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
;
2196 if (otfg
->positioning_type
& 0xF)
2198 int feature_idx
= otfg
->positioning_type
>> 4;
2202 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
2203 tag
= PACK_OTF_TAG (tag
);
2204 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
2206 MFLTGlyphFT
*g
= in_glyphs
+ j
;
2207 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
2219 if (out
->allocated
< out
->used
+ len
)
2221 font
->get_metrics (font
, in
, from
, to
);
2222 memcpy (out
->glyphs
+ out
->used
, in_glyphs
, sizeof (MFLTGlyphFT
) * len
);
2228 ftfont_try_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
,
2229 MFLTGlyphString
*in
, int from
, int to
)
2231 return ftfont_drive_otf (font
, spec
, in
, from
, to
, NULL
, NULL
);
2234 #else /* not M17N_FLT_USE_NEW_FEATURE */
2237 ftfont_drive_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
, MFLTGlyphString
*in
,
2239 MFLTGlyphString
*out
, MFLTGlyphAdjustment
*adjustment
)
2241 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
2242 MFLTGlyphFT
*in_glyphs
= (MFLTGlyphFT
*) (in
->glyphs
) + from
;
2243 MFLTGlyphFT
*out_glyphs
= out
? (MFLTGlyphFT
*) (out
->glyphs
) : NULL
;
2244 FT_Face ft_face
= flt_font_ft
->ft_face
;
2245 OTF
*otf
= flt_font_ft
->otf
;
2246 int len
= to
- from
;
2249 char script
[5], *langsys
= NULL
;
2250 char *gsub_features
= NULL
, *gpos_features
= NULL
;
2254 OTF_tag_name (spec
->script
, script
);
2259 langsys
= langsysbuf
;
2260 OTF_tag_name (spec
->langsys
, langsys
);
2264 for (i
= 0; i
< 2; i
++)
2268 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
2270 for (j
= 0; spec
->features
[i
][j
]; j
++);
2271 SAFE_NALLOCA (p
, 6, j
);
2276 for (j
= 0; spec
->features
[i
][j
]; j
++)
2278 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
2279 *p
++ = '*', *p
++ = ',';
2282 OTF_tag_name (spec
->features
[i
][j
], p
);
2291 setup_otf_gstring (len
);
2292 for (i
= 0; i
< len
; i
++)
2294 otf_gstring
.glyphs
[i
].c
= in_glyphs
[i
].g
.c
;
2295 otf_gstring
.glyphs
[i
].glyph_id
= in_glyphs
[i
].g
.code
;
2298 OTF_drive_gdef (otf
, &otf_gstring
);
2303 if (OTF_drive_gsub (otf
, &otf_gstring
, script
, langsys
, gsub_features
)
2306 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
2311 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
2314 int min_from
, max_to
;
2317 g
= out_glyphs
+ out
->used
;
2318 *g
= in_glyphs
[otfg
->f
.index
.from
];
2319 if (g
->g
.code
!= otfg
->glyph_id
)
2322 g
->g
.code
= otfg
->glyph_id
;
2326 min_from
= g
->g
.from
;
2328 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
2330 /* OTFG substitutes multiple glyphs in IN. */
2331 for (j
= from
+ otfg
->f
.index
.from
+ 1;
2332 j
<= from
+ otfg
->f
.index
.to
; j
++)
2334 if (min_from
> in
->glyphs
[j
].from
)
2335 min_from
= in
->glyphs
[j
].from
;
2336 if (max_to
< in
->glyphs
[j
].to
)
2337 max_to
= in
->glyphs
[j
].to
;
2339 g
->g
.from
= min_from
;
2342 for (i
++, otfg
++; (i
< otf_gstring
.used
2343 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
2346 g
= out_glyphs
+ out
->used
;
2347 *g
= in_glyphs
[otfg
->f
.index
.to
];
2348 if (g
->g
.code
!= otfg
->glyph_id
)
2351 g
->g
.code
= otfg
->glyph_id
;
2360 if (out
->allocated
< out
->used
+ len
)
2365 for (i
= 0; i
< len
; i
++)
2366 out_glyphs
[out
->used
++] = in_glyphs
[i
];
2371 MFLTGlyphFT
*base
= NULL
, *mark
= NULL
, *g
;
2372 int x_ppem
, y_ppem
, x_scale
, y_scale
;
2374 if (OTF_drive_gpos (otf
, &otf_gstring
, script
, langsys
, gpos_features
)
2381 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2382 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2383 x_scale
= ft_face
->size
->metrics
.x_scale
;
2384 y_scale
= ft_face
->size
->metrics
.y_scale
;
2386 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out_glyphs
+ gidx
;
2387 i
< otf_gstring
.used
; i
++, otfg
++, g
++)
2391 if (! otfg
->glyph_id
)
2393 switch (otfg
->positioning_type
)
2397 case 1: /* Single */
2400 int format
= otfg
->f
.f1
.format
;
2402 if (format
& OTF_XPlacement
)
2404 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
2405 if (format
& OTF_XPlaDevice
)
2407 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
2408 if (format
& OTF_YPlacement
)
2410 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
2411 if (format
& OTF_YPlaDevice
)
2413 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
2414 if (format
& OTF_XAdvance
)
2416 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
2417 if (format
& OTF_XAdvDevice
)
2419 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
2420 if (format
& OTF_YAdvance
)
2422 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
2423 if (format
& OTF_YAdvDevice
)
2425 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
2426 adjustment
[i
].set
= 1;
2429 case 3: /* Cursive */
2430 /* Not yet supported. */
2432 case 4: /* Mark-to-Base */
2433 case 5: /* Mark-to-Ligature */
2437 goto label_adjust_anchor
;
2438 default: /* i.e. case 6 Mark-to-Mark */
2443 label_adjust_anchor
:
2445 int base_x
, base_y
, mark_x
, mark_y
;
2446 int this_from
, this_to
;
2448 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
2449 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
2450 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
2451 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
2453 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
2454 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
, prev
->g
.code
,
2455 x_ppem
, y_ppem
, &base_x
, &base_y
);
2456 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
2457 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->g
.code
,
2458 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2459 adjustment
[i
].xoff
= (base_x
- mark_x
);
2460 adjustment
[i
].yoff
= - (base_y
- mark_y
);
2461 adjustment
[i
].back
= (g
- prev
);
2462 adjustment
[i
].xadv
= 0;
2463 adjustment
[i
].advance_is_absolute
= 1;
2464 adjustment
[i
].set
= 1;
2465 this_from
= g
->g
.from
;
2467 for (j
= 0; prev
+ j
< g
; j
++)
2469 if (this_from
> prev
[j
].g
.from
)
2470 this_from
= prev
[j
].g
.from
;
2471 if (this_to
< prev
[j
].g
.to
)
2472 this_to
= prev
[j
].g
.to
;
2474 for (; prev
<= g
; prev
++)
2476 prev
->g
.from
= this_from
;
2477 prev
->g
.to
= this_to
;
2481 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2483 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2494 if (out
->allocated
< out
->used
+ len
)
2496 font
->get_metrics (font
, in
, from
, to
);
2497 memcpy (out_glyphs
+ out
->used
, in_glyphs
,
2498 sizeof (MFLTGlyphFT
) * len
);
2503 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2505 static MFLTGlyphString gstring
;
2507 static bool m17n_flt_initialized
;
2510 ftfont_shape_by_flt (Lisp_Object lgstring
, struct font
*font
,
2511 FT_Face ft_face
, OTF
*otf
, FT_Matrix
*matrix
)
2513 ptrdiff_t len
= LGSTRING_GLYPH_LEN (lgstring
);
2515 struct MFLTFontFT flt_font_ft
;
2517 bool with_variation_selector
= false;
2519 if (! m17n_flt_initialized
)
2522 #ifdef M17N_FLT_USE_NEW_FEATURE
2523 mflt_enable_new_feature
= 1;
2524 mflt_try_otf
= ftfont_try_otf
;
2525 #endif /* M17N_FLT_USE_NEW_FEATURE */
2526 m17n_flt_initialized
= 1;
2529 for (i
= 0; i
< len
; i
++)
2531 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2536 c
= LGLYPH_CHAR (g
);
2537 if (CHAR_VARIATION_SELECTOR_P (c
))
2538 with_variation_selector
= true;
2543 if (otf
&& with_variation_selector
)
2545 setup_otf_gstring (len
);
2546 for (i
= 0; i
< len
; i
++)
2548 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2550 otf_gstring
.glyphs
[i
].c
= LGLYPH_CHAR (g
);
2551 otf_gstring
.glyphs
[i
].f
.index
.from
= LGLYPH_FROM (g
);
2552 otf_gstring
.glyphs
[i
].f
.index
.to
= LGLYPH_TO (g
);
2554 OTF_drive_cmap (otf
, &otf_gstring
);
2555 for (i
= 0; i
< otf_gstring
.used
; i
++)
2557 OTF_Glyph
*otfg
= otf_gstring
.glyphs
+ i
;
2558 Lisp_Object g0
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.from
);
2559 Lisp_Object g1
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.to
);
2561 LGLYPH_SET_CODE (g0
, otfg
->glyph_id
);
2562 LGLYPH_SET_TO (g0
, LGLYPH_TO (g1
));
2563 LGSTRING_SET_GLYPH (lgstring
, i
, g0
);
2565 if (len
> otf_gstring
.used
)
2567 len
= otf_gstring
.used
;
2568 LGSTRING_SET_GLYPH (lgstring
, len
, Qnil
);
2573 Lisp_Object family
= Ffont_get (LGSTRING_FONT (lgstring
), QCfamily
);
2576 flt_font_ft
.flt_font
.family
= Mnil
;
2578 flt_font_ft
.flt_font
.family
2579 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family
))));
2581 flt_font_ft
.flt_font
.x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2582 flt_font_ft
.flt_font
.y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2583 flt_font_ft
.flt_font
.get_glyph_id
= ftfont_get_glyph_id
;
2584 flt_font_ft
.flt_font
.get_metrics
= ftfont_get_metrics
;
2585 flt_font_ft
.flt_font
.check_otf
= ftfont_check_otf
;
2586 flt_font_ft
.flt_font
.drive_otf
= ftfont_drive_otf
;
2587 flt_font_ft
.flt_font
.internal
= NULL
;
2588 flt_font_ft
.font
= font
;
2589 flt_font_ft
.ft_face
= ft_face
;
2590 flt_font_ft
.otf
= otf
;
2591 flt_font_ft
.matrix
= matrix
->xx
!= 0 ? matrix
: 0;
2595 /* A little bit ad hoc. Perhaps, shaper must get script and
2596 language information, and select a proper flt for them
2598 int c1
= LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, 1));
2599 if (CHAR_HAS_CATEGORY (c1
, '^'))
2600 flt
= mflt_get (msymbol ("combining"));
2604 flt
= mflt_find (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, 0)),
2605 &flt_font_ft
.flt_font
);
2607 return make_number (0);
2610 MFLTGlyphFT
*glyphs
= (MFLTGlyphFT
*) gstring
.glyphs
;
2611 ptrdiff_t allocated
= gstring
.allocated
;
2612 ptrdiff_t incr_min
= len
- allocated
;
2619 glyphs
= xpalloc (NULL
, &allocated
, incr_min
, INT_MAX
, sizeof *glyphs
);
2623 for (i
= 0; i
< len
; i
++)
2625 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2626 memset (&glyphs
[i
], 0, sizeof glyphs
[i
]);
2627 glyphs
[i
].g
.c
= LGLYPH_CHAR (g
);
2628 if (with_variation_selector
)
2630 glyphs
[i
].g
.code
= LGLYPH_CODE (g
);
2631 glyphs
[i
].g
.encoded
= 1;
2635 gstring
.glyph_size
= sizeof *glyphs
;
2636 gstring
.glyphs
= (MFLTGlyph
*) glyphs
;
2637 gstring
.allocated
= allocated
;
2641 while (mflt_run (&gstring
, 0, len
, &flt_font_ft
.flt_font
, flt
) == -2);
2643 if (gstring
.used
> LGSTRING_GLYPH_LEN (lgstring
))
2645 for (i
= 0; i
< gstring
.used
; i
++)
2647 MFLTGlyphFT
*g
= (MFLTGlyphFT
*) (gstring
.glyphs
) + i
;
2649 g
->g
.from
= LGLYPH_FROM (LGSTRING_GLYPH (lgstring
, g
->g
.from
));
2650 g
->g
.to
= LGLYPH_TO (LGSTRING_GLYPH (lgstring
, g
->g
.to
));
2653 for (i
= 0; i
< gstring
.used
; i
++)
2655 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
, i
);
2656 MFLTGlyphFT
*g
= (MFLTGlyphFT
*) (gstring
.glyphs
) + i
;
2660 lglyph
= LGLYPH_NEW ();
2661 LGSTRING_SET_GLYPH (lgstring
, i
, lglyph
);
2663 LGLYPH_SET_FROM (lglyph
, g
->g
.from
);
2664 LGLYPH_SET_TO (lglyph
, g
->g
.to
);
2665 LGLYPH_SET_CHAR (lglyph
, g
->g
.c
);
2666 LGLYPH_SET_CODE (lglyph
, g
->g
.code
);
2667 LGLYPH_SET_WIDTH (lglyph
, g
->g
.xadv
>> 6);
2668 LGLYPH_SET_LBEARING (lglyph
, g
->g
.lbearing
>> 6);
2669 LGLYPH_SET_RBEARING (lglyph
, g
->g
.rbearing
>> 6);
2670 LGLYPH_SET_ASCENT (lglyph
, g
->g
.ascent
>> 6);
2671 LGLYPH_SET_DESCENT (lglyph
, g
->g
.descent
>> 6);
2674 Lisp_Object vec
= make_uninit_vector (3);
2676 ASET (vec
, 0, make_number (g
->g
.xoff
>> 6));
2677 ASET (vec
, 1, make_number (g
->g
.yoff
>> 6));
2678 ASET (vec
, 2, make_number (g
->g
.xadv
>> 6));
2679 LGLYPH_SET_ADJUSTMENT (lglyph
, vec
);
2682 return make_number (i
);
2686 ftfont_shape (Lisp_Object lgstring
)
2688 struct font
*font
= CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring
));
2689 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
2690 OTF
*otf
= ftfont_get_otf (ftfont_info
);
2692 return ftfont_shape_by_flt (lgstring
, font
, ftfont_info
->ft_size
->face
, otf
,
2693 &ftfont_info
->matrix
);
2696 #endif /* HAVE_M17N_FLT */
2698 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2701 ftfont_variation_glyphs (struct font
*font
, int c
, unsigned variations
[256])
2703 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
2704 OTF
*otf
= ftfont_get_otf (ftfont_info
);
2708 return OTF_get_variation_glyphs (otf
, c
, variations
);
2711 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2712 #endif /* HAVE_LIBOTF */
2714 static const char *const ftfont_booleans
[] = {
2727 static const char *const ftfont_non_booleans
[] = {
2759 ftfont_filter_properties (Lisp_Object font
, Lisp_Object alist
)
2761 font_filter_properties (font
, alist
, ftfont_booleans
, ftfont_non_booleans
);
2766 ftfont_combining_capability (struct font
*font
)
2768 #ifdef HAVE_M17N_FLT
2776 syms_of_ftfont (void)
2778 /* Symbolic type of this font-driver. */
2779 DEFSYM (Qfreetype
, "freetype");
2781 /* Fontconfig's generic families and their aliases. */
2782 DEFSYM (Qmonospace
, "monospace");
2783 DEFSYM (Qsans_serif
, "sans-serif");
2784 DEFSYM (Qsans
, "sans");
2785 DEFSYM (Qsans__serif
, "sans serif");
2787 staticpro (&freetype_font_cache
);
2788 freetype_font_cache
= list1 (Qt
);
2790 staticpro (&ftfont_generic_family_list
);
2791 ftfont_generic_family_list
= list3 (Fcons (Qmonospace
, Qt
),
2792 Fcons (Qsans_serif
, Qt
),
2795 staticpro (&ft_face_cache
);
2796 ft_face_cache
= Qnil
;
2798 ftfont_driver
.type
= Qfreetype
;
2799 register_font_driver (&ftfont_driver
, NULL
);