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"
33 #include "composite.h"
37 /* Flag to tell if FcInit is already called or not. */
38 static bool fc_initialized
;
40 /* Handle to a FreeType library instance. */
41 static FT_Library ft_library
;
43 /* Cache for FreeType fonts. */
44 static Lisp_Object freetype_font_cache
;
46 /* Cache for FT_Face and FcCharSet. */
47 static Lisp_Object ft_face_cache
;
49 /* The actual structure for FreeType font that can be cast to struct
56 /* The following four members must be here in this order to be
57 compatible with struct xftfont_info (in xftfont.c). */
58 bool maybe_otf
; /* Flag to tell if this may be OTF or not. */
60 #endif /* HAVE_LIBOTF */
66 size_t ftfont_info_size
= sizeof (struct ftfont_info
);
70 FTFONT_CACHE_FOR_FACE
,
71 FTFONT_CACHE_FOR_CHARSET
,
72 FTFONT_CACHE_FOR_ENTITY
75 static Lisp_Object
ftfont_pattern_entity (FcPattern
*, Lisp_Object
);
77 static Lisp_Object
ftfont_resolve_generic_family (Lisp_Object
,
79 static Lisp_Object
ftfont_lookup_cache (Lisp_Object
,
80 enum ftfont_cache_for
);
82 static void ftfont_filter_properties (Lisp_Object font
, Lisp_Object alist
);
84 #define SYMBOL_FcChar8(SYM) (FcChar8 *) SDATA (SYMBOL_NAME (SYM))
90 /* characters to distinguish the charset from the others */
92 /* additional constraint by language */
95 FcCharSet
*fc_charset
;
96 } fc_charset_table
[] =
97 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
98 { "iso8859-2", { 0x00A0, 0x010E }},
99 { "iso8859-3", { 0x00A0, 0x0108 }},
100 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
101 { "iso8859-5", { 0x00A0, 0x0401 }},
102 { "iso8859-6", { 0x00A0, 0x060C }},
103 { "iso8859-7", { 0x00A0, 0x0384 }},
104 { "iso8859-8", { 0x00A0, 0x05D0 }},
105 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
106 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
107 { "iso8859-11", { 0x00A0, 0x0E01 }},
108 { "iso8859-13", { 0x00A0, 0x201C }},
109 { "iso8859-14", { 0x00A0, 0x0174 }},
110 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
111 { "iso8859-16", { 0x00A0, 0x0218}},
112 { "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
113 { "big5-0", { 0xF6B1 }, "zh-tw" },
114 { "jisx0208.1983-0", { 0x4E55 }, "ja"},
115 { "ksc5601.1985-0", { 0xAC00 }, "ko"},
116 { "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
117 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
118 { "cns11643.1992-3", { 0x201A9 }},
119 { "cns11643.1992-4", { 0x20057 }},
120 { "cns11643.1992-5", { 0x20000 }},
121 { "cns11643.1992-6", { 0x20003 }},
122 { "cns11643.1992-7", { 0x20055 }},
123 { "gbk-0", { 0x4E06 }, "zh-cn"},
124 { "jisx0212.1990-0", { 0x4E44 }},
125 { "jisx0213.2000-1", { 0xFA10 }, "ja"},
126 { "jisx0213.2000-2", { 0xFA49 }},
127 { "jisx0213.2004-1", { 0x20B9F }},
128 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
129 { "tis620.2529-1", { 0x0E01 }, "th"},
130 { "windows-1251", { 0x0401, 0x0490 }, "ru"},
131 { "koi8-r", { 0x0401, 0x2219 }, "ru"},
132 { "mulelao-1", { 0x0E81 }, "lo"},
133 { "unicode-sip", { 0x20000 }},
138 matching_prefix (char const *str
, ptrdiff_t len
, char const *pat
)
140 return len
== strlen (pat
) && c_strncasecmp (str
, pat
, len
) == 0;
143 /* Dirty hack for handing ADSTYLE property.
145 Fontconfig (actually the underlying FreeType) gives such ADSTYLE
146 font property of PCF/BDF fonts in FC_STYLE. And, "Bold",
147 "Oblique", "Italic", or any non-normal SWIDTH property names
148 (e.g. SemiCondensed) are appended. In addition, if there's no
149 ADSTYLE property nor non-normal WEIGHT/SLANT/SWIDTH properties,
150 "Regular" is used for FC_STYLE (see the function
151 pcf_interpret_style in src/pcf/pcfread.c of FreeType).
153 Unfortunately this behavior is not documented, so the following
154 code may fail if FreeType changes the behavior in the future. */
157 get_adstyle_property (FcPattern
*p
)
164 if ((FcPatternGetString (p
, FC_FONTFORMAT
, 0, &fcstr
) == FcResultMatch
)
165 && xstrcasecmp ((char *) fcstr
, "bdf") != 0
166 && xstrcasecmp ((char *) fcstr
, "pcf") != 0)
167 /* Not a BDF nor PCF font. */
170 if (FcPatternGetString (p
, FC_STYLE
, 0, &fcstr
) != FcResultMatch
)
172 str
= (char *) fcstr
;
173 for (end
= str
; *end
&& *end
!= ' '; end
++);
174 if (matching_prefix (str
, end
- str
, "Regular")
175 || matching_prefix (str
, end
- str
, "Bold")
176 || matching_prefix (str
, end
- str
, "Oblique")
177 || matching_prefix (str
, end
- str
, "Italic"))
179 adstyle
= font_intern_prop (str
, end
- str
, 1);
180 if (font_style_to_value (FONT_WIDTH_INDEX
, adstyle
, 0) >= 0)
186 ftfont_pattern_entity (FcPattern
*p
, Lisp_Object extra
)
188 Lisp_Object key
, cache
, entity
;
196 if (FcPatternGetString (p
, FC_FILE
, 0, &str
) != FcResultMatch
)
198 if (FcPatternGetInteger (p
, FC_INDEX
, 0, &idx
) != FcResultMatch
)
202 key
= Fcons (build_unibyte_string (file
), make_number (idx
));
203 cache
= ftfont_lookup_cache (key
, FTFONT_CACHE_FOR_ENTITY
);
204 entity
= XCAR (cache
);
207 Lisp_Object val
= font_make_entity ();
210 for (i
= 0; i
< FONT_OBJLIST_INDEX
; i
++)
211 ASET (val
, i
, AREF (entity
, i
));
213 ASET (val
, FONT_EXTRA_INDEX
, Fcopy_sequence (extra
));
214 font_put_extra (val
, QCfont_entity
, key
);
218 entity
= font_make_entity ();
219 XSETCAR (cache
, entity
);
221 ASET (entity
, FONT_TYPE_INDEX
, Qfreetype
);
222 ASET (entity
, FONT_REGISTRY_INDEX
, Qiso10646_1
);
224 if (FcPatternGetString (p
, FC_FOUNDRY
, 0, &str
) == FcResultMatch
)
226 char *s
= (char *) str
;
227 ASET (entity
, FONT_FOUNDRY_INDEX
, font_intern_prop (s
, strlen (s
), 1));
229 if (FcPatternGetString (p
, FC_FAMILY
, 0, &str
) == FcResultMatch
)
231 char *s
= (char *) str
;
232 ASET (entity
, FONT_FAMILY_INDEX
, font_intern_prop (s
, strlen (s
), 1));
234 if (FcPatternGetInteger (p
, FC_WEIGHT
, 0, &numeric
) == FcResultMatch
)
236 if (numeric
>= FC_WEIGHT_REGULAR
&& numeric
< FC_WEIGHT_MEDIUM
)
237 numeric
= FC_WEIGHT_MEDIUM
;
238 FONT_SET_STYLE (entity
, FONT_WEIGHT_INDEX
, make_number (numeric
));
240 if (FcPatternGetInteger (p
, FC_SLANT
, 0, &numeric
) == FcResultMatch
)
243 FONT_SET_STYLE (entity
, FONT_SLANT_INDEX
, make_number (numeric
));
245 if (FcPatternGetInteger (p
, FC_WIDTH
, 0, &numeric
) == FcResultMatch
)
247 FONT_SET_STYLE (entity
, FONT_WIDTH_INDEX
, make_number (numeric
));
249 if (FcPatternGetDouble (p
, FC_PIXEL_SIZE
, 0, &dbl
) == FcResultMatch
)
251 ASET (entity
, FONT_SIZE_INDEX
, make_number (dbl
));
254 ASET (entity
, FONT_SIZE_INDEX
, make_number (0));
255 if (FcPatternGetInteger (p
, FC_SPACING
, 0, &numeric
) == FcResultMatch
)
256 ASET (entity
, FONT_SPACING_INDEX
, make_number (numeric
));
257 if (FcPatternGetDouble (p
, FC_DPI
, 0, &dbl
) == FcResultMatch
)
260 ASET (entity
, FONT_DPI_INDEX
, make_number (dpi
));
262 if (FcPatternGetBool (p
, FC_SCALABLE
, 0, &b
) == FcResultMatch
265 ASET (entity
, FONT_SIZE_INDEX
, make_number (0));
266 ASET (entity
, FONT_AVGWIDTH_INDEX
, make_number (0));
270 /* As this font is not scalable, perhaps this is a BDF or PCF
274 ASET (entity
, FONT_ADSTYLE_INDEX
, get_adstyle_property (p
));
275 if ((ft_library
|| FT_Init_FreeType (&ft_library
) == 0)
276 && FT_New_Face (ft_library
, file
, idx
, &ft_face
) == 0)
280 if (FT_Get_BDF_Property (ft_face
, "AVERAGE_WIDTH", &rec
) == 0
281 && rec
.type
== BDF_PROPERTY_TYPE_INTEGER
)
282 ASET (entity
, FONT_AVGWIDTH_INDEX
, make_number (rec
.u
.integer
));
283 FT_Done_Face (ft_face
);
287 ASET (entity
, FONT_EXTRA_INDEX
, Fcopy_sequence (extra
));
288 font_put_extra (entity
, QCfont_entity
, key
);
293 static Lisp_Object ftfont_generic_family_list
;
296 ftfont_resolve_generic_family (Lisp_Object family
, FcPattern
*pattern
)
303 family
= Fintern (Fdowncase (SYMBOL_NAME (family
)), Qnil
);
304 if (EQ (family
, Qmono
))
306 else if (EQ (family
, Qsans
) || EQ (family
, Qsans__serif
))
307 family
= Qsans_serif
;
308 slot
= assq_no_quit (family
, ftfont_generic_family_list
);
311 if (! EQ (XCDR (slot
), Qt
))
313 pattern
= FcPatternDuplicate (pattern
);
316 FcPatternDel (pattern
, FC_FOUNDRY
);
317 FcPatternDel (pattern
, FC_FAMILY
);
318 FcPatternAddString (pattern
, FC_FAMILY
, SYMBOL_FcChar8 (family
));
319 if (FcPatternGetLangSet (pattern
, FC_LANG
, 0, &langset
) != FcResultMatch
)
321 /* This is to avoid the effect of locale. */
322 static const FcChar8 lang
[] = "en";
323 langset
= FcLangSetCreate ();
324 FcLangSetAdd (langset
, lang
);
325 FcPatternAddLangSet (pattern
, FC_LANG
, langset
);
326 FcLangSetDestroy (langset
);
328 FcConfigSubstitute (NULL
, pattern
, FcMatchPattern
);
329 FcDefaultSubstitute (pattern
);
330 match
= FcFontMatch (NULL
, pattern
, &result
);
335 if (FcPatternGetString (match
, FC_FAMILY
, 0, &fam
) == FcResultMatch
)
336 family
= intern ((char *) fam
);
340 XSETCDR (slot
, family
);
341 if (match
) FcPatternDestroy (match
);
343 if (pattern
) FcPatternDestroy (pattern
);
347 struct ftfont_cache_data
350 FcCharSet
*fc_charset
;
354 ftfont_lookup_cache (Lisp_Object key
, enum ftfont_cache_for cache_for
)
356 Lisp_Object cache
, val
, entity
;
357 struct ftfont_cache_data
*cache_data
;
359 if (FONT_ENTITY_P (key
))
362 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
363 eassert (CONSP (val
));
369 if (NILP (ft_face_cache
))
372 cache
= Fgethash (key
, ft_face_cache
, Qnil
);
375 if (NILP (ft_face_cache
))
376 ft_face_cache
= CALLN (Fmake_hash_table
, QCtest
, Qequal
);
377 cache_data
= xmalloc (sizeof *cache_data
);
378 cache_data
->ft_face
= NULL
;
379 cache_data
->fc_charset
= NULL
;
380 val
= make_save_ptr_int (cache_data
, 0);
381 cache
= Fcons (Qnil
, val
);
382 Fputhash (key
, cache
, ft_face_cache
);
387 cache_data
= XSAVE_POINTER (val
, 0);
390 if (cache_for
== FTFONT_CACHE_FOR_ENTITY
)
393 if (cache_for
== FTFONT_CACHE_FOR_FACE
394 ? ! cache_data
->ft_face
: ! cache_data
->fc_charset
)
396 char *filename
= SSDATA (XCAR (key
));
397 int idx
= XINT (XCDR (key
));
399 if (cache_for
== FTFONT_CACHE_FOR_FACE
)
402 && FT_Init_FreeType (&ft_library
) != 0)
404 if (FT_New_Face (ft_library
, filename
, idx
, &cache_data
->ft_face
)
410 FcPattern
*pat
= NULL
;
411 FcFontSet
*fontset
= NULL
;
412 FcObjectSet
*objset
= NULL
;
413 FcCharSet
*charset
= NULL
;
415 pat
= FcPatternBuild (0, FC_FILE
, FcTypeString
, (FcChar8
*) filename
,
416 FC_INDEX
, FcTypeInteger
, idx
, NULL
);
419 objset
= FcObjectSetBuild (FC_CHARSET
, FC_STYLE
, NULL
);
422 fontset
= FcFontList (NULL
, pat
, objset
);
425 if (fontset
&& fontset
->nfont
> 0
426 && (FcPatternGetCharSet (fontset
->fonts
[0], FC_CHARSET
, 0,
429 cache_data
->fc_charset
= FcCharSetCopy (charset
);
431 cache_data
->fc_charset
= FcCharSetCreate ();
435 FcFontSetDestroy (fontset
);
437 FcObjectSetDestroy (objset
);
439 FcPatternDestroy (pat
);
446 ftfont_get_fc_charset (Lisp_Object entity
)
448 Lisp_Object val
, cache
;
449 struct ftfont_cache_data
*cache_data
;
451 cache
= ftfont_lookup_cache (entity
, FTFONT_CACHE_FOR_CHARSET
);
453 cache_data
= XSAVE_POINTER (val
, 0);
454 return cache_data
->fc_charset
;
459 ftfont_get_otf (struct ftfont_info
*ftfont_info
)
463 if (ftfont_info
->otf
)
464 return ftfont_info
->otf
;
465 if (! ftfont_info
->maybe_otf
)
467 otf
= OTF_open_ft_face (ftfont_info
->ft_size
->face
);
468 if (! otf
|| OTF_get_table (otf
, "head") < 0)
472 ftfont_info
->maybe_otf
= 0;
475 ftfont_info
->otf
= otf
;
478 #endif /* HAVE_LIBOTF */
480 static Lisp_Object
ftfont_get_cache (struct frame
*);
481 static Lisp_Object
ftfont_list (struct frame
*, Lisp_Object
);
482 static Lisp_Object
ftfont_match (struct frame
*, Lisp_Object
);
483 static Lisp_Object
ftfont_list_family (struct frame
*);
484 static Lisp_Object
ftfont_open (struct frame
*, Lisp_Object
, int);
485 static void ftfont_close (struct font
*);
486 static int ftfont_has_char (Lisp_Object
, int);
487 static unsigned ftfont_encode_char (struct font
*, int);
488 static void ftfont_text_extents (struct font
*, unsigned *, int,
489 struct font_metrics
*);
490 static int ftfont_get_bitmap (struct font
*, unsigned,
491 struct font_bitmap
*, int);
492 static int ftfont_anchor_point (struct font
*, unsigned, int,
495 static Lisp_Object
ftfont_otf_capability (struct font
*);
496 # ifdef HAVE_M17N_FLT
497 static Lisp_Object
ftfont_shape (Lisp_Object
);
501 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
502 static int ftfont_variation_glyphs (struct font
*, int c
,
503 unsigned variations
[256]);
504 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
506 struct font_driver ftfont_driver
=
508 LISP_INITIALLY_ZERO
, /* Qfreetype */
509 0, /* case insensitive */
514 NULL
, /* free_entity */
517 /* We can't draw a text without device dependent functions. */
518 NULL
, /* prepare_face */
519 NULL
, /* done_face */
523 /* We can't draw a text without device dependent functions. */
526 NULL
, /* free_bitmap */
529 ftfont_otf_capability
,
530 #else /* not HAVE_LIBOTF */
532 #endif /* not HAVE_LIBOTF */
533 NULL
, /* otf_drive */
534 NULL
, /* start_for_frame */
535 NULL
, /* end_for_frame */
536 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
538 #else /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
540 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
543 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
544 ftfont_variation_glyphs
,
549 ftfont_filter_properties
, /* filter_properties */
553 ftfont_get_cache (struct frame
*f
)
555 return freetype_font_cache
;
559 ftfont_get_charset (Lisp_Object registry
)
561 char *str
= SSDATA (SYMBOL_NAME (registry
));
563 char *re
= SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry
)) * 2 + 1);
567 for (i
= j
= 0; i
< SBYTES (SYMBOL_NAME (registry
)); i
++, j
++)
571 else if (str
[i
] == '*')
578 regexp
= make_unibyte_string (re
, j
);
580 for (i
= 0; fc_charset_table
[i
].name
; i
++)
581 if (fast_c_string_match_ignore_case
582 (regexp
, fc_charset_table
[i
].name
,
583 strlen (fc_charset_table
[i
].name
)) >= 0)
585 if (! fc_charset_table
[i
].name
)
587 if (! fc_charset_table
[i
].fc_charset
)
589 FcCharSet
*charset
= FcCharSetCreate ();
590 int *uniquifier
= fc_charset_table
[i
].uniquifier
;
594 for (j
= 0; uniquifier
[j
]; j
++)
595 if (! FcCharSetAddChar (charset
, uniquifier
[j
]))
597 FcCharSetDestroy (charset
);
600 fc_charset_table
[i
].fc_charset
= charset
;
608 unsigned int script_tag
, langsys_tag
;
610 unsigned int *features
[2];
613 #define OTF_SYM_TAG(SYM, TAG) \
615 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
616 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
619 #define OTF_TAG_STR(TAG, P) \
621 (P)[0] = (char) (TAG >> 24); \
622 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
623 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
624 (P)[3] = (char) (TAG & 0xFF); \
629 #define OTF_TAG_SYM(SYM, TAG) \
633 OTF_TAG_STR (TAG, str); \
634 (SYM) = font_intern_prop (str, 4, 1); \
639 static struct OpenTypeSpec
*
640 ftfont_get_open_type_spec (Lisp_Object otf_spec
)
642 struct OpenTypeSpec
*spec
= malloc (sizeof *spec
);
649 spec
->script
= XCAR (otf_spec
);
650 if (! NILP (spec
->script
))
652 OTF_SYM_TAG (spec
->script
, spec
->script_tag
);
653 val
= assq_no_quit (spec
->script
, Votf_script_alist
);
654 if (CONSP (val
) && SYMBOLP (XCDR (val
)))
655 spec
->script
= XCDR (val
);
660 spec
->script_tag
= 0x44464C54; /* "DFLT" */
661 otf_spec
= XCDR (otf_spec
);
662 spec
->langsys_tag
= 0;
663 if (! NILP (otf_spec
))
665 val
= XCAR (otf_spec
);
667 OTF_SYM_TAG (val
, spec
->langsys_tag
);
668 otf_spec
= XCDR (otf_spec
);
670 spec
->nfeatures
[0] = spec
->nfeatures
[1] = 0;
671 for (i
= 0; i
< 2 && ! NILP (otf_spec
); i
++, otf_spec
= XCDR (otf_spec
))
675 val
= XCAR (otf_spec
);
680 (min (PTRDIFF_MAX
, SIZE_MAX
) / sizeof (int) < XINT (len
)
682 : malloc (XINT (len
) * sizeof *spec
->features
[i
]));
683 if (! spec
->features
[i
])
685 if (i
> 0 && spec
->features
[0])
686 free (spec
->features
[0]);
690 for (j
= 0, negative
= 0; CONSP (val
); val
= XCDR (val
))
692 if (NILP (XCAR (val
)))
698 OTF_SYM_TAG (XCAR (val
), tag
);
699 spec
->features
[i
][j
++] = negative
? tag
& 0x80000000 : tag
;
702 spec
->nfeatures
[i
] = j
;
708 ftfont_spec_pattern (Lisp_Object spec
, char *otlayout
, struct OpenTypeSpec
**otspec
, const char **langname
)
710 Lisp_Object tmp
, extra
;
711 FcPattern
*pattern
= NULL
;
712 FcCharSet
*charset
= NULL
;
713 FcLangSet
*langset
= NULL
;
717 Lisp_Object script
= Qnil
;
718 Lisp_Object registry
;
721 if ((n
= FONT_SLANT_NUMERIC (spec
)) >= 0
723 /* Fontconfig doesn't support reverse-italic/oblique. */
726 if (INTEGERP (AREF (spec
, FONT_DPI_INDEX
)))
727 dpi
= XINT (AREF (spec
, FONT_DPI_INDEX
));
728 if (INTEGERP (AREF (spec
, FONT_AVGWIDTH_INDEX
))
729 && XINT (AREF (spec
, FONT_AVGWIDTH_INDEX
)) == 0)
732 registry
= AREF (spec
, FONT_REGISTRY_INDEX
);
734 || EQ (registry
, Qascii_0
)
735 || EQ (registry
, Qiso10646_1
)
736 || EQ (registry
, Qunicode_bmp
))
742 fc_charset_idx
= ftfont_get_charset (registry
);
743 if (fc_charset_idx
< 0)
745 charset
= fc_charset_table
[fc_charset_idx
].fc_charset
;
746 *langname
= fc_charset_table
[fc_charset_idx
].lang
;
747 lang
= (FcChar8
*) *langname
;
750 langset
= FcLangSetCreate ();
753 FcLangSetAdd (langset
, lang
);
758 for (extra
= AREF (spec
, FONT_EXTRA_INDEX
);
759 CONSP (extra
); extra
= XCDR (extra
))
761 Lisp_Object key
, val
;
763 key
= XCAR (XCAR (extra
)), val
= XCDR (XCAR (extra
));
769 else if (EQ (key
, QClang
))
772 langset
= FcLangSetCreate ();
777 if (! FcLangSetAdd (langset
, SYMBOL_FcChar8 (val
)))
781 for (; CONSP (val
); val
= XCDR (val
))
782 if (SYMBOLP (XCAR (val
))
783 && ! FcLangSetAdd (langset
, SYMBOL_FcChar8 (XCAR (val
))))
786 else if (EQ (key
, QCotf
))
790 *otspec
= ftfont_get_open_type_spec (val
);
793 strcpy (otlayout
, "otlayout:");
794 OTF_TAG_STR ((*otspec
)->script_tag
, otlayout
+ 9);
795 script
= (*otspec
)->script
;
798 else if (EQ (key
, QCscript
))
800 else if (EQ (key
, QCscalable
))
801 scalable
= ! NILP (val
);
804 if (! NILP (script
) && ! charset
)
806 Lisp_Object chars
= assq_no_quit (script
, Vscript_representative_chars
);
808 if (CONSP (chars
) && CONSP (CDR (chars
)))
810 charset
= FcCharSetCreate ();
813 for (chars
= XCDR (chars
); CONSP (chars
); chars
= XCDR (chars
))
814 if (CHARACTERP (XCAR (chars
))
815 && ! FcCharSetAddChar (charset
, XFASTINT (XCAR (chars
))))
820 pattern
= FcPatternCreate ();
823 tmp
= AREF (spec
, FONT_FOUNDRY_INDEX
);
825 && ! FcPatternAddString (pattern
, FC_FOUNDRY
, SYMBOL_FcChar8 (tmp
)))
827 tmp
= AREF (spec
, FONT_FAMILY_INDEX
);
829 && ! FcPatternAddString (pattern
, FC_FAMILY
, SYMBOL_FcChar8 (tmp
)))
832 && ! FcPatternAddCharSet (pattern
, FC_CHARSET
, charset
))
835 && ! FcPatternAddLangSet (pattern
, FC_LANG
, langset
))
838 && ! FcPatternAddDouble (pattern
, FC_DPI
, dpi
))
841 && ! FcPatternAddBool (pattern
, FC_SCALABLE
, scalable
? FcTrue
: FcFalse
))
847 /* We come here because of unexpected error in fontconfig API call
848 (usually insufficient memory). */
851 FcPatternDestroy (pattern
);
856 if ((*otspec
)->nfeatures
[0] > 0)
857 free ((*otspec
)->features
[0]);
858 if ((*otspec
)->nfeatures
[1] > 0)
859 free ((*otspec
)->features
[1]);
865 if (langset
) FcLangSetDestroy (langset
);
866 if (charset
&& fc_charset_idx
< 0) FcCharSetDestroy (charset
);
871 ftfont_list (struct frame
*f
, Lisp_Object spec
)
873 Lisp_Object val
= Qnil
, family
, adstyle
;
876 FcFontSet
*fontset
= NULL
;
877 FcObjectSet
*objset
= NULL
;
879 Lisp_Object chars
= Qnil
;
880 char otlayout
[15]; /* For "otlayout:XXXX" */
881 struct OpenTypeSpec
*otspec
= NULL
;
883 const char *langname
= NULL
;
885 if (! fc_initialized
)
891 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
894 if (FcPatternGetCharSet (pattern
, FC_CHARSET
, 0, &charset
) != FcResultMatch
)
896 val
= assq_no_quit (QCscript
, AREF (spec
, FONT_EXTRA_INDEX
));
899 val
= assq_no_quit (XCDR (val
), Vscript_representative_chars
);
900 if (CONSP (val
) && VECTORP (XCDR (val
)))
905 if (INTEGERP (AREF (spec
, FONT_SPACING_INDEX
)))
906 spacing
= XINT (AREF (spec
, FONT_SPACING_INDEX
));
907 family
= AREF (spec
, FONT_FAMILY_INDEX
);
910 Lisp_Object resolved
;
912 resolved
= ftfont_resolve_generic_family (family
, pattern
);
913 if (! NILP (resolved
))
915 FcPatternDel (pattern
, FC_FAMILY
);
916 if (! FcPatternAddString (pattern
, FC_FAMILY
,
917 SYMBOL_FcChar8 (resolved
)))
921 adstyle
= AREF (spec
, FONT_ADSTYLE_INDEX
);
922 if (! NILP (adstyle
) && SBYTES (SYMBOL_NAME (adstyle
)) == 0)
924 objset
= FcObjectSetBuild (FC_FOUNDRY
, FC_FAMILY
, FC_WEIGHT
, FC_SLANT
,
925 FC_WIDTH
, FC_PIXEL_SIZE
, FC_SPACING
, FC_SCALABLE
,
926 FC_STYLE
, FC_FILE
, FC_INDEX
,
929 #endif /* FC_CAPABILITY */
937 FcObjectSetAdd (objset
, FC_CHARSET
);
939 fontset
= FcFontList (NULL
, pattern
, objset
);
940 if (! fontset
|| fontset
->nfont
== 0)
943 /* Need fix because this finds any fonts. */
944 if (fontset
->nfont
== 0 && ! NILP (family
))
946 /* Try matching with configuration. For instance, the
947 configuration may specify "Nimbus Mono L" as an alias of
949 FcPattern
*pat
= FcPatternBuild (0, FC_FAMILY
, FcTypeString
,
950 SYMBOL_FcChar8 (family
), NULL
);
953 if (FcConfigSubstitute (NULL
, pat
, FcMatchPattern
) == FcTrue
)
956 FcPatternGetString (pat
, FC_FAMILY
, i
, &fam
) == FcResultMatch
;
959 FcPatternDel (pattern
, FC_FAMILY
);
960 FcPatternAddString (pattern
, FC_FAMILY
, fam
);
961 FcFontSetDestroy (fontset
);
962 fontset
= FcFontList (NULL
, pattern
, objset
);
963 if (fontset
&& fontset
->nfont
> 0)
969 for (i
= 0; i
< fontset
->nfont
; i
++)
977 if ((FcPatternGetInteger (fontset
->fonts
[i
], FC_SPACING
, 0, &this)
988 if (FcPatternGetString (fontset
->fonts
[i
], FC_CAPABILITY
, 0, &this)
990 || ! strstr ((char *) this, otlayout
))
993 #endif /* FC_CAPABILITY */
1001 if (FcPatternGetString (fontset
->fonts
[i
], FC_FILE
, 0, &file
)
1004 otf
= OTF_open ((char *) file
);
1007 passed
= (OTF_check_features (otf
, 1, otspec
->script_tag
,
1008 otspec
->langsys_tag
,
1009 otspec
->features
[0],
1010 otspec
->nfeatures
[0]) == 1
1011 && OTF_check_features (otf
, 0, otspec
->script_tag
,
1012 otspec
->langsys_tag
,
1013 otspec
->features
[1],
1014 otspec
->nfeatures
[1]) == 1);
1019 #endif /* HAVE_LIBOTF */
1020 if (VECTORP (chars
))
1024 if (FcPatternGetCharSet (fontset
->fonts
[i
], FC_CHARSET
, 0, &charset
)
1027 for (j
= 0; j
< ASIZE (chars
); j
++)
1028 if (TYPE_RANGED_INTEGERP (FcChar32
, AREF (chars
, j
))
1029 && FcCharSetHasChar (charset
, XFASTINT (AREF (chars
, j
))))
1031 if (j
== ASIZE (chars
))
1034 if (! NILP (adstyle
) || langname
)
1036 Lisp_Object this_adstyle
= get_adstyle_property (fontset
->fonts
[i
]);
1038 if (! NILP (adstyle
)
1039 && (NILP (this_adstyle
)
1040 || xstrcasecmp (SSDATA (SYMBOL_NAME (adstyle
)),
1041 SSDATA (SYMBOL_NAME (this_adstyle
))) != 0))
1044 && ! NILP (this_adstyle
)
1045 && xstrcasecmp (langname
, SSDATA (SYMBOL_NAME (this_adstyle
))))
1048 entity
= ftfont_pattern_entity (fontset
->fonts
[i
],
1049 AREF (spec
, FONT_EXTRA_INDEX
));
1050 if (! NILP (entity
))
1051 val
= Fcons (entity
, val
);
1053 val
= Fnreverse (val
);
1057 /* We come here because of unexpected error in fontconfig API call
1058 (usually insufficient memory). */
1062 FONT_ADD_LOG ("ftfont-list", spec
, val
);
1063 if (objset
) FcObjectSetDestroy (objset
);
1064 if (fontset
) FcFontSetDestroy (fontset
);
1065 if (pattern
) FcPatternDestroy (pattern
);
1070 ftfont_match (struct frame
*f
, Lisp_Object spec
)
1072 Lisp_Object entity
= Qnil
;
1073 FcPattern
*pattern
, *match
= NULL
;
1075 char otlayout
[15]; /* For "otlayout:XXXX" */
1076 struct OpenTypeSpec
*otspec
= NULL
;
1077 const char *langname
= NULL
;
1079 if (! fc_initialized
)
1085 pattern
= ftfont_spec_pattern (spec
, otlayout
, &otspec
, &langname
);
1089 if (INTEGERP (AREF (spec
, FONT_SIZE_INDEX
)))
1093 value
.type
= FcTypeDouble
;
1094 value
.u
.d
= XINT (AREF (spec
, FONT_SIZE_INDEX
));
1095 FcPatternAdd (pattern
, FC_PIXEL_SIZE
, value
, FcFalse
);
1097 if (FcConfigSubstitute (NULL
, pattern
, FcMatchPattern
) == FcTrue
)
1099 FcDefaultSubstitute (pattern
);
1100 match
= FcFontMatch (NULL
, pattern
, &result
);
1103 entity
= ftfont_pattern_entity (match
, AREF (spec
, FONT_EXTRA_INDEX
));
1104 FcPatternDestroy (match
);
1105 if (! NILP (AREF (spec
, FONT_FAMILY_INDEX
))
1106 && NILP (assq_no_quit (AREF (spec
, FONT_FAMILY_INDEX
),
1107 ftfont_generic_family_list
))
1108 && NILP (Fstring_equal (AREF (spec
, FONT_FAMILY_INDEX
),
1109 AREF (entity
, FONT_FAMILY_INDEX
))))
1113 FcPatternDestroy (pattern
);
1115 FONT_ADD_LOG ("ftfont-match", spec
, entity
);
1120 ftfont_list_family (struct frame
*f
)
1122 Lisp_Object list
= Qnil
;
1123 FcPattern
*pattern
= NULL
;
1124 FcFontSet
*fontset
= NULL
;
1125 FcObjectSet
*objset
= NULL
;
1128 if (! fc_initialized
)
1134 pattern
= FcPatternCreate ();
1137 objset
= FcObjectSetBuild (FC_FAMILY
, NULL
);
1140 fontset
= FcFontList (NULL
, pattern
, objset
);
1144 for (i
= 0; i
< fontset
->nfont
; i
++)
1146 FcPattern
*pat
= fontset
->fonts
[i
];
1149 if (FcPatternGetString (pat
, FC_FAMILY
, 0, &str
) == FcResultMatch
)
1150 list
= Fcons (intern ((char *) str
), list
);
1154 if (objset
) FcObjectSetDestroy (objset
);
1155 if (fontset
) FcFontSetDestroy (fontset
);
1156 if (pattern
) FcPatternDestroy (pattern
);
1163 ftfont_open2 (struct frame
*f
,
1166 Lisp_Object font_object
)
1168 struct ftfont_info
*ftfont_info
;
1170 struct ftfont_cache_data
*cache_data
;
1174 Lisp_Object val
, filename
, idx
, cache
;
1180 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
1184 cache
= ftfont_lookup_cache (entity
, FTFONT_CACHE_FOR_FACE
);
1187 filename
= XCAR (val
);
1190 cache_data
= XSAVE_POINTER (XCDR (cache
), 0);
1191 ft_face
= cache_data
->ft_face
;
1192 if (XSAVE_INTEGER (val
, 1) > 0)
1194 /* FT_Face in this cache is already used by the different size. */
1195 if (FT_New_Size (ft_face
, &ft_size
) != 0)
1197 if (FT_Activate_Size (ft_size
) != 0)
1199 FT_Done_Size (ft_size
);
1203 set_save_integer (val
, 1, XSAVE_INTEGER (val
, 1) + 1);
1204 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
1207 if (FT_Set_Pixel_Sizes (ft_face
, size
, size
) != 0)
1209 if (XSAVE_INTEGER (val
, 1) == 0)
1210 FT_Done_Face (ft_face
);
1214 ASET (font_object
, FONT_FILE_INDEX
, filename
);
1215 font
= XFONT_OBJECT (font_object
);
1216 ftfont_info
= (struct ftfont_info
*) font
;
1217 ftfont_info
->ft_size
= ft_face
->size
;
1218 ftfont_info
->index
= XINT (idx
);
1220 ftfont_info
->maybe_otf
= (ft_face
->face_flags
& FT_FACE_FLAG_SFNT
) != 0;
1221 ftfont_info
->otf
= NULL
;
1222 #endif /* HAVE_LIBOTF */
1223 /* This means that there's no need of transformation. */
1224 ftfont_info
->matrix
.xx
= 0;
1225 font
->pixel_size
= size
;
1226 font
->driver
= &ftfont_driver
;
1227 font
->encoding_charset
= font
->repertory_charset
= -1;
1229 upEM
= ft_face
->units_per_EM
;
1230 scalable
= (INTEGERP (AREF (entity
, FONT_AVGWIDTH_INDEX
))
1231 && XINT (AREF (entity
, FONT_AVGWIDTH_INDEX
)) == 0);
1234 font
->ascent
= ft_face
->ascender
* size
/ upEM
+ 0.5;
1235 font
->descent
= - ft_face
->descender
* size
/ upEM
+ 0.5;
1236 font
->height
= ft_face
->height
* size
/ upEM
+ 0.5;
1240 font
->ascent
= ft_face
->size
->metrics
.ascender
>> 6;
1241 font
->descent
= - ft_face
->size
->metrics
.descender
>> 6;
1242 font
->height
= ft_face
->size
->metrics
.height
>> 6;
1244 if (INTEGERP (AREF (entity
, FONT_SPACING_INDEX
)))
1245 spacing
= XINT (AREF (entity
, FONT_SPACING_INDEX
));
1247 spacing
= FC_PROPORTIONAL
;
1248 if (spacing
!= FC_PROPORTIONAL
1250 && spacing
!= FC_DUAL
1251 #endif /* FC_DUAL */
1253 font
->min_width
= font
->average_width
= font
->space_width
1254 = (scalable
? ft_face
->max_advance_width
* size
/ upEM
+ 0.5
1255 : ft_face
->size
->metrics
.max_advance
>> 6);
1260 font
->min_width
= font
->average_width
= font
->space_width
= 0;
1261 for (i
= 32, n
= 0; i
< 127; i
++)
1262 if (FT_Load_Char (ft_face
, i
, FT_LOAD_DEFAULT
) == 0)
1264 int this_width
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1267 && (! font
->min_width
|| font
->min_width
> this_width
))
1268 font
->min_width
= this_width
;
1270 font
->space_width
= this_width
;
1271 font
->average_width
+= this_width
;
1275 font
->average_width
/= n
;
1278 font
->baseline_offset
= 0;
1279 font
->relative_compose
= 0;
1280 font
->default_ascent
= 0;
1281 font
->vertical_centering
= 0;
1284 font
->underline_position
= (-ft_face
->underline_position
* size
/ upEM
1286 font
->underline_thickness
= (ft_face
->underline_thickness
* size
/ upEM
1291 font
->underline_position
= -1;
1292 font
->underline_thickness
= 0;
1299 ftfont_open (struct frame
*f
, Lisp_Object entity
, int pixel_size
)
1301 Lisp_Object font_object
;
1303 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
1306 font_object
= font_build_object (VECSIZE (struct ftfont_info
),
1307 Qfreetype
, entity
, size
);
1308 return ftfont_open2 (f
, entity
, pixel_size
, font_object
);
1312 ftfont_close (struct font
*font
)
1314 /* FIXME: Although this function can be called while garbage-collecting,
1315 the function assumes that Lisp data structures are properly-formed.
1316 This invalid assumption can lead to core dumps (Bug#20890). */
1318 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1319 Lisp_Object val
, cache
;
1321 val
= Fcons (font
->props
[FONT_FILE_INDEX
], make_number (ftfont_info
->index
));
1322 cache
= ftfont_lookup_cache (val
, FTFONT_CACHE_FOR_FACE
);
1323 eassert (CONSP (cache
));
1325 set_save_integer (val
, 1, XSAVE_INTEGER (val
, 1) - 1);
1326 if (XSAVE_INTEGER (val
, 1) == 0)
1328 struct ftfont_cache_data
*cache_data
= XSAVE_POINTER (val
, 0);
1330 FT_Done_Face (cache_data
->ft_face
);
1332 if (ftfont_info
->otf
)
1333 OTF_close (ftfont_info
->otf
);
1335 cache_data
->ft_face
= NULL
;
1338 FT_Done_Size (ftfont_info
->ft_size
);
1342 ftfont_has_char (Lisp_Object font
, int c
)
1344 struct charset
*cs
= NULL
;
1346 if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qja
)
1347 && charset_jisx0208
>= 0)
1348 cs
= CHARSET_FROM_ID (charset_jisx0208
);
1349 else if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qko
)
1350 && charset_ksc5601
>= 0)
1351 cs
= CHARSET_FROM_ID (charset_ksc5601
);
1353 return (ENCODE_CHAR (cs
, c
) != CHARSET_INVALID_CODE (cs
));
1355 if (FONT_ENTITY_P (font
))
1357 FcCharSet
*charset
= ftfont_get_fc_charset (font
);
1359 return (FcCharSetHasChar (charset
, c
) == FcTrue
);
1363 struct ftfont_info
*ftfont_info
;
1365 ftfont_info
= (struct ftfont_info
*) XFONT_OBJECT (font
);
1366 return (FT_Get_Char_Index (ftfont_info
->ft_size
->face
, (FT_ULong
) c
)
1372 ftfont_encode_char (struct font
*font
, int c
)
1374 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1375 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1376 FT_ULong charcode
= c
;
1377 FT_UInt code
= FT_Get_Char_Index (ft_face
, charcode
);
1379 return (code
> 0 ? code
: FONT_INVALID_CODE
);
1383 ftfont_text_extents (struct font
*font
, unsigned int *code
,
1384 int nglyphs
, struct font_metrics
*metrics
)
1386 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1387 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1391 if (ftfont_info
->ft_size
!= ft_face
->size
)
1392 FT_Activate_Size (ftfont_info
->ft_size
);
1394 for (i
= 0, first
= 1; i
< nglyphs
; i
++)
1396 if (FT_Load_Glyph (ft_face
, code
[i
], FT_LOAD_DEFAULT
) == 0)
1398 FT_Glyph_Metrics
*m
= &ft_face
->glyph
->metrics
;
1402 metrics
->lbearing
= m
->horiBearingX
>> 6;
1403 metrics
->rbearing
= (m
->horiBearingX
+ m
->width
) >> 6;
1404 metrics
->ascent
= m
->horiBearingY
>> 6;
1405 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1408 if (metrics
->lbearing
> width
+ (m
->horiBearingX
>> 6))
1409 metrics
->lbearing
= width
+ (m
->horiBearingX
>> 6);
1410 if (metrics
->rbearing
1411 < width
+ ((m
->horiBearingX
+ m
->width
) >> 6))
1413 = width
+ ((m
->horiBearingX
+ m
->width
) >> 6);
1414 if (metrics
->ascent
< (m
->horiBearingY
>> 6))
1415 metrics
->ascent
= m
->horiBearingY
>> 6;
1416 if (metrics
->descent
> ((m
->height
- m
->horiBearingY
) >> 6))
1417 metrics
->descent
= (m
->height
- m
->horiBearingY
) >> 6;
1418 width
+= m
->horiAdvance
>> 6;
1421 width
+= font
->space_width
;
1423 metrics
->width
= width
;
1427 ftfont_get_bitmap (struct font
*font
, unsigned int code
, struct font_bitmap
*bitmap
, int bits_per_pixel
)
1429 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1430 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1431 FT_Int32 load_flags
= FT_LOAD_RENDER
;
1433 if (ftfont_info
->ft_size
!= ft_face
->size
)
1434 FT_Activate_Size (ftfont_info
->ft_size
);
1435 if (bits_per_pixel
== 1)
1437 #ifdef FT_LOAD_TARGET_MONO
1438 load_flags
|= FT_LOAD_TARGET_MONO
;
1440 load_flags
|= FT_LOAD_MONOCHROME
;
1443 else if (bits_per_pixel
!= 8)
1444 /* We don't support such a rendering. */
1447 if (FT_Load_Glyph (ft_face
, code
, load_flags
) != 0)
1449 bitmap
->bits_per_pixel
1450 = (ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_MONO
? 1
1451 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
? 8
1452 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD
? 8
1453 : ft_face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_LCD_V
? 8
1455 if (bitmap
->bits_per_pixel
< 0)
1456 /* We don't support that kind of pixel mode. */
1458 bitmap
->rows
= ft_face
->glyph
->bitmap
.rows
;
1459 bitmap
->width
= ft_face
->glyph
->bitmap
.width
;
1460 bitmap
->pitch
= ft_face
->glyph
->bitmap
.pitch
;
1461 bitmap
->buffer
= ft_face
->glyph
->bitmap
.buffer
;
1462 bitmap
->left
= ft_face
->glyph
->bitmap_left
;
1463 bitmap
->top
= ft_face
->glyph
->bitmap_top
;
1464 bitmap
->advance
= ft_face
->glyph
->metrics
.horiAdvance
>> 6;
1470 ftfont_anchor_point (struct font
*font
, unsigned int code
, int idx
,
1473 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1474 FT_Face ft_face
= ftfont_info
->ft_size
->face
;
1476 if (ftfont_info
->ft_size
!= ft_face
->size
)
1477 FT_Activate_Size (ftfont_info
->ft_size
);
1478 if (FT_Load_Glyph (ft_face
, code
, FT_LOAD_DEFAULT
) != 0)
1480 if (ft_face
->glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
1482 if (idx
>= ft_face
->glyph
->outline
.n_points
)
1484 *x
= ft_face
->glyph
->outline
.points
[idx
].x
;
1485 *y
= ft_face
->glyph
->outline
.points
[idx
].y
;
1492 ftfont_otf_features (OTF_GSUB_GPOS
*gsub_gpos
)
1494 Lisp_Object scripts
, langsyses
, features
, sym
;
1497 for (scripts
= Qnil
, i
= gsub_gpos
->ScriptList
.ScriptCount
- 1; i
>= 0; i
--)
1499 OTF_Script
*otf_script
= gsub_gpos
->ScriptList
.Script
+ i
;
1501 for (langsyses
= Qnil
, j
= otf_script
->LangSysCount
- 1; j
>= -1; j
--)
1503 OTF_LangSys
*otf_langsys
;
1506 otf_langsys
= otf_script
->LangSys
+ j
;
1507 else if (otf_script
->DefaultLangSysOffset
)
1508 otf_langsys
= &otf_script
->DefaultLangSys
;
1512 for (features
= Qnil
, k
= otf_langsys
->FeatureCount
- 1; k
>= 0; k
--)
1514 l
= otf_langsys
->FeatureIndex
[k
];
1515 if (l
>= gsub_gpos
->FeatureList
.FeatureCount
)
1517 OTF_TAG_SYM (sym
, gsub_gpos
->FeatureList
.Feature
[l
].FeatureTag
);
1518 features
= Fcons (sym
, features
);
1521 OTF_TAG_SYM (sym
, otf_script
->LangSysRecord
[j
].LangSysTag
);
1524 langsyses
= Fcons (Fcons (sym
, features
), langsyses
);
1527 OTF_TAG_SYM (sym
, gsub_gpos
->ScriptList
.Script
[i
].ScriptTag
);
1528 scripts
= Fcons (Fcons (sym
, langsyses
), scripts
);
1536 ftfont_otf_capability (struct font
*font
)
1538 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
1539 OTF
*otf
= ftfont_get_otf (ftfont_info
);
1540 Lisp_Object gsub_gpos
;
1544 gsub_gpos
= Fcons (Qnil
, Qnil
);
1545 if (OTF_get_table (otf
, "GSUB") == 0
1546 && otf
->gsub
->FeatureList
.FeatureCount
> 0)
1547 XSETCAR (gsub_gpos
, ftfont_otf_features (otf
->gsub
));
1548 if (OTF_get_table (otf
, "GPOS") == 0
1549 && otf
->gpos
->FeatureList
.FeatureCount
> 0)
1550 XSETCDR (gsub_gpos
, ftfont_otf_features (otf
->gpos
));
1554 #ifdef HAVE_M17N_FLT
1556 #if (((LIBOTF_MAJOR_VERSION > 1) || (LIBOTF_RELEASE_NUMBER >= 10)) \
1557 && ((M17NLIB_MAJOR_VERSION > 1) || (M17NLIB_MINOR_VERSION >= 6)))
1558 /* We can use the new feature of libotf and m17n-flt to handle the
1559 character encoding scheme introduced in Unicode 5.1 and 5.2 for
1560 some Agian scripts. */
1561 #define M17N_FLT_USE_NEW_FEATURE
1573 /* The actual type of elements in the array MFLTGlyphString.glyphs.
1574 We use this structure instead of MFLTGlyph to utilize the new
1575 feature of libotf ver.0.9.15 which requires saving and restoring
1576 the value of OTF_GlyphString.positioning_type in the succeeding
1577 calls of the callback function MFLTFont.drive_otf (which is set to
1578 ftfont_drive_otf). */
1582 unsigned int libotf_positioning_type
;
1586 ftfont_get_glyph_id (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1589 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1590 FT_Face ft_face
= flt_font_ft
->ft_face
;
1593 for (g
= (MFLTGlyphFT
*) (gstring
->glyphs
) + from
; from
< to
; g
++, from
++)
1596 FT_UInt code
= FT_Get_Char_Index (ft_face
, g
->g
.code
);
1598 g
->g
.code
= code
> 0 ? code
: FONT_INVALID_CODE
;
1604 /* Operators for 26.6 fixed fractional pixel format */
1606 #define FLOOR(x) ((x) & -64)
1607 #define CEIL(x) (((x)+63) & -64)
1608 #define ROUND(x) (((x)+32) & -64)
1611 ftfont_get_metrics (MFLTFont
*font
, MFLTGlyphString
*gstring
,
1614 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1615 FT_Face ft_face
= flt_font_ft
->ft_face
;
1618 for (g
= (MFLTGlyphFT
*) (gstring
->glyphs
) + from
; from
< to
; g
++, from
++)
1619 if (! g
->g
.measured
)
1621 if (g
->g
.code
!= FONT_INVALID_CODE
)
1623 FT_Glyph_Metrics
*m
;
1625 if (FT_Load_Glyph (ft_face
, g
->g
.code
, FT_LOAD_DEFAULT
) != 0)
1627 m
= &ft_face
->glyph
->metrics
;
1628 if (flt_font_ft
->matrix
)
1633 v
[0].x
= v
[1].x
= m
->horiBearingX
;
1634 v
[2].x
= v
[3].x
= m
->horiBearingX
+ m
->width
;
1635 v
[0].y
= v
[2].y
= m
->horiBearingY
;
1636 v
[1].y
= v
[3].y
= m
->horiBearingY
- m
->height
;
1637 for (i
= 0; i
< 4; i
++)
1638 FT_Vector_Transform (v
+ i
, flt_font_ft
->matrix
);
1639 g
->g
.lbearing
= v
[0].x
< v
[1].x
? FLOOR (v
[0].x
) : FLOOR (v
[1].x
);
1640 g
->g
.rbearing
= v
[2].x
> v
[3].x
? CEIL (v
[2].x
) : CEIL (v
[3].x
);
1641 g
->g
.ascent
= v
[0].y
> v
[2].y
? CEIL (v
[0].y
) : CEIL (v
[2].y
);
1642 g
->g
.descent
= v
[1].y
< v
[3].y
? - FLOOR (v
[1].y
) : - FLOOR (v
[3].y
);
1646 g
->g
.lbearing
= FLOOR (m
->horiBearingX
);
1647 g
->g
.rbearing
= CEIL (m
->horiBearingX
+ m
->width
);
1648 g
->g
.ascent
= CEIL (m
->horiBearingY
);
1649 g
->g
.descent
= - FLOOR (m
->horiBearingY
- m
->height
);
1651 g
->g
.xadv
= ROUND (ft_face
->glyph
->advance
.x
);
1656 g
->g
.rbearing
= g
->g
.xadv
= flt_font_ft
->font
->space_width
<< 6;
1657 g
->g
.ascent
= flt_font_ft
->font
->ascent
<< 6;
1658 g
->g
.descent
= flt_font_ft
->font
->descent
<< 6;
1667 ftfont_check_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
)
1669 #define FEATURE_NONE(IDX) (! spec->features[IDX])
1671 #define FEATURE_ANY(IDX) \
1672 (spec->features[IDX] \
1673 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
1675 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1676 OTF
*otf
= flt_font_ft
->otf
;
1681 if (FEATURE_ANY (0) && FEATURE_ANY (1))
1682 /* Return true iff any of GSUB or GPOS support the script (and
1685 && (OTF_check_features (otf
, 0, spec
->script
, spec
->langsys
,
1687 || OTF_check_features (otf
, 1, spec
->script
, spec
->langsys
,
1690 for (i
= 0; i
< 2; i
++)
1691 if (! FEATURE_ANY (i
))
1693 if (FEATURE_NONE (i
))
1696 && OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1701 if (spec
->features
[i
][0] == 0xFFFFFFFF)
1704 || OTF_check_features (otf
, i
== 0, spec
->script
, spec
->langsys
,
1710 for (n
= 1; spec
->features
[i
][n
]; n
++);
1712 SAFE_NALLOCA (tags
, 1, n
);
1713 for (n
= 0, negative
= 0; spec
->features
[i
][n
]; n
++)
1715 if (spec
->features
[i
][n
] == 0xFFFFFFFF)
1718 tags
[n
- 1] = spec
->features
[i
][n
] | 0x80000000;
1720 tags
[n
] = spec
->features
[i
][n
];
1723 #ifndef M17N_FLT_USE_NEW_FEATURE
1724 passed
= n
- negative
> 0;
1727 passed
= (OTF_check_features (otf
, i
== 0, spec
->script
,
1728 spec
->langsys
, tags
, n
- negative
)
1739 #define DEVICE_DELTA(table, size) \
1740 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1741 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
1745 adjust_anchor (FT_Face ft_face
, OTF_Anchor
*anchor
,
1746 unsigned code
, int x_ppem
, int y_ppem
, int *x
, int *y
)
1748 if (anchor
->AnchorFormat
== 2)
1750 FT_Outline
*outline
;
1751 int ap
= anchor
->f
.f1
.AnchorPoint
;
1753 FT_Load_Glyph (ft_face
, (FT_UInt
) code
, FT_LOAD_MONOCHROME
);
1754 outline
= &ft_face
->glyph
->outline
;
1755 if (ap
< outline
->n_points
)
1757 *x
= outline
->points
[ap
].x
<< 6;
1758 *y
= outline
->points
[ap
].y
<< 6;
1761 else if (anchor
->AnchorFormat
== 3)
1763 if (anchor
->f
.f2
.XDeviceTable
.offset
1764 && anchor
->f
.f2
.XDeviceTable
.DeltaValue
)
1765 *x
+= DEVICE_DELTA (anchor
->f
.f2
.XDeviceTable
, x_ppem
);
1766 if (anchor
->f
.f2
.YDeviceTable
.offset
1767 && anchor
->f
.f2
.YDeviceTable
.DeltaValue
)
1768 *y
+= DEVICE_DELTA (anchor
->f
.f2
.YDeviceTable
, y_ppem
);
1772 static OTF_GlyphString otf_gstring
;
1775 setup_otf_gstring (int size
)
1777 if (otf_gstring
.size
< size
)
1779 ptrdiff_t new_size
= otf_gstring
.size
;
1780 xfree (otf_gstring
.glyphs
);
1781 otf_gstring
.glyphs
= xpalloc (NULL
, &new_size
, size
- otf_gstring
.size
,
1782 INT_MAX
, sizeof *otf_gstring
.glyphs
);
1783 otf_gstring
.size
= new_size
;
1785 otf_gstring
.used
= size
;
1786 memset (otf_gstring
.glyphs
, 0, sizeof (OTF_Glyph
) * size
);
1789 #ifdef M17N_FLT_USE_NEW_FEATURE
1791 /* Pack 32-bit OTF tag (0x7F7F7F7F) into 28-bit (0x0FFFFFFF). */
1792 #define PACK_OTF_TAG(TAG) \
1793 ((((TAG) & 0x7F000000) >> 3) \
1794 | (((TAG) & 0x7F0000) >> 2) \
1795 | (((TAG) & 0x7F00) >> 1) \
1798 /* Assuming that FONT is an OpenType font, apply OpenType features
1799 specified in SPEC on glyphs between FROM and TO of IN, and record
1800 the lastly applied feature in each glyph of IN. If OUT is not
1801 NULL, append the resulting glyphs to OUT while storing glyph
1802 position adjustment information in ADJUSTMENT. */
1805 ftfont_drive_otf (MFLTFont
*font
,
1807 MFLTGlyphString
*in
,
1810 MFLTGlyphString
*out
,
1811 MFLTGlyphAdjustment
*adjustment
)
1813 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
1814 MFLTGlyphFT
*in_glyphs
= (MFLTGlyphFT
*) (in
->glyphs
) + from
;
1815 MFLTGlyphFT
*out_glyphs
= out
? (MFLTGlyphFT
*) (out
->glyphs
) : NULL
;
1816 FT_Face ft_face
= flt_font_ft
->ft_face
;
1817 OTF
*otf
= flt_font_ft
->otf
;
1818 int len
= to
- from
;
1821 char script
[5], *langsys
= NULL
;
1822 char *gsub_features
= NULL
, *gpos_features
= NULL
;
1823 OTF_Feature
*features
;
1827 OTF_tag_name (spec
->script
, script
);
1832 langsys
= langsysbuf
;
1833 OTF_tag_name (spec
->langsys
, langsys
);
1837 for (i
= 0; i
< 2; i
++)
1841 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
1843 for (j
= 0; spec
->features
[i
][j
]; j
++);
1844 SAFE_NALLOCA (p
, 6, j
);
1849 for (j
= 0; spec
->features
[i
][j
]; j
++)
1851 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
1852 *p
++ = '*', *p
++ = ',';
1855 OTF_tag_name (spec
->features
[i
][j
], p
);
1864 setup_otf_gstring (len
);
1865 for (i
= 0; i
< len
; i
++)
1867 otf_gstring
.glyphs
[i
].c
= in_glyphs
[i
].g
.c
& 0x11FFFF;
1868 otf_gstring
.glyphs
[i
].glyph_id
= in_glyphs
[i
].g
.code
;
1869 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1870 otf_gstring
.glyphs
[i
].positioning_type
= in_glyphs
[i
].libotf_positioning_type
;
1874 OTF_drive_gdef (otf
, &otf_gstring
);
1875 gidx
= out
? out
->used
: from
;
1877 if (gsub_features
&& out
)
1879 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1880 if (OTF_drive_gsub_features (otf
, &otf_gstring
, script
, langsys
,
1884 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1888 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
1893 features
= otf
->gsub
->FeatureList
.Feature
;
1894 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
1897 int min_from
, max_to
;
1900 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1901 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1903 feature_idx
= otfg
->positioning_type
>> 4;
1905 g
= out_glyphs
+ out
->used
;
1906 *g
= in_glyphs
[otfg
->f
.index
.from
];
1907 if (g
->g
.code
!= otfg
->glyph_id
)
1910 g
->g
.code
= otfg
->glyph_id
;
1914 min_from
= g
->g
.from
;
1916 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
1918 /* OTFG substitutes multiple glyphs in IN. */
1919 for (j
= otfg
->f
.index
.from
+ 1; j
<= otfg
->f
.index
.to
; j
++)
1921 if (min_from
> in_glyphs
[j
].g
.from
)
1922 min_from
= in_glyphs
[j
].g
.from
;
1923 if (max_to
< in_glyphs
[j
].g
.to
)
1924 max_to
= in_glyphs
[j
].g
.to
;
1926 g
->g
.from
= min_from
;
1931 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1932 tag
= PACK_OTF_TAG (tag
);
1933 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1935 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1936 g
->libotf_positioning_type
1937 = otfg
->positioning_type
& OTF_positioning_type_components_mask
;
1939 for (i
++, otfg
++; (i
< otf_gstring
.used
1940 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
1943 g
= out_glyphs
+ out
->used
;
1944 *g
= in_glyphs
[otfg
->f
.index
.to
];
1945 if (g
->g
.code
!= otfg
->glyph_id
)
1948 g
->g
.code
= otfg
->glyph_id
;
1951 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1952 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1954 feature_idx
= otfg
->positioning_type
>> 4;
1958 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1959 tag
= PACK_OTF_TAG (tag
);
1960 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
1962 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1963 g
->libotf_positioning_type
1964 = otfg
->positioning_type
& OTF_positioning_type_components_mask
;
1970 else if (gsub_features
)
1972 /* Just for checking which features will be applied. */
1973 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1974 if (OTF_drive_gsub_features (otf
, &otf_gstring
, script
, langsys
,
1978 if (OTF_drive_gsub_with_log (otf
, &otf_gstring
, script
, langsys
,
1982 features
= otf
->gsub
->FeatureList
.Feature
;
1983 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; i
++,
1987 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
1988 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
1990 feature_idx
= otfg
->positioning_type
>> 4;
1994 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
1995 tag
= PACK_OTF_TAG (tag
);
1996 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
1998 MFLTGlyphFT
*g
= in_glyphs
+ j
;
1999 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
2006 if (out
->allocated
< out
->used
+ len
)
2011 for (i
= 0; i
< len
; i
++)
2012 out_glyphs
[out
->used
++] = in_glyphs
[i
];
2015 if (gpos_features
&& out
)
2017 MFLTGlyphFT
*base
= NULL
, *mark
= NULL
, *g
;
2018 int x_ppem
, y_ppem
, x_scale
, y_scale
;
2020 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2021 if (OTF_drive_gpos_features (otf
, &otf_gstring
, script
, langsys
,
2028 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
2035 features
= otf
->gpos
->FeatureList
.Feature
;
2036 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2037 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2038 x_scale
= ft_face
->size
->metrics
.x_scale
;
2039 y_scale
= ft_face
->size
->metrics
.y_scale
;
2041 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out_glyphs
+ gidx
;
2042 i
< otf_gstring
.used
; i
++, otfg
++)
2044 MFLTGlyphAdjustment
*adjust
= adjustment
;
2046 int positioning_type
, feature_idx
;
2048 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2049 positioning_type
= OTF_POSITIONING_TYPE_GET_FORMAT (otfg
);
2050 feature_idx
= OTF_POSITIONING_TYPE_GET_FEATURE (otfg
);
2052 positioning_type
= otfg
->positioning_type
& 0xF;
2053 feature_idx
= otfg
->positioning_type
>> 4;
2057 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
2058 tag
= PACK_OTF_TAG (tag
);
2059 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
2062 if (! otfg
->glyph_id
)
2063 /* This is a pseudo glyph that contains positioning
2064 information to be accumulated to a real glyph. */
2066 switch (positioning_type
)
2070 case 1: /* Single */
2073 int format
= otfg
->f
.f1
.format
;
2075 if (format
& OTF_XPlacement
)
2077 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
2078 if (format
& OTF_XPlaDevice
)
2080 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
2081 if (format
& OTF_YPlacement
)
2083 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
2084 if (format
& OTF_YPlaDevice
)
2086 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
2087 if (format
& OTF_XAdvance
)
2089 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
2090 if (format
& OTF_XAdvDevice
)
2092 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
2093 if (format
& OTF_YAdvance
)
2095 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
2096 if (format
& OTF_YAdvDevice
)
2098 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
2102 case 3: /* Cursive */
2103 /* Not yet supported. */
2105 case 4: /* Mark-to-Base */
2106 case 5: /* Mark-to-Ligature */
2110 goto label_adjust_anchor
;
2111 default: /* i.e. case 6 Mark-to-Mark */
2115 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2117 int distance
= OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg
);
2121 prev
= g
- distance
;
2122 if (prev
< out_glyphs
)
2128 label_adjust_anchor
:
2130 int base_x
, base_y
, mark_x
, mark_y
;
2131 int this_from
, this_to
;
2133 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
2134 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
2135 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
2136 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
2138 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
2139 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
, prev
->g
.code
,
2140 x_ppem
, y_ppem
, &base_x
, &base_y
);
2141 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
2142 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->g
.code
,
2143 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2144 adjust
->xoff
= (base_x
- mark_x
);
2145 adjust
->yoff
= - (base_y
- mark_y
);
2146 adjust
->back
= (g
- prev
);
2148 adjust
->advance_is_absolute
= 1;
2150 this_from
= g
->g
.from
;
2152 for (j
= 0; prev
+ j
< g
; j
++)
2154 if (this_from
> prev
[j
].g
.from
)
2155 this_from
= prev
[j
].g
.from
;
2156 if (this_to
< prev
[j
].g
.to
)
2157 this_to
= prev
[j
].g
.to
;
2159 for (; prev
<= g
; prev
++)
2161 prev
->g
.from
= this_from
;
2162 prev
->g
.to
= this_to
;
2168 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2170 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2178 else if (gpos_features
)
2180 if (OTF_drive_gpos_with_log (otf
, &otf_gstring
, script
, langsys
,
2186 features
= otf
->gpos
->FeatureList
.Feature
;
2187 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
;
2189 if (otfg
->positioning_type
& 0xF)
2191 int feature_idx
= otfg
->positioning_type
>> 4;
2195 unsigned int tag
= features
[feature_idx
- 1].FeatureTag
;
2196 tag
= PACK_OTF_TAG (tag
);
2197 for (j
= otfg
->f
.index
.from
; j
<= otfg
->f
.index
.to
; j
++)
2199 MFLTGlyphFT
*g
= in_glyphs
+ j
;
2200 g
->g
.internal
= (g
->g
.internal
& ~0x1FFFFFFF) | tag
;
2212 if (out
->allocated
< out
->used
+ len
)
2214 font
->get_metrics (font
, in
, from
, to
);
2215 memcpy (out
->glyphs
+ out
->used
, in_glyphs
, sizeof (MFLTGlyphFT
) * len
);
2221 ftfont_try_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
,
2222 MFLTGlyphString
*in
, int from
, int to
)
2224 return ftfont_drive_otf (font
, spec
, in
, from
, to
, NULL
, NULL
);
2227 #else /* not M17N_FLT_USE_NEW_FEATURE */
2230 ftfont_drive_otf (MFLTFont
*font
, MFLTOtfSpec
*spec
, MFLTGlyphString
*in
,
2232 MFLTGlyphString
*out
, MFLTGlyphAdjustment
*adjustment
)
2234 struct MFLTFontFT
*flt_font_ft
= (struct MFLTFontFT
*) font
;
2235 MFLTGlyphFT
*in_glyphs
= (MFLTGlyphFT
*) (in
->glyphs
) + from
;
2236 MFLTGlyphFT
*out_glyphs
= out
? (MFLTGlyphFT
*) (out
->glyphs
) : NULL
;
2237 FT_Face ft_face
= flt_font_ft
->ft_face
;
2238 OTF
*otf
= flt_font_ft
->otf
;
2239 int len
= to
- from
;
2242 char script
[5], *langsys
= NULL
;
2243 char *gsub_features
= NULL
, *gpos_features
= NULL
;
2247 OTF_tag_name (spec
->script
, script
);
2252 langsys
= langsysbuf
;
2253 OTF_tag_name (spec
->langsys
, langsys
);
2257 for (i
= 0; i
< 2; i
++)
2261 if (spec
->features
[i
] && spec
->features
[i
][1] != 0xFFFFFFFF)
2263 for (j
= 0; spec
->features
[i
][j
]; j
++);
2264 SAFE_NALLOCA (p
, 6, j
);
2269 for (j
= 0; spec
->features
[i
][j
]; j
++)
2271 if (spec
->features
[i
][j
] == 0xFFFFFFFF)
2272 *p
++ = '*', *p
++ = ',';
2275 OTF_tag_name (spec
->features
[i
][j
], p
);
2284 setup_otf_gstring (len
);
2285 for (i
= 0; i
< len
; i
++)
2287 otf_gstring
.glyphs
[i
].c
= in_glyphs
[i
].g
.c
;
2288 otf_gstring
.glyphs
[i
].glyph_id
= in_glyphs
[i
].g
.code
;
2291 OTF_drive_gdef (otf
, &otf_gstring
);
2296 if (OTF_drive_gsub (otf
, &otf_gstring
, script
, langsys
, gsub_features
)
2299 if (out
->allocated
< out
->used
+ otf_gstring
.used
)
2304 for (i
= 0, otfg
= otf_gstring
.glyphs
; i
< otf_gstring
.used
; )
2307 int min_from
, max_to
;
2310 g
= out_glyphs
+ out
->used
;
2311 *g
= in_glyphs
[otfg
->f
.index
.from
];
2312 if (g
->g
.code
!= otfg
->glyph_id
)
2315 g
->g
.code
= otfg
->glyph_id
;
2319 min_from
= g
->g
.from
;
2321 if (otfg
->f
.index
.from
< otfg
->f
.index
.to
)
2323 /* OTFG substitutes multiple glyphs in IN. */
2324 for (j
= from
+ otfg
->f
.index
.from
+ 1;
2325 j
<= from
+ otfg
->f
.index
.to
; j
++)
2327 if (min_from
> in
->glyphs
[j
].from
)
2328 min_from
= in
->glyphs
[j
].from
;
2329 if (max_to
< in
->glyphs
[j
].to
)
2330 max_to
= in
->glyphs
[j
].to
;
2332 g
->g
.from
= min_from
;
2335 for (i
++, otfg
++; (i
< otf_gstring
.used
2336 && otfg
->f
.index
.from
== otfg
[-1].f
.index
.from
);
2339 g
= out_glyphs
+ out
->used
;
2340 *g
= in_glyphs
[otfg
->f
.index
.to
];
2341 if (g
->g
.code
!= otfg
->glyph_id
)
2344 g
->g
.code
= otfg
->glyph_id
;
2353 if (out
->allocated
< out
->used
+ len
)
2358 for (i
= 0; i
< len
; i
++)
2359 out_glyphs
[out
->used
++] = in_glyphs
[i
];
2364 MFLTGlyphFT
*base
= NULL
, *mark
= NULL
, *g
;
2365 int x_ppem
, y_ppem
, x_scale
, y_scale
;
2367 if (OTF_drive_gpos (otf
, &otf_gstring
, script
, langsys
, gpos_features
)
2374 x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2375 y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2376 x_scale
= ft_face
->size
->metrics
.x_scale
;
2377 y_scale
= ft_face
->size
->metrics
.y_scale
;
2379 for (i
= 0, otfg
= otf_gstring
.glyphs
, g
= out_glyphs
+ gidx
;
2380 i
< otf_gstring
.used
; i
++, otfg
++, g
++)
2384 if (! otfg
->glyph_id
)
2386 switch (otfg
->positioning_type
)
2390 case 1: /* Single */
2393 int format
= otfg
->f
.f1
.format
;
2395 if (format
& OTF_XPlacement
)
2397 = otfg
->f
.f1
.value
->XPlacement
* x_scale
/ 0x10000;
2398 if (format
& OTF_XPlaDevice
)
2400 += DEVICE_DELTA (otfg
->f
.f1
.value
->XPlaDevice
, x_ppem
);
2401 if (format
& OTF_YPlacement
)
2403 = - (otfg
->f
.f1
.value
->YPlacement
* y_scale
/ 0x10000);
2404 if (format
& OTF_YPlaDevice
)
2406 -= DEVICE_DELTA (otfg
->f
.f1
.value
->YPlaDevice
, y_ppem
);
2407 if (format
& OTF_XAdvance
)
2409 += otfg
->f
.f1
.value
->XAdvance
* x_scale
/ 0x10000;
2410 if (format
& OTF_XAdvDevice
)
2412 += DEVICE_DELTA (otfg
->f
.f1
.value
->XAdvDevice
, x_ppem
);
2413 if (format
& OTF_YAdvance
)
2415 += otfg
->f
.f1
.value
->YAdvance
* y_scale
/ 0x10000;
2416 if (format
& OTF_YAdvDevice
)
2418 += DEVICE_DELTA (otfg
->f
.f1
.value
->YAdvDevice
, y_ppem
);
2419 adjustment
[i
].set
= 1;
2422 case 3: /* Cursive */
2423 /* Not yet supported. */
2425 case 4: /* Mark-to-Base */
2426 case 5: /* Mark-to-Ligature */
2430 goto label_adjust_anchor
;
2431 default: /* i.e. case 6 Mark-to-Mark */
2436 label_adjust_anchor
:
2438 int base_x
, base_y
, mark_x
, mark_y
;
2439 int this_from
, this_to
;
2441 base_x
= otfg
->f
.f4
.base_anchor
->XCoordinate
* x_scale
/ 0x10000;
2442 base_y
= otfg
->f
.f4
.base_anchor
->YCoordinate
* y_scale
/ 0x10000;
2443 mark_x
= otfg
->f
.f4
.mark_anchor
->XCoordinate
* x_scale
/ 0x10000;
2444 mark_y
= otfg
->f
.f4
.mark_anchor
->YCoordinate
* y_scale
/ 0x10000;
2446 if (otfg
->f
.f4
.base_anchor
->AnchorFormat
!= 1)
2447 adjust_anchor (ft_face
, otfg
->f
.f4
.base_anchor
, prev
->g
.code
,
2448 x_ppem
, y_ppem
, &base_x
, &base_y
);
2449 if (otfg
->f
.f4
.mark_anchor
->AnchorFormat
!= 1)
2450 adjust_anchor (ft_face
, otfg
->f
.f4
.mark_anchor
, g
->g
.code
,
2451 x_ppem
, y_ppem
, &mark_x
, &mark_y
);
2452 adjustment
[i
].xoff
= (base_x
- mark_x
);
2453 adjustment
[i
].yoff
= - (base_y
- mark_y
);
2454 adjustment
[i
].back
= (g
- prev
);
2455 adjustment
[i
].xadv
= 0;
2456 adjustment
[i
].advance_is_absolute
= 1;
2457 adjustment
[i
].set
= 1;
2458 this_from
= g
->g
.from
;
2460 for (j
= 0; prev
+ j
< g
; j
++)
2462 if (this_from
> prev
[j
].g
.from
)
2463 this_from
= prev
[j
].g
.from
;
2464 if (this_to
< prev
[j
].g
.to
)
2465 this_to
= prev
[j
].g
.to
;
2467 for (; prev
<= g
; prev
++)
2469 prev
->g
.from
= this_from
;
2470 prev
->g
.to
= this_to
;
2474 if (otfg
->GlyphClass
== OTF_GlyphClass0
)
2476 else if (otfg
->GlyphClass
== OTF_GlyphClassMark
)
2487 if (out
->allocated
< out
->used
+ len
)
2489 font
->get_metrics (font
, in
, from
, to
);
2490 memcpy (out_glyphs
+ out
->used
, in_glyphs
,
2491 sizeof (MFLTGlyphFT
) * len
);
2496 #endif /* not M17N_FLT_USE_NEW_FEATURE */
2498 static MFLTGlyphString gstring
;
2500 static bool m17n_flt_initialized
;
2503 ftfont_shape_by_flt (Lisp_Object lgstring
, struct font
*font
,
2504 FT_Face ft_face
, OTF
*otf
, FT_Matrix
*matrix
)
2506 ptrdiff_t len
= LGSTRING_GLYPH_LEN (lgstring
);
2508 struct MFLTFontFT flt_font_ft
;
2510 bool with_variation_selector
= false;
2512 if (! m17n_flt_initialized
)
2515 #ifdef M17N_FLT_USE_NEW_FEATURE
2516 mflt_enable_new_feature
= 1;
2517 mflt_try_otf
= ftfont_try_otf
;
2518 #endif /* M17N_FLT_USE_NEW_FEATURE */
2519 m17n_flt_initialized
= 1;
2522 for (i
= 0; i
< len
; i
++)
2524 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2529 c
= LGLYPH_CHAR (g
);
2530 if (CHAR_VARIATION_SELECTOR_P (c
))
2531 with_variation_selector
= true;
2536 if (with_variation_selector
)
2538 setup_otf_gstring (len
);
2539 for (i
= 0; i
< len
; i
++)
2541 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2543 otf_gstring
.glyphs
[i
].c
= LGLYPH_CHAR (g
);
2544 otf_gstring
.glyphs
[i
].f
.index
.from
= LGLYPH_FROM (g
);
2545 otf_gstring
.glyphs
[i
].f
.index
.to
= LGLYPH_TO (g
);
2547 OTF_drive_cmap (otf
, &otf_gstring
);
2548 for (i
= 0; i
< otf_gstring
.used
; i
++)
2550 OTF_Glyph
*otfg
= otf_gstring
.glyphs
+ i
;
2551 Lisp_Object g0
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.from
);
2552 Lisp_Object g1
= LGSTRING_GLYPH (lgstring
, otfg
->f
.index
.to
);
2554 LGLYPH_SET_CODE (g0
, otfg
->glyph_id
);
2555 LGLYPH_SET_TO (g0
, LGLYPH_TO (g1
));
2556 LGSTRING_SET_GLYPH (lgstring
, i
, g0
);
2558 if (len
> otf_gstring
.used
)
2560 len
= otf_gstring
.used
;
2561 LGSTRING_SET_GLYPH (lgstring
, len
, Qnil
);
2566 Lisp_Object family
= Ffont_get (LGSTRING_FONT (lgstring
), QCfamily
);
2569 flt_font_ft
.flt_font
.family
= Mnil
;
2571 flt_font_ft
.flt_font
.family
2572 = msymbol (SSDATA (Fdowncase (SYMBOL_NAME (family
))));
2574 flt_font_ft
.flt_font
.x_ppem
= ft_face
->size
->metrics
.x_ppem
;
2575 flt_font_ft
.flt_font
.y_ppem
= ft_face
->size
->metrics
.y_ppem
;
2576 flt_font_ft
.flt_font
.get_glyph_id
= ftfont_get_glyph_id
;
2577 flt_font_ft
.flt_font
.get_metrics
= ftfont_get_metrics
;
2578 flt_font_ft
.flt_font
.check_otf
= ftfont_check_otf
;
2579 flt_font_ft
.flt_font
.drive_otf
= ftfont_drive_otf
;
2580 flt_font_ft
.flt_font
.internal
= NULL
;
2581 flt_font_ft
.font
= font
;
2582 flt_font_ft
.ft_face
= ft_face
;
2583 flt_font_ft
.otf
= otf
;
2584 flt_font_ft
.matrix
= matrix
->xx
!= 0 ? matrix
: 0;
2588 /* A little bit ad hoc. Perhaps, shaper must get script and
2589 language information, and select a proper flt for them
2591 int c1
= LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, 1));
2592 if (0x300 <= c1
&& c1
<= 0x36F)
2593 flt
= mflt_get (msymbol ("combining"));
2596 MFLTGlyphFT
*glyphs
= (MFLTGlyphFT
*) gstring
.glyphs
;
2597 ptrdiff_t allocated
= gstring
.allocated
;
2598 ptrdiff_t incr_min
= len
- allocated
;
2605 glyphs
= xpalloc (NULL
, &allocated
, incr_min
, INT_MAX
, sizeof *glyphs
);
2609 for (i
= 0; i
< len
; i
++)
2611 Lisp_Object g
= LGSTRING_GLYPH (lgstring
, i
);
2612 memset (&glyphs
[i
], 0, sizeof glyphs
[i
]);
2613 glyphs
[i
].g
.c
= LGLYPH_CHAR (g
);
2614 if (with_variation_selector
)
2616 glyphs
[i
].g
.code
= LGLYPH_CODE (g
);
2617 glyphs
[i
].g
.encoded
= 1;
2621 gstring
.glyph_size
= sizeof *glyphs
;
2622 gstring
.glyphs
= (MFLTGlyph
*) glyphs
;
2623 gstring
.allocated
= allocated
;
2627 while (mflt_run (&gstring
, 0, len
, &flt_font_ft
.flt_font
, flt
) == -2);
2629 if (gstring
.used
> LGSTRING_GLYPH_LEN (lgstring
))
2631 for (i
= 0; i
< gstring
.used
; i
++)
2633 MFLTGlyphFT
*g
= (MFLTGlyphFT
*) (gstring
.glyphs
) + i
;
2635 g
->g
.from
= LGLYPH_FROM (LGSTRING_GLYPH (lgstring
, g
->g
.from
));
2636 g
->g
.to
= LGLYPH_TO (LGSTRING_GLYPH (lgstring
, g
->g
.to
));
2639 for (i
= 0; i
< gstring
.used
; i
++)
2641 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
, i
);
2642 MFLTGlyphFT
*g
= (MFLTGlyphFT
*) (gstring
.glyphs
) + i
;
2646 lglyph
= LGLYPH_NEW ();
2647 LGSTRING_SET_GLYPH (lgstring
, i
, lglyph
);
2649 LGLYPH_SET_FROM (lglyph
, g
->g
.from
);
2650 LGLYPH_SET_TO (lglyph
, g
->g
.to
);
2651 LGLYPH_SET_CHAR (lglyph
, g
->g
.c
);
2652 LGLYPH_SET_CODE (lglyph
, g
->g
.code
);
2653 LGLYPH_SET_WIDTH (lglyph
, g
->g
.xadv
>> 6);
2654 LGLYPH_SET_LBEARING (lglyph
, g
->g
.lbearing
>> 6);
2655 LGLYPH_SET_RBEARING (lglyph
, g
->g
.rbearing
>> 6);
2656 LGLYPH_SET_ASCENT (lglyph
, g
->g
.ascent
>> 6);
2657 LGLYPH_SET_DESCENT (lglyph
, g
->g
.descent
>> 6);
2660 Lisp_Object vec
= make_uninit_vector (3);
2662 ASET (vec
, 0, make_number (g
->g
.xoff
>> 6));
2663 ASET (vec
, 1, make_number (g
->g
.yoff
>> 6));
2664 ASET (vec
, 2, make_number (g
->g
.xadv
>> 6));
2665 LGLYPH_SET_ADJUSTMENT (lglyph
, vec
);
2668 return make_number (i
);
2672 ftfont_shape (Lisp_Object lgstring
)
2674 struct font
*font
= CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring
));
2675 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
2676 OTF
*otf
= ftfont_get_otf (ftfont_info
);
2679 return make_number (0);
2680 return ftfont_shape_by_flt (lgstring
, font
, ftfont_info
->ft_size
->face
, otf
,
2681 &ftfont_info
->matrix
);
2684 #endif /* HAVE_M17N_FLT */
2686 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
2689 ftfont_variation_glyphs (struct font
*font
, int c
, unsigned variations
[256])
2691 struct ftfont_info
*ftfont_info
= (struct ftfont_info
*) font
;
2692 OTF
*otf
= ftfont_get_otf (ftfont_info
);
2696 return OTF_get_variation_glyphs (otf
, c
, variations
);
2699 #endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
2700 #endif /* HAVE_LIBOTF */
2702 static const char *const ftfont_booleans
[] = {
2715 static const char *const ftfont_non_booleans
[] = {
2747 ftfont_filter_properties (Lisp_Object font
, Lisp_Object alist
)
2749 font_filter_properties (font
, alist
, ftfont_booleans
, ftfont_non_booleans
);
2754 syms_of_ftfont (void)
2756 /* Symbolic type of this font-driver. */
2757 DEFSYM (Qfreetype
, "freetype");
2759 /* Fontconfig's generic families and their aliases. */
2760 DEFSYM (Qmonospace
, "monospace");
2761 DEFSYM (Qsans_serif
, "sans-serif");
2762 DEFSYM (Qsans
, "sans");
2763 DEFSYM (Qsans__serif
, "sans serif");
2765 staticpro (&freetype_font_cache
);
2766 freetype_font_cache
= list1 (Qt
);
2768 staticpro (&ftfont_generic_family_list
);
2769 ftfont_generic_family_list
= list3 (Fcons (Qmonospace
, Qt
),
2770 Fcons (Qsans_serif
, Qt
),
2773 staticpro (&ft_face_cache
);
2774 ft_face_cache
= Qnil
;
2776 ftfont_driver
.type
= Qfreetype
;
2777 register_font_driver (&ftfont_driver
, NULL
);