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 /* 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);
573 for (i
= j
= 0; i
< SBYTES (SYMBOL_NAME (registry
)); i
++, j
++)
577 else if (str
[i
] == '*')
584 AUTO_STRING_WITH_LEN (regexp
, re
, j
);
585 for (i
= 0; fc_charset_table
[i
].name
; i
++)
586 if (fast_c_string_match_ignore_case
587 (regexp
, fc_charset_table
[i
].name
,
588 strlen (fc_charset_table
[i
].name
)) >= 0)
591 if (! fc_charset_table
[i
].name
)
593 if (! fc_charset_table
[i
].fc_charset
)
595 FcCharSet
*charset
= FcCharSetCreate ();
596 int *uniquifier
= fc_charset_table
[i
].uniquifier
;
600 for (j
= 0; uniquifier
[j
]; j
++)
601 if (! FcCharSetAddChar (charset
, uniquifier
[j
]))
603 FcCharSetDestroy (charset
);
606 fc_charset_table
[i
].fc_charset
= charset
;
614 unsigned int script_tag
, langsys_tag
;
616 unsigned int *features
[2];
619 #define OTF_SYM_TAG(SYM, TAG) \
621 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
622 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
625 #define OTF_TAG_STR(TAG, P) \
627 (P)[0] = (char) (TAG >> 24); \
628 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
629 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
630 (P)[3] = (char) (TAG & 0xFF); \
635 #define OTF_TAG_SYM(SYM, TAG) \
639 OTF_TAG_STR (TAG, str); \
640 (SYM) = font_intern_prop (str, 4, 1); \
645 static struct OpenTypeSpec
*
646 ftfont_get_open_type_spec (Lisp_Object otf_spec
)
648 struct OpenTypeSpec
*spec
= malloc (sizeof *spec
);
655 spec
->script
= XCAR (otf_spec
);
656 if (! NILP (spec
->script
))
658 OTF_SYM_TAG (spec
->script
, spec
->script_tag
);
659 val
= assq_no_quit (spec
->script
, Votf_script_alist
);
660 if (CONSP (val
) && SYMBOLP (XCDR (val
)))
661 spec
->script
= XCDR (val
);
666 spec
->script_tag
= 0x44464C54; /* "DFLT" */
667 otf_spec
= XCDR (otf_spec
);
668 spec
->langsys_tag
= 0;
669 if (! NILP (otf_spec
))
671 val
= XCAR (otf_spec
);
673 OTF_SYM_TAG (val
, spec
->langsys_tag
);
674 otf_spec
= XCDR (otf_spec
);
676 spec
->nfeatures
[0] = spec
->nfeatures
[1] = 0;
677 for (i
= 0; i
< 2 && ! NILP (otf_spec
); i
++, otf_spec
= XCDR (otf_spec
))
681 val
= XCAR (otf_spec
);
686 (min (PTRDIFF_MAX
, SIZE_MAX
) / sizeof (int) < XINT (len
)
688 : malloc (XINT (len
) * sizeof *spec
->features
[i
]));
689 if (! spec
->features
[i
])
691 if (i
> 0 && spec
->features
[0])
692 free (spec
->features
[0]);
696 for (j
= 0, negative
= 0; CONSP (val
); val
= XCDR (val
))
698 if (NILP (XCAR (val
)))
704 OTF_SYM_TAG (XCAR (val
), tag
);
705 spec
->features
[i
][j
++] = negative
? tag
& 0x80000000 : tag
;
708 spec
->nfeatures
[i
] = j
;
714 ftfont_spec_pattern (Lisp_Object spec
, char *otlayout
, struct OpenTypeSpec
**otspec
, const char **langname
)
716 Lisp_Object tmp
, extra
;
717 FcPattern
*pattern
= NULL
;
718 FcCharSet
*charset
= NULL
;
719 FcLangSet
*langset
= NULL
;
723 Lisp_Object script
= Qnil
;
724 Lisp_Object registry
;
727 if ((n
= FONT_SLANT_NUMERIC (spec
)) >= 0
729 /* Fontconfig doesn't support reverse-italic/oblique. */
732 if (INTEGERP (AREF (spec
, FONT_DPI_INDEX
)))
733 dpi
= XINT (AREF (spec
, FONT_DPI_INDEX
));
734 if (INTEGERP (AREF (spec
, FONT_AVGWIDTH_INDEX
))
735 && XINT (AREF (spec
, FONT_AVGWIDTH_INDEX
)) == 0)
738 registry
= AREF (spec
, FONT_REGISTRY_INDEX
);
740 || EQ (registry
, Qascii_0
)
741 || EQ (registry
, Qiso10646_1
)
742 || EQ (registry
, Qunicode_bmp
))
748 fc_charset_idx
= ftfont_get_charset (registry
);
749 if (fc_charset_idx
< 0)
751 charset
= fc_charset_table
[fc_charset_idx
].fc_charset
;
752 *langname
= fc_charset_table
[fc_charset_idx
].lang
;
753 lang
= (FcChar8
*) *langname
;
756 langset
= FcLangSetCreate ();
759 FcLangSetAdd (langset
, lang
);
764 for (extra
= AREF (spec
, FONT_EXTRA_INDEX
);
765 CONSP (extra
); extra
= XCDR (extra
))
767 Lisp_Object key
, val
;
769 key
= XCAR (XCAR (extra
)), val
= XCDR (XCAR (extra
));
775 else if (EQ (key
, QClang
))
778 langset
= FcLangSetCreate ();
783 if (! FcLangSetAdd (langset
, SYMBOL_FcChar8 (val
)))
787 for (; CONSP (val
); val
= XCDR (val
))
788 if (SYMBOLP (XCAR (val
))
789 && ! FcLangSetAdd (langset
, SYMBOL_FcChar8 (XCAR (val
))))
792 else if (EQ (key
, QCotf
))
796 *otspec
= ftfont_get_open_type_spec (val
);
799 strcpy (otlayout
, "otlayout:");
800 OTF_TAG_STR ((*otspec
)->script_tag
, otlayout
+ 9);
801 script
= (*otspec
)->script
;
804 else if (EQ (key
, QCscript
))
806 else if (EQ (key
, QCscalable
))
807 scalable
= ! NILP (val
);
810 if (! NILP (script
) && ! charset
)
812 Lisp_Object chars
= assq_no_quit (script
, Vscript_representative_chars
);
814 if (CONSP (chars
) && CONSP (CDR (chars
)))
816 charset
= FcCharSetCreate ();
819 for (chars
= XCDR (chars
); CONSP (chars
); chars
= XCDR (chars
))
820 if (CHARACTERP (XCAR (chars
))
821 && ! FcCharSetAddChar (charset
, XFASTINT (XCAR (chars
))))
826 pattern
= FcPatternCreate ();
829 tmp
= AREF (spec
, FONT_FOUNDRY_INDEX
);
831 && ! FcPatternAddString (pattern
, FC_FOUNDRY
, SYMBOL_FcChar8 (tmp
)))
833 tmp
= AREF (spec
, FONT_FAMILY_INDEX
);
835 && ! FcPatternAddString (pattern
, FC_FAMILY
, SYMBOL_FcChar8 (tmp
)))
838 && ! FcPatternAddCharSet (pattern
, FC_CHARSET
, charset
))
841 && ! FcPatternAddLangSet (pattern
, FC_LANG
, langset
))
844 && ! FcPatternAddDouble (pattern
, FC_DPI
, dpi
))
847 && ! FcPatternAddBool (pattern
, FC_SCALABLE
, scalable
? FcTrue
: FcFalse
))
853 /* We come here because of unexpected error in fontconfig API call
854 (usually insufficient memory). */
857 FcPatternDestroy (pattern
);
862 if ((*otspec
)->nfeatures
[0] > 0)
863 free ((*otspec
)->features
[0]);
864 if ((*otspec
)->nfeatures
[1] > 0)
865 free ((*otspec
)->features
[1]);
871 if (langset
) FcLangSetDestroy (langset
);
872 if (charset
&& fc_charset_idx
< 0) FcCharSetDestroy (charset
);
877 ftfont_list (struct frame
*f
, Lisp_Object spec
)
879 Lisp_Object val
= Qnil
, family
, adstyle
;
882 FcFontSet
*fontset
= NULL
;
883 FcObjectSet
*objset
= NULL
;
885 Lisp_Object chars
= Qnil
;
886 char otlayout
[15]; /* For "otlayout:XXXX" */
887 struct OpenTypeSpec
*otspec
= NULL
;
889 const char *langname
= NULL
;
891 if (! fc_initialized
)
897 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
900 if (FcPatternGetCharSet (pattern
, FC_CHARSET
, 0, &charset
) != FcResultMatch
)
902 val
= assq_no_quit (QCscript
, AREF (spec
, FONT_EXTRA_INDEX
));
905 val
= assq_no_quit (XCDR (val
), Vscript_representative_chars
);
906 if (CONSP (val
) && VECTORP (XCDR (val
)))
911 if (INTEGERP (AREF (spec
, FONT_SPACING_INDEX
)))
912 spacing
= XINT (AREF (spec
, FONT_SPACING_INDEX
));
913 family
= AREF (spec
, FONT_FAMILY_INDEX
);
916 Lisp_Object resolved
;
918 resolved
= ftfont_resolve_generic_family (family
, pattern
);
919 if (! NILP (resolved
))
921 FcPatternDel (pattern
, FC_FAMILY
);
922 if (! FcPatternAddString (pattern
, FC_FAMILY
,
923 SYMBOL_FcChar8 (resolved
)))
927 adstyle
= AREF (spec
, FONT_ADSTYLE_INDEX
);
928 if (! NILP (adstyle
) && SBYTES (SYMBOL_NAME (adstyle
)) == 0)
930 objset
= FcObjectSetBuild (FC_FOUNDRY
, FC_FAMILY
, FC_WEIGHT
, FC_SLANT
,
931 FC_WIDTH
, FC_PIXEL_SIZE
, FC_SPACING
, FC_SCALABLE
,
932 FC_STYLE
, FC_FILE
, FC_INDEX
,
935 #endif /* FC_CAPABILITY */
943 FcObjectSetAdd (objset
, FC_CHARSET
);
945 fontset
= FcFontList (NULL
, pattern
, objset
);
946 if (! fontset
|| fontset
->nfont
== 0)
949 /* Need fix because this finds any fonts. */
950 if (fontset
->nfont
== 0 && ! NILP (family
))
952 /* Try matching with configuration. For instance, the
953 configuration may specify "Nimbus Mono L" as an alias of
955 FcPattern
*pat
= FcPatternBuild (0, FC_FAMILY
, FcTypeString
,
956 SYMBOL_FcChar8 (family
), NULL
);
959 if (FcConfigSubstitute (NULL
, pat
, FcMatchPattern
) == FcTrue
)
962 FcPatternGetString (pat
, FC_FAMILY
, i
, &fam
) == FcResultMatch
;
965 FcPatternDel (pattern
, FC_FAMILY
);
966 FcPatternAddString (pattern
, FC_FAMILY
, fam
);
967 FcFontSetDestroy (fontset
);
968 fontset
= FcFontList (NULL
, pattern
, objset
);
969 if (fontset
&& fontset
->nfont
> 0)
975 for (i
= 0; i
< fontset
->nfont
; i
++)
983 if ((FcPatternGetInteger (fontset
->fonts
[i
], FC_SPACING
, 0, &this)
994 if (FcPatternGetString (fontset
->fonts
[i
], FC_CAPABILITY
, 0, &this)
996 || ! strstr ((char *) this, otlayout
))
999 #endif /* FC_CAPABILITY */
1007 if (FcPatternGetString (fontset
->fonts
[i
], FC_FILE
, 0, &file
)
1010 otf
= OTF_open ((char *) file
);
1013 passed
= (OTF_check_features (otf
, 1, otspec
->script_tag
,
1014 otspec
->langsys_tag
,
1015 otspec
->features
[0],
1016 otspec
->nfeatures
[0]) == 1
1017 && OTF_check_features (otf
, 0, otspec
->script_tag
,
1018 otspec
->langsys_tag
,
1019 otspec
->features
[1],
1020 otspec
->nfeatures
[1]) == 1);
1025 #endif /* HAVE_LIBOTF */
1026 if (VECTORP (chars
))
1030 if (FcPatternGetCharSet (fontset
->fonts
[i
], FC_CHARSET
, 0, &charset
)
1033 for (j
= 0; j
< ASIZE (chars
); j
++)
1034 if (TYPE_RANGED_INTEGERP (FcChar32
, AREF (chars
, j
))
1035 && FcCharSetHasChar (charset
, XFASTINT (AREF (chars
, j
))))
1037 if (j
== ASIZE (chars
))
1040 if (! NILP (adstyle
) || langname
)
1042 Lisp_Object this_adstyle
= get_adstyle_property (fontset
->fonts
[i
]);
1044 if (! NILP (adstyle
)
1045 && (NILP (this_adstyle
)
1046 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle
)),
1047 SSDATA (SYMBOL_NAME (this_adstyle
))) != 0))
1050 && ! NILP (this_adstyle
)
1051 && xstrcasecmp (langname
, SSDATA (SYMBOL_NAME (this_adstyle
))))
1054 entity
= ftfont_pattern_entity (fontset
->fonts
[i
],
1055 AREF (spec
, FONT_EXTRA_INDEX
));
1056 if (! NILP (entity
))
1057 val
= Fcons (entity
, val
);
1059 val
= Fnreverse (val
);
1063 /* We come here because of unexpected error in fontconfig API call
1064 (usually insufficient memory). */
1068 FONT_ADD_LOG ("ftfont-list", spec
, val
);
1069 if (objset
) FcObjectSetDestroy (objset
);
1070 if (fontset
) FcFontSetDestroy (fontset
);
1071 if (pattern
) FcPatternDestroy (pattern
);
1076 ftfont_match (struct frame
*f
, Lisp_Object spec
)
1078 Lisp_Object entity
= Qnil
;
1079 FcPattern
*pattern
, *match
= NULL
;
1081 char otlayout
[15]; /* For "otlayout:XXXX" */
1082 struct OpenTypeSpec
*otspec
= NULL
;
1083 const char *langname
= NULL
;
1085 if (! fc_initialized
)
1091 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
1095 if (INTEGERP (AREF (spec
, FONT_SIZE_INDEX
)))
1099 value
.type
= FcTypeDouble
;
1100 value
.u
.d
= XINT (AREF (spec
, FONT_SIZE_INDEX
));
1101 FcPatternAdd (pattern
, FC_PIXEL_SIZE
, value
, FcFalse
);
1103 if (FcConfigSubstitute (NULL
, pattern
, FcMatchPattern
) == FcTrue
)
1105 FcDefaultSubstitute (pattern
);
1106 match
= FcFontMatch (NULL
, pattern
, &result
);
1109 entity
= ftfont_pattern_entity (match
, AREF (spec
, FONT_EXTRA_INDEX
));
1110 FcPatternDestroy (match
);
1111 if (! NILP (AREF (spec
, FONT_FAMILY_INDEX
))
1112 && NILP (assq_no_quit (AREF (spec
, FONT_FAMILY_INDEX
),
1113 ftfont_generic_family_list
))
1114 && NILP (Fstring_equal (AREF (spec
, FONT_FAMILY_INDEX
),
1115 AREF (entity
, FONT_FAMILY_INDEX
))))
1119 FcPatternDestroy (pattern
);
1121 FONT_ADD_LOG ("ftfont-match", spec
, entity
);
1126 ftfont_list_family (struct frame
*f
)
1128 Lisp_Object list
= Qnil
;
1129 FcPattern
*pattern
= NULL
;
1130 FcFontSet
*fontset
= NULL
;
1131 FcObjectSet
*objset
= NULL
;
1134 if (! fc_initialized
)
1140 pattern
= FcPatternCreate ();
1143 objset
= FcObjectSetBuild (FC_FAMILY
, NULL
);
1146 fontset
= FcFontList (NULL
, pattern
, objset
);
1150 for (i
= 0; i
< fontset
->nfont
; i
++)
1152 FcPattern
*pat
= fontset
->fonts
[i
];
1155 if (FcPatternGetString (pat
, FC_FAMILY
, 0, &str
) == FcResultMatch
)
1156 list
= Fcons (intern ((char *) str
), list
);
1160 if (objset
) FcObjectSetDestroy (objset
);
1161 if (fontset
) FcFontSetDestroy (fontset
);
1162 if (pattern
) FcPatternDestroy (pattern
);
1169 ftfont_open2 (struct frame
*f
,
1172 Lisp_Object font_object
)
1174 struct ftfont_info
*ftfont_info
;
1176 struct ftfont_cache_data
*cache_data
;
1180 Lisp_Object val
, filename
, idx
, cache
;
1186 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
1190 cache
= ftfont_lookup_cache (entity
, FTFONT_CACHE_FOR_FACE
);
1193 filename
= XCAR (val
);
1196 cache_data
= XSAVE_POINTER (XCDR (cache
), 0);
1197 ft_face
= cache_data
->ft_face
;
1198 if (XSAVE_INTEGER (val
, 1) > 0)
1200 /* FT_Face in this cache is already used by the different size. */
1201 if (FT_New_Size (ft_face
, &ft_size
) != 0)
1203 if (FT_Activate_Size (ft_size
) != 0)
1205 FT_Done_Size (ft_size
);
1209 set_save_integer (val
, 1, XSAVE_INTEGER (val
, 1) + 1);
1210 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
1213 if (FT_Set_Pixel_Sizes (ft_face
, size
, size
) != 0)
1215 if (XSAVE_INTEGER (val
, 1) == 0)
1216 FT_Done_Face (ft_face
);
1220 ASET (font_object
, FONT_FILE_INDEX
, filename
);
1221 font
= XFONT_OBJECT (font_object
);
1222 ftfont_info
= (struct ftfont_info
*) font
;
1223 ftfont_info
->ft_size
= ft_face
->size
;
1224 ftfont_info
->index
= XINT (idx
);
1226 ftfont_info
->maybe_otf
= (ft_face
->face_flags
& FT_FACE_FLAG_SFNT
) != 0;
1227 ftfont_info
->otf
= NULL
;
1228 #endif /* HAVE_LIBOTF */
1229 /* This means that there's no need of transformation. */
1230 ftfont_info
->matrix
.xx
= 0;
1231 font
->pixel_size
= size
;
1232 font
->driver
= &ftfont_driver
;
1233 font
->encoding_charset
= font
->repertory_charset
= -1;
1235 upEM
= ft_face
->units_per_EM
;
1236 scalable
= (INTEGERP (AREF (entity
, FONT_AVGWIDTH_INDEX
))
1237 && XINT (AREF (entity
, FONT_AVGWIDTH_INDEX
)) == 0);
1240 font
->ascent
= ft_face
->ascender
* size
/ upEM
+ 0.5;
1241 font
->descent
= - ft_face
->descender
* size
/ upEM
+ 0.5;
1242 font
->height
= ft_face
->height
* size
/ upEM
+ 0.5;
1246 font
->ascent
= ft_face
->size
->metrics
.ascender
>> 6;
1247 font
->descent
= - ft_face
->size
->metrics
.descender
>> 6;
1248 font
->height
= ft_face
->size
->metrics
.height
>> 6;
1250 if (INTEGERP (AREF (entity
, FONT_SPACING_INDEX
)))
1251 spacing
= XINT (AREF (entity
, FONT_SPACING_INDEX
));
1253 spacing
= FC_PROPORTIONAL
;
1254 if (spacing
!= FC_PROPORTIONAL
1256 && spacing
!= FC_DUAL
1257 #endif /* FC_DUAL */
1259 font
->min_width
= font
->average_width
= font
->space_width
1260 = (scalable
? ft_face
->max_advance_width
* size
/ upEM
+ 0.5
1261 : ft_face
->size
->metrics
.max_advance
>> 6);
1266 font
->min_width
= font
->average_width
= font
->space_width
= 0;
1267 for (i
= 32, n
= 0; i
< 127; i
++)
1268 if (FT_Load_Char (ft_face
, i
, FT_LOAD_DEFAULT
) == 0)
1270 int this_width
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1273 && (! font
->min_width
|| font
->min_width
> this_width
))
1274 font
->min_width
= this_width
;
1276 font
->space_width
= this_width
;
1277 font
->average_width
+= this_width
;
1281 font
->average_width
/= n
;
1284 font
->baseline_offset
= 0;
1285 font
->relative_compose
= 0;
1286 font
->default_ascent
= 0;
1287 font
->vertical_centering
= 0;
1290 font
->underline_position
= (-ft_face
->underline_position
* size
/ upEM
1292 font
->underline_thickness
= (ft_face
->underline_thickness
* size
/ upEM
1297 font
->underline_position
= -1;
1298 font
->underline_thickness
= 0;
1305 ftfont_open (struct frame
*f
, Lisp_Object entity
, int pixel_size
)
1307 Lisp_Object font_object
;
1309 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
1312 font_object
= font_build_object (VECSIZE (struct ftfont_info
),
1313 Qfreetype
, entity
, size
);
1314 return ftfont_open2 (f
, entity
, pixel_size
, font_object
);
1318 ftfont_close (struct font
*font
)
1320 /* FIXME: Although this function can be called while garbage-collecting,
1321 the function assumes that Lisp data structures are properly-formed.
1322 This invalid assumption can lead to core dumps (Bug#20890). */
1324 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1325 Lisp_Object val
, cache
;
1327 val
= Fcons (font
->props
[FONT_FILE_INDEX
], make_number (ftfont_info
->index
));
1328 cache
= ftfont_lookup_cache (val
, FTFONT_CACHE_FOR_FACE
);
1329 eassert (CONSP (cache
));
1331 set_save_integer (val
, 1, XSAVE_INTEGER (val
, 1) - 1);
1332 if (XSAVE_INTEGER (val
, 1) == 0)
1334 struct ftfont_cache_data
*cache_data
= XSAVE_POINTER (val
, 0);
1336 FT_Done_Face (cache_data
->ft_face
);
1338 if (ftfont_info
->otf
)
1339 OTF_close (ftfont_info
->otf
);
1341 cache_data
->ft_face
= NULL
;
1344 FT_Done_Size (ftfont_info
->ft_size
);
1348 ftfont_has_char (Lisp_Object font
, int c
)
1350 struct charset
*cs
= NULL
;
1352 if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qja
)
1353 && charset_jisx0208
>= 0)
1354 cs
= CHARSET_FROM_ID (charset_jisx0208
);
1355 else if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qko
)
1356 && charset_ksc5601
>= 0)
1357 cs
= CHARSET_FROM_ID (charset_ksc5601
);
1359 return (ENCODE_CHAR (cs
, c
) != CHARSET_INVALID_CODE (cs
));
1361 if (FONT_ENTITY_P (font
))
1363 FcCharSet
*charset
= ftfont_get_fc_charset (font
);
1365 return (FcCharSetHasChar (charset
, c
) == FcTrue
);
1369 struct ftfont_info
*ftfont_info
;
1371 ftfont_info
= (struct ftfont_info
*) XFONT_OBJECT (font
);
1372 return (FT_Get_Char_Index (ftfont_info
->ft_size
->face
, (FT_ULong
) c
)
1378 ftfont_encode_char (struct font
*font
, int c
)
1380 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1381 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1382 FT_ULong charcode
= c
;
1383 FT_UInt code
= FT_Get_Char_Index (ft_face
, charcode
);
1385 return (code
> 0 ? code
: FONT_INVALID_CODE
);
1389 ftfont_text_extents (struct font
*font
, unsigned int *code
,
1390 int nglyphs
, struct font_metrics
*metrics
)
1392 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1393 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1397 if (ftfont_info
->ft_size
!= ft_face
->size
)
1398 FT_Activate_Size (ftfont_info
->ft_size
);
1400 for (i
= 0, first
= 1; i
< nglyphs
; i
++)
1402 if (FT_Load_Glyph (ft_face
, code
[i
], FT_LOAD_DEFAULT
) == 0)
1404 FT_Glyph_Metrics
*m
= &ft_face
->glyph
->metrics
;
1408 metrics
->lbearing
= m
->horiBearingX
>> 6;
1409 metrics
->rbearing
= (m
->horiBearingX
+ m
->width
) >> 6;
1410 metrics
->ascent
= m
->horiBearingY
>> 6;
1411 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1414 if (metrics
->lbearing
> width
+ (m
->horiBearingX
>> 6))
1415 metrics
->lbearing
= width
+ (m
->horiBearingX
>> 6);
1416 if (metrics
->rbearing
1417 < width
+ ((m
->horiBearingX
+ m
->width
) >> 6))
1419 = width
+ ((m
->horiBearingX
+ m
->width
) >> 6);
1420 if (metrics
->ascent
< (m
->horiBearingY
>> 6))
1421 metrics
->ascent
= m
->horiBearingY
>> 6;
1422 if (metrics
->descent
> ((m
->height
- m
->horiBearingY
) >> 6))
1423 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1424 width
+= m
->horiAdvance
>> 6;
1427 width
+= font
->space_width
;
1429 metrics
->width
= width
;
1433 ftfont_get_bitmap (struct font
*font
, unsigned int code
, struct font_bitmap
*bitmap
, int bits_per_pixel
)
1435 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1436 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1437 FT_Int32 load_flags
= FT_LOAD_RENDER
;
1439 if (ftfont_info
->ft_size
!= ft_face
->size
)
1440 FT_Activate_Size (ftfont_info
->ft_size
);
1441 if (bits_per_pixel
== 1)
1443 #ifdef FT_LOAD_TARGET_MONO
1444 load_flags
|= FT_LOAD_TARGET_MONO
;
1446 load_flags
|= FT_LOAD_MONOCHROME
;
1449 else if (bits_per_pixel
!= 8)
1450 /* We don't support such a rendering. */
1453 if (FT_Load_Glyph (ft_face
, code
, load_flags
) != 0)
1455 bitmap
->bits_per_pixel
1456 = (ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_MONO
? 1
1457 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
? 8
1458 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD
? 8
1459 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD_V
? 8
1461 if (bitmap
->bits_per_pixel
< 0)
1462 /* We don't support that kind of pixel mode. */
1464 bitmap
->rows
= ft_face
->glyph
->bitmap
.rows
;
1465 bitmap
->width
= ft_face
->glyph
->bitmap
.width
;
1466 bitmap
->pitch
= ft_face
->glyph
->bitmap
.pitch
;
1467 bitmap
->buffer
= ft_face
->glyph
->bitmap
.buffer
;
1468 bitmap
->left
= ft_face
->glyph
->bitmap_left
;
1469 bitmap
->top
= ft_face
->glyph
->bitmap_top
;
1470 bitmap
->advance
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1476 ftfont_anchor_point (struct font
*font
, unsigned int code
, int idx
,
1479 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1480 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1482 if (ftfont_info
->ft_size
!= ft_face
->size
)
1483 FT_Activate_Size (ftfont_info
->ft_size
);
1484 if (FT_Load_Glyph (ft_face
, code
, FT_LOAD_DEFAULT
) != 0)
1486 if (ft_face
->glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
1488 if (idx
>= ft_face
->glyph
->outline
.n_points
)
1490 *x
= ft_face
->glyph
->outline
.points
[idx
].x
;
1491 *y
= ft_face
->glyph
->outline
.points
[idx
].y
;
1498 ftfont_otf_features (OTF_GSUB_GPOS
*gsub_gpos
)
1500 Lisp_Object scripts
, langsyses
, features
, sym
;
1503 for (scripts
= Qnil
, i
= gsub_gpos
->ScriptList
.ScriptCount
- 1; i
>= 0; i
--)
1505 OTF_Script
*otf_script
= gsub_gpos
->ScriptList
.Script
+ i
;
1507 for (langsyses
= Qnil
, j
= otf_script
->LangSysCount
- 1; j
>= -1; j
--)
1509 OTF_LangSys
*otf_langsys
;
1512 otf_langsys
= otf_script
->LangSys
+ j
;
1513 else if (otf_script
->DefaultLangSysOffset
)
1514 otf_langsys
= &otf_script
->DefaultLangSys
;
1518 for (features
= Qnil
, k
= otf_langsys
->FeatureCount
- 1; k
>= 0; k
--)
1520 l
= otf_langsys
->FeatureIndex
[k
];
1521 if (l
>= gsub_gpos
->FeatureList
.FeatureCount
)
1523 OTF_TAG_SYM (sym
, gsub_gpos
->FeatureList
.Feature
[l
].FeatureTag
);
1524 features
= Fcons (sym
, features
);
1527 OTF_TAG_SYM (sym
, otf_script
->LangSysRecord
[j
].LangSysTag
);
1530 langsyses
= Fcons (Fcons (sym
, features
), langsyses
);
1533 OTF_TAG_SYM (sym
, gsub_gpos
->ScriptList
.Script
[i
].ScriptTag
);
1534 scripts
= Fcons (Fcons (sym
, langsyses
), scripts
);
1542 ftfont_otf_capability (struct font
*font
)
1544 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1545 OTF
*otf
= ftfont_get_otf (ftfont_info
);
1546 Lisp_Object gsub_gpos
;
1550 gsub_gpos
= Fcons (Qnil
, Qnil
);
1551 if (OTF_get_table (otf
, "GSUB") == 0
1552 && otf
->gsub
->FeatureList
.FeatureCount
> 0)
1553 XSETCAR (gsub_gpos
, ftfont_otf_features (otf
->gsub
));
1554 if (OTF_get_table (otf
, "GPOS") == 0
1555 && otf
->gpos
->FeatureList
.FeatureCount
> 0)
1556 XSETCDR (gsub_gpos
, ftfont_otf_features (otf
->gpos
));
1560 #ifdef HAVE_M17N_FLT
1562 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1563 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1564 /* We can use the new feature of libotf and m17n-flt to handle the
1565 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1566 some Agian scripts. */
1567 #define M17N_FLT_USE_NEW_FEATURE
1579 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1580 We use this structure instead of MFLTGlyph to utilize the new
1581 feature of libotf ver.0.9.15 which requires saving and restoring
1582 the value of OTF_GlyphString.positioning_type in the succeeding
1583 calls of the callback function MFLTFont.drive_otf (which is set to
1584 ftfont_drive_otf). */
1588 unsigned int libotf_positioning_type
;
1592 ftfont_get_glyph_id (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1595 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1596 FT_Face ft_face
= flt_font_ft
->ft_face
;
1599 for (g
= (MFLTGlyphFT
*) (gstring
->glyphs
) + from
; from
< to
; g
++, from
++)
1602 FT_UInt code
= FT_Get_Char_Index (ft_face
, g
->g
.code
);
1604 g
->g
.code
= code
> 0 ? code
: FONT_INVALID_CODE
;
1610 /* Operators for 26.6 fixed fractional pixel format */
1612 #define FLOOR(x) ((x) & -64)
1613 #define CEIL(x) (((x)+63) & -64)
1614 #define ROUND(x) (((x)+32) & -64)
1617 ftfont_get_metrics (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1620 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1621 FT_Face ft_face
= flt_font_ft
->ft_face
;
1624 for (g
= (MFLTGlyphFT
*) (gstring
->glyphs
) + from
; from
< to
; g
++, from
++)
1625 if (! g
->g
.measured
)
1627 if (g
->g
.code
!= FONT_INVALID_CODE
)
1629 FT_Glyph_Metrics
*m
;
1631 if (FT_Load_Glyph (ft_face
, g
->g
.code
, FT_LOAD_DEFAULT
) != 0)
1633 m
= &ft_face
->glyph
->metrics
;
1634 if (flt_font_ft
->matrix
)
1639 v
[0].x
= v
[1].x
= m
->horiBearingX
;
1640 v
[2].x
= v
[3].x
= m
->horiBearingX
+ m
->width
;
1641 v
[0].y
= v
[2].y
= m
->horiBearingY
;
1642 v
[1].y
= v
[3].y
= m
->horiBearingY
- m
->height
;
1643 for (i
= 0; i
< 4; i
++)
1644 FT_Vector_Transform (v
+ i
, flt_font_ft
->matrix
);
1645 g
->g
.lbearing
= v
[0].x
< v
[1].x
? FLOOR (v
[0].x
) : FLOOR (v
[1].x
);
1646 g
->g
.rbearing
= v
[2].x
> v
[3].x
? CEIL (v
[2].x
) : CEIL (v
[3].x
);
1647 g
->g
.ascent
= v
[0].y
> v
[2].y
? CEIL (v
[0].y
) : CEIL (v
[2].y
);
1648 g
->g
.descent
= v
[1].y
< v
[3].y
? - FLOOR (v
[1].y
) : - FLOOR (v
[3].y
);
1652 g
->g
.lbearing
= FLOOR (m
->horiBearingX
);
1653 g
->g
.rbearing
= CEIL (m
->horiBearingX
+ m
->width
);
1654 g
->g
.ascent
= CEIL (m
->horiBearingY
);
1655 g
->g
.descent
= - FLOOR (m
->horiBearingY
- m
->height
);
1657 g
->g
.xadv
= ROUND (ft_face
->glyph
->advance
.x
);
1662 g
->g
.rbearing
= g
->g
.xadv
= flt_font_ft
->font
->space_width
<< 6;
1663 g
->g
.ascent
= flt_font_ft
->font
->ascent
<< 6;
1664 g
->g
.descent
= flt_font_ft
->font
->descent
<< 6;
1673 ftfont_check_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
)
1675 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1677 #define FEATURE_ANY(IDX) \
1678 (spec->features[IDX] \
1679 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1681 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1682 OTF
*otf
= flt_font_ft
->otf
;
1687 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1688 /* Return true iff any of GSUB or GPOS support the script (and
1691 && (OTF_check_features (otf
, 0, spec
->script
, spec
->langsys
,
1693 || OTF_check_features (otf
, 1, spec
->script
, spec
->langsys
,
1696 for (i
= 0; i
< 2; i
++)
1697 if (! FEATURE_ANY (i
))
1699 if (FEATURE_NONE (i
))
1702 && OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1707 if (spec
->features
[i
][0] == 0xFFFFFFFF)
1710 || OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1716 for (n
= 1; spec
->features
[i
][n
]; n
++);
1718 SAFE_NALLOCA (tags
, 1, n
);
1719 for (n
= 0, negative
= 0; spec
->features
[i
][n
]; n
++)
1721 if (spec
->features
[i
][n
] == 0xFFFFFFFF)
1724 tags
[n
- 1] = spec
->features
[i
][n
] | 0x80000000;
1726 tags
[n
] = spec
->features
[i
][n
];
1729 #ifndef M17N_FLT_USE_NEW_FEATURE
1730 passed
= n
- negative
> 0;
1733 passed
= (OTF_check_features (otf
, i
== 0, spec
->script
,
1734 spec
->langsys
, tags
, n
- negative
)
1745 #define DEVICE_DELTA(table, size) \
1746 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1747 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1751 adjust_anchor (FT_Face ft_face
, OTF_Anchor
*anchor
,
1752 unsigned code
, int x_ppem
, int y_ppem
, int *x
, int *y
)
1754 if (anchor
->AnchorFormat
== 2)
1756 FT_Outline
*outline
;
1757 int ap
= anchor
->f
.f1
.AnchorPoint
;
1759 FT_Load_Glyph (ft_face
, (FT_UInt
) code
, FT_LOAD_MONOCHROME
);
1760 outline
= &ft_face
->glyph
->outline
;
1761 if (ap
< outline
->n_points
)
1763 *x
= outline
->points
[ap
].x
<< 6;
1764 *y
= outline
->points
[ap
].y
<< 6;
1767 else if (anchor
->AnchorFormat
== 3)
1769 if (anchor
->f
.f2
.XDeviceTable
.offset
1770 && anchor
->f
.f2
.XDeviceTable
.DeltaValue
)
1771 *x
+= DEVICE_DELTA (anchor
->f
.f2
.XDeviceTable
, x_ppem
);
1772 if (anchor
->f
.f2
.YDeviceTable
.offset
1773 && anchor
->f
.f2
.YDeviceTable
.DeltaValue
)
1774 *y
+= DEVICE_DELTA (anchor
->f
.f2
.YDeviceTable
, y_ppem
);
1778 static OTF_GlyphString otf_gstring
;
1781 setup_otf_gstring (int size
)
1783 if (otf_gstring
.size
< size
)
1785 ptrdiff_t new_size
= otf_gstring
.size
;
1786 xfree (otf_gstring
.glyphs
);
1787 otf_gstring
.glyphs
= xpalloc (NULL
, &new_size
, size
- otf_gstring
.size
,
1788 INT_MAX
, sizeof *otf_gstring
.glyphs
);
1789 otf_gstring
.size
= new_size
;
1791 otf_gstring
.used
= size
;
1792 memset (otf_gstring
.glyphs
, 0, sizeof (OTF_Glyph
) * size
);
1795 #ifdef M17N_FLT_USE_NEW_FEATURE
1797 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1798 #define PACK_OTF_TAG(TAG) \
1799 ((((TAG) & 0x7F000000) >> 3) \
1800 | (((TAG) & 0x7F0000) >> 2) \
1801 | (((TAG) & 0x7F00) >> 1) \
1804 /* Assuming that FONT is an OpenType font, apply OpenType features
1805 specified in SPEC on glyphs between FROM and TO of IN, and record
1806 the lastly applied feature in each glyph of IN. If OUT is not
1807 NULL, append the resulting glyphs to OUT while storing glyph
1808 position adjustment information in ADJUSTMENT. */
1811 ftfont_drive_otf (MFLTFont
*font
,
1813 MFLTGlyphString
*in
,
1816 MFLTGlyphString
*out
,
1817 MFLTGlyphAdjustment
*adjustment
)
1819 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1820 MFLTGlyphFT
*in_glyphs
= (MFLTGlyphFT
*) (in
->glyphs
) + from
;
1821 MFLTGlyphFT
*out_glyphs
= out
? (MFLTGlyphFT
*) (out
->glyphs
) : NULL
;
1822 FT_Face ft_face
= flt_font_ft
->ft_face
;
1823 OTF
*otf
= flt_font_ft
->otf
;
1824 int len
= to
- from
;
1827 char script
[5], *langsys
= NULL
;
1828 char *gsub_features
= NULL
, *gpos_features
= NULL
;
1829 OTF_Feature
*features
;
1833 OTF_tag_name (spec
->script
, script
);
1838 langsys
= langsysbuf
;
1839 OTF_tag_name (spec
->langsys
, langsys
);
1843 for (i
= 0; i
< 2; i
++)
1847 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
1849 for (j
= 0; spec
->features
[i
][j
]; j
++);
1850 SAFE_NALLOCA (p
, 6, j
);
1855 for (j
= 0; spec
->features
[i
][j
]; j
++)
1857 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
1858 *p
++ = '*', *p
++ = ',';
1861 OTF_tag_name (spec
->features
[i
][j
], p
);
1870 setup_otf_gstring (len
);
1871 for (i
= 0; i
< len
; i
++)
1873 otf_gstring
.glyphs
[i
].c
= in_glyphs
[i
].g
.c
& 0x11FFFF;
1874 otf_gstring
.glyphs
[i
].glyph_id
= in_glyphs
[i
].g
.code
;
1875 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1876 otf_gstring
.glyphs
[i
].positioning_type
= in_glyphs
[i
].libotf_positioning_type
;
1880 OTF_drive_gdef (otf
, &otf_gstring
);
1881 gidx
= out
? out
->used
: from
;
1883 if (gsub_features
&& out
)
1885 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1886 if (OTF_drive_gsub_features (otf
, &otf_gstring
, script
, langsys
,
1890 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1894 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
1899 features
= otf
->gsub
->FeatureList
.Feature
;
1900 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
1903 int min_from
, max_to
;
1906 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1907 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1909 feature_idx
= otfg
->positioning_type
>> 4;
1911 g
= out_glyphs
+ out
->used
;
1912 *g
= in_glyphs
[otfg
->f
.index
.from
];
1913 if (g
->g
.code
!= otfg
->glyph_id
)
1916 g
->g
.code
= otfg
->glyph_id
;
1920 min_from
= g
->g
.from
;
1922 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
1924 /* OTFG substitutes multiple glyphs in IN. */
1925 for (j
= otfg
->f
.index
.from
+ 1; j
<= otfg
->f
.index
.to
; j
++)
1927 if (min_from
> in_glyphs
[j
].g
.from
)
1928 min_from
= in_glyphs
[j
].g
.from
;
1929 if (max_to
< in_glyphs
[j
].g
.to
)
1930 max_to
= in_glyphs
[j
].g
.to
;
1932 g
->g
.from
= min_from
;
1937 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1938 tag
= PACK_OTF_TAG (tag
);
1939 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1941 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1942 g
->libotf_positioning_type
1943 = otfg
->positioning_type
& OTF_positioning_type_components_mask
;
1945 for (i
++, otfg
++; (i
< otf_gstring
.used
1946 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
1949 g
= out_glyphs
+ out
->used
;
1950 *g
= in_glyphs
[otfg
->f
.index
.to
];
1951 if (g
->g
.code
!= otfg
->glyph_id
)
1954 g
->g
.code
= otfg
->glyph_id
;
1957 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1958 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1960 feature_idx
= otfg
->positioning_type
>> 4;
1964 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1965 tag
= PACK_OTF_TAG (tag
);
1966 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1968 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1969 g
->libotf_positioning_type
1970 = otfg
->positioning_type
& OTF_positioning_type_components_mask
;
1976 else if (gsub_features
)
1978 /* Just for checking which features will be applied. */
1979 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1980 if (OTF_drive_gsub_features (otf
, &otf_gstring
, script
, langsys
,
1984 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1988 features
= otf
->gsub
->FeatureList
.Feature
;
1989 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; i
++,
1993 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1994 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1996 feature_idx
= otfg
->positioning_type
>> 4;
2000 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
2001 tag
= PACK_OTF_TAG (tag
);
2002 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
2004 MFLTGlyphFT
*g
= in_glyphs
+ j
;
2005 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
2012 if (out
->allocated
< out
->used
+ len
)
2017 for (i
= 0; i
< len
; i
++)
2018 out_glyphs
[out
->used
++] = in_glyphs
[i
];
2021 if (gpos_features
&& out
)
2023 MFLTGlyphFT
*base
= NULL
, *mark
= NULL
, *g
;
2024 int x_ppem
, y_ppem
, x_scale
, y_scale
;
2026 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2027 if (OTF_drive_gpos_features (otf
, &otf_gstring
, script
, langsys
,
2034 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
2041 features
= otf
->gpos
->FeatureList
.Feature
;
2042 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2043 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2044 x_scale
= ft_face
->size
->metrics
.x_scale
;
2045 y_scale
= ft_face
->size
->metrics
.y_scale
;
2047 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out_glyphs
+ gidx
;
2048 i
< otf_gstring
.used
; i
++, otfg
++)
2050 MFLTGlyphAdjustment
*adjust
= adjustment
;
2052 int positioning_type
, feature_idx
;
2054 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2055 positioning_type
= OTF_POSITIONING_TYPE_GET_FORMAT (otfg
);
2056 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
2058 positioning_type
= otfg
->positioning_type
& 0xF;
2059 feature_idx
= otfg
->positioning_type
>> 4;
2063 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
2064 tag
= PACK_OTF_TAG (tag
);
2065 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
2068 if (! otfg
->glyph_id
)
2069 /* This is a pseudo glyph that contains positioning
2070 information to be accumulated to a real glyph. */
2072 switch (positioning_type
)
2076 case 1: /* Single */
2079 int format
= otfg
->f
.f1
.format
;
2081 if (format
& OTF_XPlacement
)
2083 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
2084 if (format
& OTF_XPlaDevice
)
2086 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
2087 if (format
& OTF_YPlacement
)
2089 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
2090 if (format
& OTF_YPlaDevice
)
2092 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
2093 if (format
& OTF_XAdvance
)
2095 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
2096 if (format
& OTF_XAdvDevice
)
2098 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
2099 if (format
& OTF_YAdvance
)
2101 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
2102 if (format
& OTF_YAdvDevice
)
2104 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
2108 case 3: /* Cursive */
2109 /* Not yet supported. */
2111 case 4: /* Mark-to-Base */
2112 case 5: /* Mark-to-Ligature */
2116 goto label_adjust_anchor
;
2117 default: /* i.e. case 6 Mark-to-Mark */
2121 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2123 int distance
= OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg
);
2127 prev
= g
- distance
;
2128 if (prev
< out_glyphs
)
2134 label_adjust_anchor
:
2136 int base_x
, base_y
, mark_x
, mark_y
;
2137 int this_from
, this_to
;
2139 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
2140 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
2141 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
2142 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
2144 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
2145 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
, prev
->g
.code
,
2146 x_ppem
, y_ppem
, &base_x
, &base_y
);
2147 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
2148 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->g
.code
,
2149 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2150 adjust
->xoff
= (base_x
- mark_x
);
2151 adjust
->yoff
= - (base_y
- mark_y
);
2152 adjust
->back
= (g
- prev
);
2154 adjust
->advance_is_absolute
= 1;
2156 this_from
= g
->g
.from
;
2158 for (j
= 0; prev
+ j
< g
; j
++)
2160 if (this_from
> prev
[j
].g
.from
)
2161 this_from
= prev
[j
].g
.from
;
2162 if (this_to
< prev
[j
].g
.to
)
2163 this_to
= prev
[j
].g
.to
;
2165 for (; prev
<= g
; prev
++)
2167 prev
->g
.from
= this_from
;
2168 prev
->g
.to
= this_to
;
2174 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2176 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2184 else if (gpos_features
)
2186 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
2192 features
= otf
->gpos
->FeatureList
.Feature
;
2193 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
;
2195 if (otfg
->positioning_type
& 0xF)
2197 int feature_idx
= otfg
->positioning_type
>> 4;
2201 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
2202 tag
= PACK_OTF_TAG (tag
);
2203 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
2205 MFLTGlyphFT
*g
= in_glyphs
+ j
;
2206 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
2218 if (out
->allocated
< out
->used
+ len
)
2220 font
->get_metrics (font
, in
, from
, to
);
2221 memcpy (out
->glyphs
+ out
->used
, in_glyphs
, sizeof (MFLTGlyphFT
) * len
);
2227 ftfont_try_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
,
2228 MFLTGlyphString
*in
, int from
, int to
)
2230 return ftfont_drive_otf (font
, spec
, in
, from
, to
, NULL
, NULL
);
2233 #else /* not M17N_FLT_USE_NEW_FEATURE */
2236 ftfont_drive_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
, MFLTGlyphString
*in
,
2238 MFLTGlyphString
*out
, MFLTGlyphAdjustment
*adjustment
)
2240 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
2241 MFLTGlyphFT
*in_glyphs
= (MFLTGlyphFT
*) (in
->glyphs
) + from
;
2242 MFLTGlyphFT
*out_glyphs
= out
? (MFLTGlyphFT
*) (out
->glyphs
) : NULL
;
2243 FT_Face ft_face
= flt_font_ft
->ft_face
;
2244 OTF
*otf
= flt_font_ft
->otf
;
2245 int len
= to
- from
;
2248 char script
[5], *langsys
= NULL
;
2249 char *gsub_features
= NULL
, *gpos_features
= NULL
;
2253 OTF_tag_name (spec
->script
, script
);
2258 langsys
= langsysbuf
;
2259 OTF_tag_name (spec
->langsys
, langsys
);
2263 for (i
= 0; i
< 2; i
++)
2267 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
2269 for (j
= 0; spec
->features
[i
][j
]; j
++);
2270 SAFE_NALLOCA (p
, 6, j
);
2275 for (j
= 0; spec
->features
[i
][j
]; j
++)
2277 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
2278 *p
++ = '*', *p
++ = ',';
2281 OTF_tag_name (spec
->features
[i
][j
], p
);
2290 setup_otf_gstring (len
);
2291 for (i
= 0; i
< len
; i
++)
2293 otf_gstring
.glyphs
[i
].c
= in_glyphs
[i
].g
.c
;
2294 otf_gstring
.glyphs
[i
].glyph_id
= in_glyphs
[i
].g
.code
;
2297 OTF_drive_gdef (otf
, &otf_gstring
);
2302 if (OTF_drive_gsub (otf
, &otf_gstring
, script
, langsys
, gsub_features
)
2305 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
2310 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
2313 int min_from
, max_to
;
2316 g
= out_glyphs
+ out
->used
;
2317 *g
= in_glyphs
[otfg
->f
.index
.from
];
2318 if (g
->g
.code
!= otfg
->glyph_id
)
2321 g
->g
.code
= otfg
->glyph_id
;
2325 min_from
= g
->g
.from
;
2327 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
2329 /* OTFG substitutes multiple glyphs in IN. */
2330 for (j
= from
+ otfg
->f
.index
.from
+ 1;
2331 j
<= from
+ otfg
->f
.index
.to
; j
++)
2333 if (min_from
> in
->glyphs
[j
].from
)
2334 min_from
= in
->glyphs
[j
].from
;
2335 if (max_to
< in
->glyphs
[j
].to
)
2336 max_to
= in
->glyphs
[j
].to
;
2338 g
->g
.from
= min_from
;
2341 for (i
++, otfg
++; (i
< otf_gstring
.used
2342 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
2345 g
= out_glyphs
+ out
->used
;
2346 *g
= in_glyphs
[otfg
->f
.index
.to
];
2347 if (g
->g
.code
!= otfg
->glyph_id
)
2350 g
->g
.code
= otfg
->glyph_id
;
2359 if (out
->allocated
< out
->used
+ len
)
2364 for (i
= 0; i
< len
; i
++)
2365 out_glyphs
[out
->used
++] = in_glyphs
[i
];
2370 MFLTGlyphFT
*base
= NULL
, *mark
= NULL
, *g
;
2371 int x_ppem
, y_ppem
, x_scale
, y_scale
;
2373 if (OTF_drive_gpos (otf
, &otf_gstring
, script
, langsys
, gpos_features
)
2380 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2381 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2382 x_scale
= ft_face
->size
->metrics
.x_scale
;
2383 y_scale
= ft_face
->size
->metrics
.y_scale
;
2385 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out_glyphs
+ gidx
;
2386 i
< otf_gstring
.used
; i
++, otfg
++, g
++)
2390 if (! otfg
->glyph_id
)
2392 switch (otfg
->positioning_type
)
2396 case 1: /* Single */
2399 int format
= otfg
->f
.f1
.format
;
2401 if (format
& OTF_XPlacement
)
2403 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
2404 if (format
& OTF_XPlaDevice
)
2406 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
2407 if (format
& OTF_YPlacement
)
2409 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
2410 if (format
& OTF_YPlaDevice
)
2412 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
2413 if (format
& OTF_XAdvance
)
2415 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
2416 if (format
& OTF_XAdvDevice
)
2418 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
2419 if (format
& OTF_YAdvance
)
2421 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
2422 if (format
& OTF_YAdvDevice
)
2424 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
2425 adjustment
[i
].set
= 1;
2428 case 3: /* Cursive */
2429 /* Not yet supported. */
2431 case 4: /* Mark-to-Base */
2432 case 5: /* Mark-to-Ligature */
2436 goto label_adjust_anchor
;
2437 default: /* i.e. case 6 Mark-to-Mark */
2442 label_adjust_anchor
:
2444 int base_x
, base_y
, mark_x
, mark_y
;
2445 int this_from
, this_to
;
2447 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
2448 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
2449 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
2450 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
2452 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
2453 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
, prev
->g
.code
,
2454 x_ppem
, y_ppem
, &base_x
, &base_y
);
2455 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
2456 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->g
.code
,
2457 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2458 adjustment
[i
].xoff
= (base_x
- mark_x
);
2459 adjustment
[i
].yoff
= - (base_y
- mark_y
);
2460 adjustment
[i
].back
= (g
- prev
);
2461 adjustment
[i
].xadv
= 0;
2462 adjustment
[i
].advance_is_absolute
= 1;
2463 adjustment
[i
].set
= 1;
2464 this_from
= g
->g
.from
;
2466 for (j
= 0; prev
+ j
< g
; j
++)
2468 if (this_from
> prev
[j
].g
.from
)
2469 this_from
= prev
[j
].g
.from
;
2470 if (this_to
< prev
[j
].g
.to
)
2471 this_to
= prev
[j
].g
.to
;
2473 for (; prev
<= g
; prev
++)
2475 prev
->g
.from
= this_from
;
2476 prev
->g
.to
= this_to
;
2480 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2482 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2493 if (out
->allocated
< out
->used
+ len
)
2495 font
->get_metrics (font
, in
, from
, to
);
2496 memcpy (out_glyphs
+ out
->used
, in_glyphs
,
2497 sizeof (MFLTGlyphFT
) * len
);
2502 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2504 static MFLTGlyphString gstring
;
2506 static bool m17n_flt_initialized
;
2509 ftfont_shape_by_flt (Lisp_Object lgstring
, struct font
*font
,
2510 FT_Face ft_face
, OTF
*otf
, FT_Matrix
*matrix
)
2512 ptrdiff_t len
= LGSTRING_GLYPH_LEN (lgstring
);
2514 struct MFLTFontFT flt_font_ft
;
2516 bool with_variation_selector
= false;
2518 if (! m17n_flt_initialized
)
2521 #ifdef M17N_FLT_USE_NEW_FEATURE
2522 mflt_enable_new_feature
= 1;
2523 mflt_try_otf
= ftfont_try_otf
;
2524 #endif /* M17N_FLT_USE_NEW_FEATURE */
2525 m17n_flt_initialized
= 1;
2528 for (i
= 0; i
< len
; i
++)
2530 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2535 c
= LGLYPH_CHAR (g
);
2536 if (CHAR_VARIATION_SELECTOR_P (c
))
2537 with_variation_selector
= true;
2542 if (otf
&& with_variation_selector
)
2544 setup_otf_gstring (len
);
2545 for (i
= 0; i
< len
; i
++)
2547 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2549 otf_gstring
.glyphs
[i
].c
= LGLYPH_CHAR (g
);
2550 otf_gstring
.glyphs
[i
].f
.index
.from
= LGLYPH_FROM (g
);
2551 otf_gstring
.glyphs
[i
].f
.index
.to
= LGLYPH_TO (g
);
2553 OTF_drive_cmap (otf
, &otf_gstring
);
2554 for (i
= 0; i
< otf_gstring
.used
; i
++)
2556 OTF_Glyph
*otfg
= otf_gstring
.glyphs
+ i
;
2557 Lisp_Object g0
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.from
);
2558 Lisp_Object g1
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.to
);
2560 LGLYPH_SET_CODE (g0
, otfg
->glyph_id
);
2561 LGLYPH_SET_TO (g0
, LGLYPH_TO (g1
));
2562 LGSTRING_SET_GLYPH (lgstring
, i
, g0
);
2564 if (len
> otf_gstring
.used
)
2566 len
= otf_gstring
.used
;
2567 LGSTRING_SET_GLYPH (lgstring
, len
, Qnil
);
2572 Lisp_Object family
= Ffont_get (LGSTRING_FONT (lgstring
), QCfamily
);
2575 flt_font_ft
.flt_font
.family
= Mnil
;
2577 flt_font_ft
.flt_font
.family
2578 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family
))));
2580 flt_font_ft
.flt_font
.x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2581 flt_font_ft
.flt_font
.y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2582 flt_font_ft
.flt_font
.get_glyph_id
= ftfont_get_glyph_id
;
2583 flt_font_ft
.flt_font
.get_metrics
= ftfont_get_metrics
;
2584 flt_font_ft
.flt_font
.check_otf
= ftfont_check_otf
;
2585 flt_font_ft
.flt_font
.drive_otf
= ftfont_drive_otf
;
2586 flt_font_ft
.flt_font
.internal
= NULL
;
2587 flt_font_ft
.font
= font
;
2588 flt_font_ft
.ft_face
= ft_face
;
2589 flt_font_ft
.otf
= otf
;
2590 flt_font_ft
.matrix
= matrix
->xx
!= 0 ? matrix
: 0;
2594 /* A little bit ad hoc. Perhaps, shaper must get script and
2595 language information, and select a proper flt for them
2597 int c1
= LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, 1));
2598 /* For the combining characters in the range U+300..U+36F,
2599 "combining" is the sole FLT provided by the m17n-lib. In
2600 addition, it is the sole FLT that can handle the other
2601 combining characters with non-OTF fonts. */
2602 if ((0x300 <= c1
&& c1
<= 0x36F)
2603 || (! otf
&& CHAR_HAS_CATEGORY (c1
, '^')))
2604 flt
= mflt_get (msymbol ("combining"));
2608 flt
= mflt_find (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, 0)),
2609 &flt_font_ft
.flt_font
);
2611 return make_number (0);
2614 MFLTGlyphFT
*glyphs
= (MFLTGlyphFT
*) gstring
.glyphs
;
2615 ptrdiff_t allocated
= gstring
.allocated
;
2616 ptrdiff_t incr_min
= len
- allocated
;
2623 glyphs
= xpalloc (NULL
, &allocated
, incr_min
, INT_MAX
, sizeof *glyphs
);
2627 for (i
= 0; i
< len
; i
++)
2629 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2630 memset (&glyphs
[i
], 0, sizeof glyphs
[i
]);
2631 glyphs
[i
].g
.c
= LGLYPH_CHAR (g
);
2632 if (with_variation_selector
)
2634 glyphs
[i
].g
.code
= LGLYPH_CODE (g
);
2635 glyphs
[i
].g
.encoded
= 1;
2639 gstring
.glyph_size
= sizeof *glyphs
;
2640 gstring
.glyphs
= (MFLTGlyph
*) glyphs
;
2641 gstring
.allocated
= allocated
;
2645 while (mflt_run (&gstring
, 0, len
, &flt_font_ft
.flt_font
, flt
) == -2);
2647 if (gstring
.used
> LGSTRING_GLYPH_LEN (lgstring
))
2649 for (i
= 0; i
< gstring
.used
; i
++)
2651 MFLTGlyphFT
*g
= (MFLTGlyphFT
*) (gstring
.glyphs
) + i
;
2653 g
->g
.from
= LGLYPH_FROM (LGSTRING_GLYPH (lgstring
, g
->g
.from
));
2654 g
->g
.to
= LGLYPH_TO (LGSTRING_GLYPH (lgstring
, g
->g
.to
));
2657 for (i
= 0; i
< gstring
.used
; i
++)
2659 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
, i
);
2660 MFLTGlyphFT
*g
= (MFLTGlyphFT
*) (gstring
.glyphs
) + i
;
2664 lglyph
= LGLYPH_NEW ();
2665 LGSTRING_SET_GLYPH (lgstring
, i
, lglyph
);
2667 LGLYPH_SET_FROM (lglyph
, g
->g
.from
);
2668 LGLYPH_SET_TO (lglyph
, g
->g
.to
);
2669 LGLYPH_SET_CHAR (lglyph
, g
->g
.c
);
2670 LGLYPH_SET_CODE (lglyph
, g
->g
.code
);
2671 LGLYPH_SET_WIDTH (lglyph
, g
->g
.xadv
>> 6);
2672 LGLYPH_SET_LBEARING (lglyph
, g
->g
.lbearing
>> 6);
2673 LGLYPH_SET_RBEARING (lglyph
, g
->g
.rbearing
>> 6);
2674 LGLYPH_SET_ASCENT (lglyph
, g
->g
.ascent
>> 6);
2675 LGLYPH_SET_DESCENT (lglyph
, g
->g
.descent
>> 6);
2678 Lisp_Object vec
= make_uninit_vector (3);
2680 ASET (vec
, 0, make_number (g
->g
.xoff
>> 6));
2681 ASET (vec
, 1, make_number (g
->g
.yoff
>> 6));
2682 ASET (vec
, 2, make_number (g
->g
.xadv
>> 6));
2683 LGLYPH_SET_ADJUSTMENT (lglyph
, vec
);
2686 return make_number (i
);
2690 ftfont_shape (Lisp_Object lgstring
)
2692 struct font
*font
= CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring
));
2693 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
2694 OTF
*otf
= ftfont_get_otf (ftfont_info
);
2696 return ftfont_shape_by_flt (lgstring
, font
, ftfont_info
->ft_size
->face
, otf
,
2697 &ftfont_info
->matrix
);
2700 #endif /* HAVE_M17N_FLT */
2702 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2705 ftfont_variation_glyphs (struct font
*font
, int c
, unsigned variations
[256])
2707 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
2708 OTF
*otf
= ftfont_get_otf (ftfont_info
);
2712 return OTF_get_variation_glyphs (otf
, c
, variations
);
2715 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2716 #endif /* HAVE_LIBOTF */
2718 static const char *const ftfont_booleans
[] = {
2731 static const char *const ftfont_non_booleans
[] = {
2763 ftfont_filter_properties (Lisp_Object font
, Lisp_Object alist
)
2765 font_filter_properties (font
, alist
, ftfont_booleans
, ftfont_non_booleans
);
2770 ftfont_combining_capability (struct font
*font
)
2772 #ifdef HAVE_M17N_FLT
2780 syms_of_ftfont (void)
2782 /* Symbolic type of this font-driver. */
2783 DEFSYM (Qfreetype
, "freetype");
2785 /* Fontconfig's generic families and their aliases. */
2786 DEFSYM (Qmonospace
, "monospace");
2787 DEFSYM (Qsans_serif
, "sans-serif");
2788 DEFSYM (Qsans
, "sans");
2789 DEFSYM (Qsans__serif
, "sans serif");
2791 staticpro (&freetype_font_cache
);
2792 freetype_font_cache
= list1 (Qt
);
2794 staticpro (&ftfont_generic_family_list
);
2795 ftfont_generic_family_list
= list3 (Fcons (Qmonospace
, Qt
),
2796 Fcons (Qsans_serif
, Qt
),
2799 staticpro (&ft_face_cache
);
2800 ft_face_cache
= Qnil
;
2802 ftfont_driver
.type
= Qfreetype
;
2803 register_font_driver (&ftfont_driver
, NULL
);