summaryrefslogtreecommitdiff
path: root/src/ftfont.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ftfont.c')
-rw-r--r--src/ftfont.c789
1 files changed, 624 insertions, 165 deletions
diff --git a/src/ftfont.c b/src/ftfont.c
index 35f59233761..301a145b7ac 100644
--- a/src/ftfont.c
+++ b/src/ftfont.c
@@ -1,5 +1,5 @@
/* ftfont.c -- FreeType font driver.
- Copyright (C) 2006-2017 Free Software Foundation, Inc.
+ Copyright (C) 2006-2022 Free Software Foundation, Inc.
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
National Institute of Advanced Industrial Science and Technology (AIST)
Registration Number H13PRO009
@@ -20,10 +20,20 @@ You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
-#include <stdio.h>
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
+/* These two blocks are here because this file is built when using XFT
+ and when using Cairo, so struct font_info in ftfont.h needs access
+ to the appropriate types. */
+#ifdef HAVE_XFT
+# include <X11/Xlib.h>
+# include <X11/Xft/Xft.h>
+#endif
+#ifdef USE_CAIRO
+# include <cairo-ft.h>
+#endif
+
#include <c-strcase.h>
#include "lisp.h"
@@ -34,8 +44,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "composite.h"
#include "font.h"
#include "ftfont.h"
+#include "pdumper.h"
static struct font_driver const ftfont_driver;
+#ifdef HAVE_HARFBUZZ
+static struct font_driver fthbfont_driver;
+#endif /* HAVE_HARFBUZZ */
/* Flag to tell if FcInit is already called or not. */
static bool fc_initialized;
@@ -49,25 +63,6 @@ static Lisp_Object freetype_font_cache;
/* Cache for FT_Face and FcCharSet. */
static Lisp_Object ft_face_cache;
-/* The actual structure for FreeType font that can be cast to struct
- font. */
-
-struct ftfont_info
-{
- struct font font;
-#ifdef HAVE_LIBOTF
- /* The following four members must be here in this order to be
- compatible with struct xftfont_info (in xftfont.c). */
- bool maybe_otf; /* Flag to tell if this may be OTF or not. */
- OTF *otf;
-#endif /* HAVE_LIBOTF */
- FT_Size ft_size;
- int index;
- FT_Matrix matrix;
-};
-
-size_t ftfont_info_size = sizeof (struct ftfont_info);
-
enum ftfont_cache_for
{
FTFONT_CACHE_FOR_FACE,
@@ -107,7 +102,7 @@ static struct
{ "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
{ "iso8859-16", { 0x00A0, 0x0218}},
{ "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
- { "big5-0", { 0xF6B1 }, "zh-tw" },
+ { "big5-0", { 0x9C21 }, "zh-tw" },
{ "jisx0208.1983-0", { 0x4E55 }, "ja"},
{ "ksc5601.1985-0", { 0xAC00 }, "ko"},
{ "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
@@ -124,7 +119,7 @@ static struct
{ "jisx0213.2004-1", { 0x20B9F }},
{ "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
{ "tis620.2529-1", { 0x0E01 }, "th"},
- { "windows-1251", { 0x0401, 0x0490 }, "ru"},
+ { "microsoft-cp1251", { 0x0401, 0x0490 }, "ru"},
{ "koi8-r", { 0x0401, 0x2219 }, "ru"},
{ "mulelao-1", { 0x0E81 }, "lo"},
{ "unicode-sip", { 0x20000 }},
@@ -194,9 +189,27 @@ ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
return Qnil;
if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
return Qnil;
+#ifdef FC_VARIABLE
+ /* This is a virtual/meta FcPattern for a variable weight font, from
+ which it is possible to extract an FcRange value specifying the
+ minimum and maximum weights available in this file. We don't
+ need to know that information explicitly, so skip it. We will be
+ called with an FcPattern for each actually available, non-virtual
+ weight.
+
+ Fontconfig started generating virtual/meta patterns for variable
+ weight fonts in the same release that FC_VARIABLE was added, so
+ we conditionalize on that constant. This also ensures that
+ FcPatternGetRange is available. */
+ FcRange *range;
+ if (FcPatternGetRange (p, FC_WEIGHT, 0, &range) == FcResultMatch
+ && FcPatternGetBool (p, FC_VARIABLE, 0, &b) == FcResultMatch
+ && b == FcTrue)
+ return Qnil;
+#endif /* FC_VARIABLE */
file = (char *) str;
- key = Fcons (build_unibyte_string (file), make_number (idx));
+ key = Fcons (build_unibyte_string (file), make_fixnum (idx));
cache = ftfont_lookup_cache (key, FTFONT_CACHE_FOR_ENTITY);
entity = XCAR (cache);
if (! NILP (entity))
@@ -230,37 +243,35 @@ ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
}
if (FcPatternGetInteger (p, FC_WEIGHT, 0, &numeric) == FcResultMatch)
{
- if (numeric >= FC_WEIGHT_REGULAR && numeric < FC_WEIGHT_MEDIUM)
- numeric = FC_WEIGHT_MEDIUM;
- FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_number (numeric));
+ FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, make_fixnum (numeric));
}
if (FcPatternGetInteger (p, FC_SLANT, 0, &numeric) == FcResultMatch)
{
numeric += 100;
- FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_number (numeric));
+ FONT_SET_STYLE (entity, FONT_SLANT_INDEX, make_fixnum (numeric));
}
if (FcPatternGetInteger (p, FC_WIDTH, 0, &numeric) == FcResultMatch)
{
- FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (numeric));
+ FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_fixnum (numeric));
}
if (FcPatternGetDouble (p, FC_PIXEL_SIZE, 0, &dbl) == FcResultMatch)
{
- ASET (entity, FONT_SIZE_INDEX, make_number (dbl));
+ ASET (entity, FONT_SIZE_INDEX, make_fixnum (dbl));
}
else
- ASET (entity, FONT_SIZE_INDEX, make_number (0));
+ ASET (entity, FONT_SIZE_INDEX, make_fixnum (0));
if (FcPatternGetInteger (p, FC_SPACING, 0, &numeric) == FcResultMatch)
- ASET (entity, FONT_SPACING_INDEX, make_number (numeric));
+ ASET (entity, FONT_SPACING_INDEX, make_fixnum (numeric));
if (FcPatternGetDouble (p, FC_DPI, 0, &dbl) == FcResultMatch)
{
int dpi = dbl;
- ASET (entity, FONT_DPI_INDEX, make_number (dpi));
+ ASET (entity, FONT_DPI_INDEX, make_fixnum (dpi));
}
if (FcPatternGetBool (p, FC_SCALABLE, 0, &b) == FcResultMatch
&& b == FcTrue)
{
- ASET (entity, FONT_SIZE_INDEX, make_number (0));
- ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
+ ASET (entity, FONT_SIZE_INDEX, make_fixnum (0));
+ ASET (entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
}
else
{
@@ -276,7 +287,7 @@ ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
if (FT_Get_BDF_Property (ft_face, "AVERAGE_WIDTH", &rec) == 0
&& rec.type == BDF_PROPERTY_TYPE_INTEGER)
- ASET (entity, FONT_AVGWIDTH_INDEX, make_number (rec.u.integer));
+ ASET (entity, FONT_AVGWIDTH_INDEX, make_fixnum (rec.u.integer));
FT_Done_Face (ft_face);
}
}
@@ -345,23 +356,21 @@ struct ftfont_cache_data
{
FT_Face ft_face;
FcCharSet *fc_charset;
+ intptr_t face_refcount;
};
static Lisp_Object
ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
{
- Lisp_Object cache, val, entity;
+ Lisp_Object cache, val;
struct ftfont_cache_data *cache_data;
if (FONT_ENTITY_P (key))
{
- entity = key;
- val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
+ val = assq_no_quit (QCfont_entity, AREF (key, FONT_EXTRA_INDEX));
eassert (CONSP (val));
key = XCDR (val);
}
- else
- entity = Qnil;
if (NILP (ft_face_cache))
cache = Qnil;
@@ -371,17 +380,15 @@ ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
{
if (NILP (ft_face_cache))
ft_face_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
- cache_data = xmalloc (sizeof *cache_data);
- cache_data->ft_face = NULL;
- cache_data->fc_charset = NULL;
- val = make_save_ptr_int (cache_data, 0);
+ cache_data = xzalloc (sizeof *cache_data);
+ val = make_mint_ptr (cache_data);
cache = Fcons (Qnil, val);
Fputhash (key, cache, ft_face_cache);
}
else
{
val = XCDR (cache);
- cache_data = XSAVE_POINTER (val, 0);
+ cache_data = xmint_pointer (val);
}
if (cache_for == FTFONT_CACHE_FOR_ENTITY)
@@ -391,7 +398,7 @@ ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
? ! cache_data->ft_face : ! cache_data->fc_charset)
{
char *filename = SSDATA (XCAR (key));
- int idx = XINT (XCDR (key));
+ int idx = XFIXNUM (XCDR (key));
if (cache_for == FTFONT_CACHE_FOR_FACE)
{
@@ -439,7 +446,7 @@ ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
return cache;
}
-FcCharSet *
+static FcCharSet *
ftfont_get_fc_charset (Lisp_Object entity)
{
Lisp_Object val, cache;
@@ -447,13 +454,13 @@ ftfont_get_fc_charset (Lisp_Object entity)
cache = ftfont_lookup_cache (entity, FTFONT_CACHE_FOR_CHARSET);
val = XCDR (cache);
- cache_data = XSAVE_POINTER (val, 0);
+ cache_data = xmint_pointer (val);
return cache_data->fc_charset;
}
#ifdef HAVE_LIBOTF
static OTF *
-ftfont_get_otf (struct ftfont_info *ftfont_info)
+ftfont_get_otf (struct font_info *ftfont_info)
{
OTF *otf;
@@ -557,7 +564,19 @@ struct OpenTypeSpec
OTF_TAG_STR (TAG, str); \
(SYM) = font_intern_prop (str, 4, 1); \
} while (0)
-#endif
+#elif defined HAVE_HARFBUZZ
+/* Libotf emulations on HarfBuzz for the functions called from
+ ftfont_list. They are a bit slower than the original ones, so used
+ as fallbacks when libotf is not available. */
+typedef hb_face_t OTF;
+typedef unsigned int OTF_tag;
+static OTF *hbotf_open (const char *);
+static int hbotf_check_features (OTF *, int, OTF_tag, OTF_tag,
+ const OTF_tag *, int);
+#define OTF_open hbotf_open
+#define OTF_close hb_face_destroy
+#define OTF_check_features hbotf_check_features
+#endif /* !HAVE_LIBOTF && HAVE_HARFBUZZ */
static struct OpenTypeSpec *
@@ -594,16 +613,14 @@ ftfont_get_open_type_spec (Lisp_Object otf_spec)
spec->nfeatures[0] = spec->nfeatures[1] = 0;
for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
{
- Lisp_Object len;
-
val = XCAR (otf_spec);
if (NILP (val))
continue;
- len = Flength (val);
+ ptrdiff_t len = list_length (val);
spec->features[i] =
- (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
+ (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < len
? 0
- : malloc (XINT (len) * sizeof *spec->features[i]));
+ : malloc (len * sizeof *spec->features[i]));
if (! spec->features[i])
{
if (i > 0 && spec->features[0])
@@ -620,7 +637,7 @@ ftfont_get_open_type_spec (Lisp_Object otf_spec)
unsigned int tag;
OTF_SYM_TAG (XCAR (val), tag);
- spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
+ spec->features[i][j++] = negative ? tag | 0x80000000 : tag;
}
}
spec->nfeatures[i] = j;
@@ -628,8 +645,29 @@ ftfont_get_open_type_spec (Lisp_Object otf_spec)
return spec;
}
+#if defined HAVE_XFT && defined FC_COLOR
+static bool
+xft_color_font_whitelisted_p (const char *family)
+{
+ Lisp_Object tem, name;
+
+ tem = Vxft_color_font_whitelist;
+
+ FOR_EACH_TAIL_SAFE (tem)
+ {
+ name = XCAR (tem);
+
+ if (STRINGP (name) && !strcmp (family, SSDATA (name)))
+ return true;
+ }
+
+ return false;
+}
+#endif
+
static FcPattern *
-ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **otspec, const char **langname)
+ftfont_spec_pattern (Lisp_Object spec, char *otlayout,
+ struct OpenTypeSpec **otspec, const char **langname)
{
Lisp_Object tmp, extra;
FcPattern *pattern = NULL;
@@ -647,10 +685,10 @@ ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **ots
/* Fontconfig doesn't support reverse-italic/oblique. */
return NULL;
- if (INTEGERP (AREF (spec, FONT_DPI_INDEX)))
- dpi = XINT (AREF (spec, FONT_DPI_INDEX));
- if (INTEGERP (AREF (spec, FONT_AVGWIDTH_INDEX))
- && XINT (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
+ if (FIXNUMP (AREF (spec, FONT_DPI_INDEX)))
+ dpi = XFIXNUM (AREF (spec, FONT_DPI_INDEX));
+ if (FIXNUMP (AREF (spec, FONT_AVGWIDTH_INDEX))
+ && XFIXNUM (AREF (spec, FONT_AVGWIDTH_INDEX)) == 0)
scalable = 1;
registry = AREF (spec, FONT_REGISTRY_INDEX);
@@ -687,8 +725,8 @@ ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **ots
key = XCAR (XCAR (extra)), val = XCDR (XCAR (extra));
if (EQ (key, QCdpi))
{
- if (INTEGERP (val))
- dpi = XINT (val);
+ if (FIXNUMP (val))
+ dpi = XFIXNUM (val);
}
else if (EQ (key, QClang))
{
@@ -736,7 +774,7 @@ ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **ots
goto err;
for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
if (CHARACTERP (XCAR (chars))
- && ! FcCharSetAddChar (charset, XFASTINT (XCAR (chars))))
+ && ! FcCharSetAddChar (charset, XFIXNAT (XCAR (chars))))
goto err;
}
}
@@ -764,6 +802,15 @@ ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **ots
if (scalable >= 0
&& ! FcPatternAddBool (pattern, FC_SCALABLE, scalable ? FcTrue : FcFalse))
goto err;
+#if defined HAVE_XFT && defined FC_COLOR
+ /* We really don't like color fonts, they cause Xft crashes. See
+ Bug#30874. */
+ if (xft_ignore_color_fonts
+ && (NILP (AREF (spec, FONT_FAMILY_INDEX))
+ || NILP (Vxft_color_font_whitelist))
+ && ! FcPatternAddBool (pattern, FC_COLOR, FcFalse))
+ goto err;
+#endif
goto finish;
@@ -791,7 +838,7 @@ ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **ots
return pattern;
}
-Lisp_Object
+static Lisp_Object
ftfont_list (struct frame *f, Lisp_Object spec)
{
Lisp_Object val = Qnil, family, adstyle;
@@ -826,8 +873,8 @@ ftfont_list (struct frame *f, Lisp_Object spec)
}
val = Qnil;
}
- if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
- spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
+ if (FIXNUMP (AREF (spec, FONT_SPACING_INDEX)))
+ spacing = XFIXNUM (AREF (spec, FONT_SPACING_INDEX));
family = AREF (spec, FONT_FAMILY_INDEX);
if (! NILP (family))
{
@@ -854,6 +901,12 @@ ftfont_list (struct frame *f, Lisp_Object spec)
#ifdef FC_FONTFORMAT
FC_FONTFORMAT,
#endif
+#if defined HAVE_XFT && defined FC_COLOR
+ FC_COLOR,
+#endif
+#ifdef FC_VARIABLE
+ FC_VARIABLE,
+#endif /* FC_VARIABLE */
NULL);
if (! objset)
goto err;
@@ -893,7 +946,24 @@ ftfont_list (struct frame *f, Lisp_Object spec)
for (i = 0; i < fontset->nfont; i++)
{
Lisp_Object entity;
-
+#if defined HAVE_XFT && defined FC_COLOR
+ {
+ /* Some fonts, notably NotoColorEmoji, have an FC_COLOR value
+ that's neither FcTrue nor FcFalse, which means FcFontList
+ returns them even when it shouldn't really do so, so we
+ need to manually skip them here (Bug#37786). */
+ FcBool b;
+ FcChar8 *str;
+
+ if (xft_ignore_color_fonts
+ && (FcPatternGetString (fontset->fonts[i], FC_FAMILY,
+ 0, &str) != FcResultMatch
+ || !xft_color_font_whitelisted_p ((char *) str))
+ && FcPatternGetBool (fontset->fonts[i], FC_COLOR, 0, &b)
+ == FcResultMatch && b != FcFalse)
+ continue;
+ }
+#endif
if (spacing >= 0)
{
int this;
@@ -915,7 +985,7 @@ ftfont_list (struct frame *f, Lisp_Object spec)
continue;
}
#endif /* FC_CAPABILITY */
-#ifdef HAVE_LIBOTF
+#if defined HAVE_LIBOTF || defined HAVE_HARFBUZZ
if (otspec)
{
FcChar8 *file;
@@ -940,7 +1010,7 @@ ftfont_list (struct frame *f, Lisp_Object spec)
if (!passed)
continue;
}
-#endif /* HAVE_LIBOTF */
+#endif /* HAVE_LIBOTF || HAVE_HARFBUZZ */
if (VECTORP (chars))
{
ptrdiff_t j;
@@ -949,8 +1019,8 @@ ftfont_list (struct frame *f, Lisp_Object spec)
!= FcResultMatch)
continue;
for (j = 0; j < ASIZE (chars); j++)
- if (TYPE_RANGED_INTEGERP (FcChar32, AREF (chars, j))
- && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
+ if (TYPE_RANGED_FIXNUMP (FcChar32, AREF (chars, j))
+ && FcCharSetHasChar (charset, XFIXNAT (AREF (chars, j))))
break;
if (j == ASIZE (chars))
continue;
@@ -991,6 +1061,16 @@ ftfont_list (struct frame *f, Lisp_Object spec)
}
Lisp_Object
+ftfont_list2 (struct frame *f, Lisp_Object spec, Lisp_Object type)
+{
+ Lisp_Object list = ftfont_list (f, spec);
+
+ for (Lisp_Object tail = list; CONSP (tail); tail = XCDR (tail))
+ ASET (XCAR (tail), FONT_TYPE_INDEX, type);
+ return list;
+}
+
+static Lisp_Object
ftfont_match (struct frame *f, Lisp_Object spec)
{
Lisp_Object entity = Qnil;
@@ -1010,12 +1090,12 @@ ftfont_match (struct frame *f, Lisp_Object spec)
if (! pattern)
return Qnil;
- if (INTEGERP (AREF (spec, FONT_SIZE_INDEX)))
+ if (FIXNUMP (AREF (spec, FONT_SIZE_INDEX)))
{
FcValue value;
value.type = FcTypeDouble;
- value.u.d = XINT (AREF (spec, FONT_SIZE_INDEX));
+ value.u.d = XFIXNUM (AREF (spec, FONT_SIZE_INDEX));
FcPatternAdd (pattern, FC_PIXEL_SIZE, value, FcFalse);
}
if (FcConfigSubstitute (NULL, pattern, FcMatchPattern) == FcTrue)
@@ -1041,6 +1121,16 @@ ftfont_match (struct frame *f, Lisp_Object spec)
}
Lisp_Object
+ftfont_match2 (struct frame *f, Lisp_Object spec, Lisp_Object type)
+{
+ Lisp_Object entity = ftfont_match (f, spec);
+
+ if (! NILP (entity))
+ ASET (entity, FONT_TYPE_INDEX, type);
+ return entity;
+}
+
+Lisp_Object
ftfont_list_family (struct frame *f)
{
Lisp_Object list = Qnil;
@@ -1082,20 +1172,169 @@ ftfont_list_family (struct frame *f)
return list;
}
+void
+ftfont_fix_match (FcPattern *pat, FcPattern *match)
+{
+ /* These values are not used for matching (except antialias), but for
+ rendering, so make sure they are carried over to the match.
+ We also put antialias here because most fonts are antialiased, so
+ the match will have antialias true. */
+
+ FcBool b = FcTrue;
+ int i;
+ double dpi;
+
+ FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b);
+ if (! b)
+ {
+ FcPatternDel (match, FC_ANTIALIAS);
+ FcPatternAddBool (match, FC_ANTIALIAS, FcFalse);
+ }
+ FcPatternGetBool (pat, FC_HINTING, 0, &b);
+ if (! b)
+ {
+ FcPatternDel (match, FC_HINTING);
+ FcPatternAddBool (match, FC_HINTING, FcFalse);
+ }
+#ifndef FC_HINT_STYLE
+# define FC_HINT_STYLE "hintstyle"
+#endif
+ if (FcResultMatch == FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i))
+ {
+ FcPatternDel (match, FC_HINT_STYLE);
+ FcPatternAddInteger (match, FC_HINT_STYLE, i);
+ }
+#ifndef FC_LCD_FILTER
+ /* Older fontconfig versions don't have FC_LCD_FILTER. */
+#define FC_LCD_FILTER "lcdfilter"
+#endif
+ if (FcResultMatch == FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i))
+ {
+ FcPatternDel (match, FC_LCD_FILTER);
+ FcPatternAddInteger (match, FC_LCD_FILTER, i);
+ }
+ if (FcResultMatch == FcPatternGetInteger (pat, FC_RGBA, 0, &i))
+ {
+ FcPatternDel (match, FC_RGBA);
+ FcPatternAddInteger (match, FC_RGBA, i);
+ }
+ if (FcResultMatch == FcPatternGetDouble (pat, FC_DPI, 0, &dpi))
+ {
+ FcPatternDel (match, FC_DPI);
+ FcPatternAddDouble (match, FC_DPI, dpi);
+ }
+}
+
+void
+ftfont_add_rendering_parameters (FcPattern *pat, Lisp_Object entity)
+{
+ Lisp_Object tail;
+ int ival;
+
+ for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
+ {
+ Lisp_Object key = XCAR (XCAR (tail));
+ Lisp_Object val = XCDR (XCAR (tail));
+
+ if (EQ (key, QCantialias))
+ FcPatternAddBool (pat, FC_ANTIALIAS, NILP (val) ? FcFalse : FcTrue);
+ else if (EQ (key, QChinting))
+ FcPatternAddBool (pat, FC_HINTING, NILP (val) ? FcFalse : FcTrue);
+ else if (EQ (key, QCautohint))
+ FcPatternAddBool (pat, FC_AUTOHINT, NILP (val) ? FcFalse : FcTrue);
+ else if (EQ (key, QChintstyle))
+ {
+ if (FIXNUMP (val))
+ FcPatternAddInteger (pat, FC_HINT_STYLE, XFIXNUM (val));
+ else if (SYMBOLP (val)
+ && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
+ FcPatternAddInteger (pat, FC_HINT_STYLE, ival);
+ }
+ else if (EQ (key, QCrgba))
+ {
+ if (FIXNUMP (val))
+ FcPatternAddInteger (pat, FC_RGBA, XFIXNUM (val));
+ else if (SYMBOLP (val)
+ && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
+ FcPatternAddInteger (pat, FC_RGBA, ival);
+ }
+ else if (EQ (key, QClcdfilter))
+ {
+ if (FIXNUMP (val))
+ FcPatternAddInteger (pat, FC_LCD_FILTER, ival = XFIXNUM (val));
+ else if (SYMBOLP (val)
+ && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
+ FcPatternAddInteger (pat, FC_LCD_FILTER, ival);
+ }
+#ifdef FC_EMBOLDEN
+ else if (EQ (key, QCembolden))
+ FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue);
+#endif
+ }
+}
+
+FcPattern *
+ftfont_entity_pattern (Lisp_Object entity, int pixel_size)
+{
+ Lisp_Object val, filename, idx;
+ FcPattern *pat;
+ int i;
+
+ val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
+ eassert (CONSP (val));
+ val = XCDR (val);
+ filename = XCAR (val);
+ idx = XCDR (val);
+ pat = FcPatternCreate ();
+ FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity));
+ i = FONT_SLANT_NUMERIC (entity) - 100;
+ if (i < 0) i = 0;
+ FcPatternAddInteger (pat, FC_SLANT, i);
+ FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity));
+ FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
+ val = AREF (entity, FONT_FAMILY_INDEX);
+ if (! NILP (val))
+ FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
+ val = AREF (entity, FONT_FOUNDRY_INDEX);
+ if (! NILP (val))
+ FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
+ val = AREF (entity, FONT_SPACING_INDEX);
+ if (! NILP (val))
+ FcPatternAddInteger (pat, FC_SPACING, XFIXNUM (val));
+ val = AREF (entity, FONT_DPI_INDEX);
+ if (! NILP (val))
+ {
+ double dbl = XFIXNUM (val);
+
+ FcPatternAddDouble (pat, FC_DPI, dbl);
+ }
+ val = AREF (entity, FONT_AVGWIDTH_INDEX);
+ if (FIXNUMP (val) && XFIXNUM (val) == 0)
+ FcPatternAddBool (pat, FC_SCALABLE, FcTrue);
+ /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz
+ over 10x20-ISO8859-1.pcf.gz). */
+ FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity));
+
+ ftfont_add_rendering_parameters (pat, entity);
+
+ FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
+ FcPatternAddInteger (pat, FC_INDEX, XFIXNUM (idx));
+
+ return pat;
+}
+
+#ifndef USE_CAIRO
Lisp_Object
-ftfont_open2 (struct frame *f,
- Lisp_Object entity,
- int pixel_size,
- Lisp_Object font_object)
+ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
{
- struct ftfont_info *ftfont_info;
+ struct font_info *ftfont_info;
struct font *font;
struct ftfont_cache_data *cache_data;
FT_Face ft_face;
FT_Size ft_size;
FT_UInt size;
- Lisp_Object val, filename, idx, cache;
+ Lisp_Object val, filename, idx, cache, font_object;
bool scalable;
int spacing;
int i;
@@ -1110,10 +1349,9 @@ ftfont_open2 (struct frame *f,
return Qnil;
filename = XCAR (val);
idx = XCDR (val);
- val = XCDR (cache);
- cache_data = XSAVE_POINTER (XCDR (cache), 0);
+ cache_data = xmint_pointer (XCDR (cache));
ft_face = cache_data->ft_face;
- if (XSAVE_INTEGER (val, 1) > 0)
+ if (cache_data->face_refcount > 0)
{
/* FT_Face in this cache is already used by the different size. */
if (FT_New_Size (ft_face, &ft_size) != 0)
@@ -1124,49 +1362,80 @@ ftfont_open2 (struct frame *f,
return Qnil;
}
}
- set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1);
- size = XINT (AREF (entity, FONT_SIZE_INDEX));
+ size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX));
if (size == 0)
size = pixel_size;
if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
{
- if (XSAVE_INTEGER (val, 1) == 0)
- FT_Done_Face (ft_face);
+ if (cache_data->face_refcount == 0)
+ {
+ FT_Done_Face (ft_face);
+ cache_data->ft_face = NULL;
+ }
return Qnil;
}
+ cache_data->face_refcount++;
+ font_object = font_build_object (VECSIZE (struct font_info),
+ Qfreetype, entity, size);
ASET (font_object, FONT_FILE_INDEX, filename);
font = XFONT_OBJECT (font_object);
- ftfont_info = (struct ftfont_info *) font;
+ ftfont_info = (struct font_info *) font;
ftfont_info->ft_size = ft_face->size;
- ftfont_info->index = XINT (idx);
+ ftfont_info->index = XFIXNUM (idx);
#ifdef HAVE_LIBOTF
ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
ftfont_info->otf = NULL;
#endif /* HAVE_LIBOTF */
+#ifdef HAVE_HARFBUZZ
+ ftfont_info->hb_font = NULL;
+#endif /* HAVE_HARFBUZZ */
/* This means that there's no need of transformation. */
ftfont_info->matrix.xx = 0;
font->pixel_size = size;
+#ifdef HAVE_HARFBUZZ
+ if (EQ (AREF (font_object, FONT_TYPE_INDEX), Qfreetypehb))
+ font->driver = &fthbfont_driver;
+ else
+#endif /* HAVE_HARFBUZZ */
font->driver = &ftfont_driver;
font->encoding_charset = font->repertory_charset = -1;
+ val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
+ bool no_leading_p = !(CONSP (val) && NILP (XCDR (val)));
upEM = ft_face->units_per_EM;
- scalable = (INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
- && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
+ scalable = (FIXNUMP (AREF (entity, FONT_AVGWIDTH_INDEX))
+ && XFIXNUM (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0);
if (scalable)
{
font->ascent = ft_face->ascender * size / upEM + 0.5;
- font->descent = - ft_face->descender * size / upEM + 0.5;
- font->height = ft_face->height * size / upEM + 0.5;
+ if (no_leading_p)
+ {
+ font->descent = - ft_face->descender * size / upEM + 0.5;
+ font->height = font->ascent + font->descent;
+ }
+ else
+ {
+ font->height = ft_face->height * size / upEM + 0.5;
+ font->descent = font->height - font->ascent;
+ }
}
else
{
font->ascent = ft_face->size->metrics.ascender >> 6;
- font->descent = - ft_face->size->metrics.descender >> 6;
- font->height = ft_face->size->metrics.height >> 6;
+ if (no_leading_p)
+ {
+ font->descent = - ft_face->size->metrics.descender >> 6;
+ font->height = font->ascent + font->descent;
+ }
+ else
+ {
+ font->height = ft_face->size->metrics.height >> 6;
+ font->descent = font->height - font->ascent;
+ }
}
- if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
- spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
+ if (FIXNUMP (AREF (entity, FONT_SPACING_INDEX)))
+ spacing = XFIXNUM (AREF (entity, FONT_SPACING_INDEX));
else
spacing = FC_PROPORTIONAL;
if (spacing != FC_PROPORTIONAL
@@ -1219,49 +1488,40 @@ ftfont_open2 (struct frame *f,
return font_object;
}
-Lisp_Object
-ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
-{
- Lisp_Object font_object;
- FT_UInt size;
- size = XINT (AREF (entity, FONT_SIZE_INDEX));
- if (size == 0)
- size = pixel_size;
- font_object = font_build_object (VECSIZE (struct ftfont_info),
- Qfreetype, entity, size);
- return ftfont_open2 (f, entity, pixel_size, font_object);
-}
-
void
ftfont_close (struct font *font)
{
- /* FIXME: Although this function can be called while garbage-collecting,
- the function assumes that Lisp data structures are properly-formed.
- This invalid assumption can lead to core dumps (Bug#20890). */
+ if (font_data_structures_may_be_ill_formed ())
+ return;
- struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
+ struct font_info *ftfont_info = (struct font_info *) font;
Lisp_Object val, cache;
- val = Fcons (font->props[FONT_FILE_INDEX], make_number (ftfont_info->index));
+ val = Fcons (font->props[FONT_FILE_INDEX], make_fixnum (ftfont_info->index));
cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE);
eassert (CONSP (cache));
val = XCDR (cache);
- set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1);
- if (XSAVE_INTEGER (val, 1) == 0)
+ struct ftfont_cache_data *cache_data = xmint_pointer (val);
+ cache_data->face_refcount--;
+ if (cache_data->face_refcount == 0)
{
- struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0);
-
FT_Done_Face (cache_data->ft_face);
#ifdef HAVE_LIBOTF
if (ftfont_info->otf)
OTF_close (ftfont_info->otf);
#endif
+#ifdef HAVE_HARFBUZZ
+ if (ftfont_info->hb_font)
+ hb_font_destroy (ftfont_info->hb_font);
+#endif
cache_data->ft_face = NULL;
}
else
FT_Done_Size (ftfont_info->ft_size);
}
+#endif /* !USE_CAIRO */
+
int
ftfont_has_char (Lisp_Object font, int c)
{
@@ -1284,18 +1544,20 @@ ftfont_has_char (Lisp_Object font, int c)
}
else
{
- struct ftfont_info *ftfont_info;
+ struct font_info *ftfont_info;
- ftfont_info = (struct ftfont_info *) XFONT_OBJECT (font);
+ ftfont_info = (struct font_info *) XFONT_OBJECT (font);
return (FT_Get_Char_Index (ftfont_info->ft_size->face, (FT_ULong) c)
!= 0);
}
}
+#ifndef USE_CAIRO
+
unsigned
ftfont_encode_char (struct font *font, int c)
{
- struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
+ struct font_info *ftfont_info = (struct font_info *) font;
FT_Face ft_face = ftfont_info->ft_size->face;
FT_ULong charcode = c;
FT_UInt code = FT_Get_Char_Index (ft_face, charcode);
@@ -1303,11 +1565,29 @@ ftfont_encode_char (struct font *font, int c)
return (code > 0 ? code : FONT_INVALID_CODE);
}
+static bool
+ftfont_glyph_metrics (FT_Face ft_face, int c, int *advance, int *lbearing,
+ int *rbearing, int *ascent, int *descent)
+{
+ if (FT_Load_Glyph (ft_face, c, FT_LOAD_DEFAULT) == 0)
+ {
+ FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
+ *advance = m->horiAdvance >> 6;
+ *lbearing = m->horiBearingX >> 6;
+ *rbearing = (m->horiBearingX + m->width) >> 6;
+ *ascent = m->horiBearingY >> 6;
+ *descent = (m->height - m->horiBearingY) >> 6;
+ return true;
+ }
+
+ return false;
+}
+
void
-ftfont_text_extents (struct font *font, unsigned int *code,
+ftfont_text_extents (struct font *font, const unsigned int *code,
int nglyphs, struct font_metrics *metrics)
{
- struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
+ struct font_info *ftfont_info = (struct font_info *) font;
FT_Face ft_face = ftfont_info->ft_size->face;
int i, width = 0;
bool first;
@@ -1317,29 +1597,27 @@ ftfont_text_extents (struct font *font, unsigned int *code,
for (i = 0, first = 1; i < nglyphs; i++)
{
- if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
+ int advance, lbearing, rbearing, ascent, descent;
+ if (ftfont_glyph_metrics (ft_face, code[i], &advance, &lbearing,
+ &rbearing, &ascent, &descent))
{
- FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
-
if (first)
{
- metrics->lbearing = m->horiBearingX >> 6;
- metrics->rbearing = (m->horiBearingX + m->width) >> 6;
- metrics->ascent = m->horiBearingY >> 6;
- metrics->descent = (m->height - m->horiBearingY) >> 6;
+ metrics->lbearing = lbearing;
+ metrics->rbearing = rbearing;
+ metrics->ascent = ascent;
+ metrics->descent = descent;
first = 0;
}
- if (metrics->lbearing > width + (m->horiBearingX >> 6))
- metrics->lbearing = width + (m->horiBearingX >> 6);
- if (metrics->rbearing
- < width + ((m->horiBearingX + m->width) >> 6))
- metrics->rbearing
- = width + ((m->horiBearingX + m->width) >> 6);
- if (metrics->ascent < (m->horiBearingY >> 6))
- metrics->ascent = m->horiBearingY >> 6;
- if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
- metrics->descent = (m->height - m->horiBearingY) >> 6;
- width += m->horiAdvance >> 6;
+ if (metrics->lbearing > width + lbearing)
+ metrics->lbearing = width + lbearing;
+ if (metrics->rbearing < width + rbearing)
+ metrics->rbearing = width + rbearing;
+ if (metrics->ascent < ascent)
+ metrics->ascent = ascent;
+ if (metrics->descent > descent)
+ metrics->descent = descent;
+ width += advance;
}
else
width += font->space_width;
@@ -1347,10 +1625,12 @@ ftfont_text_extents (struct font *font, unsigned int *code,
metrics->width = width;
}
+#endif /* !USE_CAIRO */
+
int
ftfont_get_bitmap (struct font *font, unsigned int code, struct font_bitmap *bitmap, int bits_per_pixel)
{
- struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
+ struct font_info *ftfont_info = (struct font_info *) font;
FT_Face ft_face = ftfont_info->ft_size->face;
FT_Int32 load_flags = FT_LOAD_RENDER;
@@ -1394,7 +1674,7 @@ int
ftfont_anchor_point (struct font *font, unsigned int code, int idx,
int *x, int *y)
{
- struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
+ struct font_info *ftfont_info = (struct font_info *) font;
FT_Face ft_face = ftfont_info->ft_size->face;
if (ftfont_info->ft_size != ft_face->size)
@@ -1459,7 +1739,7 @@ ftfont_otf_features (OTF_GSUB_GPOS *gsub_gpos)
Lisp_Object
ftfont_otf_capability (struct font *font)
{
- struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
+ struct font_info *ftfont_info = (struct font_info *) font;
OTF *otf = ftfont_get_otf (ftfont_info);
Lisp_Object gsub_gpos;
@@ -2527,7 +2807,7 @@ ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
flt = mflt_find (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 0)),
&flt_font_ft.flt_font);
if (! flt)
- return make_number (0);
+ return make_fixnum (0);
}
MFLTGlyphFT *glyphs = (MFLTGlyphFT *) gstring.glyphs;
@@ -2565,10 +2845,31 @@ ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
return Qnil;
+
+ /* mflt_run may fail to set g->g.to (which must be a valid index
+ into lgstring) correctly if the font has an OTF table that is
+ different from what the m17n library expects. */
for (i = 0; i < gstring.used; i++)
{
MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
+ if (g->g.to >= len)
+ {
+ /* Invalid g->g.to. */
+ g->g.to = len - 1;
+ int from = g->g.from;
+ /* Fix remaining glyphs. */
+ for (++i; i < gstring.used; i++)
+ {
+ g = (MFLTGlyphFT *) (gstring.glyphs) + i;
+ g->g.from = from;
+ g->g.to = len - 1;
+ }
+ }
+ }
+ for (i = 0; i < gstring.used; i++)
+ {
+ MFLTGlyphFT *g = (MFLTGlyphFT *) (gstring.glyphs) + i;
g->g.from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->g.from));
g->g.to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->g.to));
}
@@ -2593,23 +2894,19 @@ ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
LGLYPH_SET_ASCENT (lglyph, g->g.ascent >> 6);
LGLYPH_SET_DESCENT (lglyph, g->g.descent >> 6);
if (g->g.adjusted)
- {
- Lisp_Object vec = make_uninit_vector (3);
-
- ASET (vec, 0, make_number (g->g.xoff >> 6));
- ASET (vec, 1, make_number (g->g.yoff >> 6));
- ASET (vec, 2, make_number (g->g.xadv >> 6));
- LGLYPH_SET_ADJUSTMENT (lglyph, vec);
- }
+ LGLYPH_SET_ADJUSTMENT (lglyph, CALLN (Fvector,
+ make_fixnum (g->g.xoff >> 6),
+ make_fixnum (g->g.yoff >> 6),
+ make_fixnum (g->g.xadv >> 6)));
}
- return make_number (i);
+ return make_fixnum (i);
}
Lisp_Object
-ftfont_shape (Lisp_Object lgstring)
+ftfont_shape (Lisp_Object lgstring, Lisp_Object direction)
{
struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
- struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
+ struct font_info *ftfont_info = (struct font_info *) font;
OTF *otf = ftfont_get_otf (ftfont_info);
return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf,
@@ -2618,21 +2915,142 @@ ftfont_shape (Lisp_Object lgstring)
#endif /* HAVE_M17N_FLT */
-#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
+#endif /* HAVE_LIBOTF */
+#if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX
int
ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
{
- struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
+ struct font_info *ftfont_info = (struct font_info *) font;
+#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
OTF *otf = ftfont_get_otf (ftfont_info);
if (! otf)
return 0;
return OTF_get_variation_glyphs (otf, c, variations);
+#else /* !HAVE_OTF_GET_VARIATION_GLYPHS */
+ FT_Face ft_face = ftfont_info->ft_size->face;
+ int i, n = 0;
+
+ for (i = 0; i < 16; i++)
+ {
+ variations[i] = FT_Face_GetCharVariantIndex (ft_face, c, 0xFE00 + i);
+ if (variations[i])
+ n++;
+ }
+ for (; i < 256; i++)
+ {
+ variations[i] = FT_Face_GetCharVariantIndex (ft_face, c,
+ 0xE0100 + (i - 16));
+ if (variations[i])
+ n++;
+ }
+
+ return n;
+#endif /* !HAVE_OTF_GET_VARIATION_GLYPHS */
}
+#endif /* HAVE_OTF_GET_VARIATION_GLYPHS || HAVE_FT_FACE_GETCHARVARIANTINDEX */
-#endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
-#endif /* HAVE_LIBOTF */
+#ifdef HAVE_HARFBUZZ
+
+hb_font_t *
+fthbfont_begin_hb_font (struct font *font, double *position_unit)
+{
+ struct font_info *ftfont_info = (struct font_info *) font;
+
+ *position_unit = 1.0 / (1 << 6);
+ if (! ftfont_info->hb_font)
+ ftfont_info->hb_font
+ = hb_ft_font_create_referenced (ftfont_info->ft_size->face);
+ return ftfont_info->hb_font;
+}
+
+#ifndef HAVE_LIBOTF
+#include <hb-ot.h>
+
+static OTF *
+hbotf_open (const char *name)
+{
+ FT_Face ft_face;
+
+ if (! ft_library
+ && FT_Init_FreeType (&ft_library) != 0)
+ return NULL;
+ if (FT_New_Face (ft_library, name, 0, &ft_face)
+ != 0)
+ return NULL;
+
+ hb_face_t *face = hb_ft_face_create_referenced (ft_face);
+ FT_Done_Face (ft_face);
+
+ return face;
+}
+
+static int
+hbotf_check_features (OTF *otf, int gsubp,
+ OTF_tag script, OTF_tag language,
+ const OTF_tag *features, int n_features)
+{
+ hb_face_t *face = otf;
+ hb_tag_t table_tag = gsubp ? HB_OT_TAG_GSUB : HB_OT_TAG_GPOS;
+ hb_tag_t script_tag = script, language_tag = language;
+
+ unsigned int script_count
+ = hb_ot_layout_table_get_script_tags (face, table_tag, 0, NULL, NULL);
+ hb_tag_t *script_tags = xnmalloc (script_count, sizeof *script_tags);
+ hb_ot_layout_table_get_script_tags (face, table_tag, 0, &script_count,
+ script_tags);
+ unsigned int script_index;
+ for (script_index = 0; script_index < script_count; script_index++)
+ if (script_tags[script_index] == script_tag)
+ break;
+ xfree (script_tags);
+ if (script_index == script_count)
+ return 0;
+
+ unsigned int language_index;
+ if (language_tag == 0)
+ language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
+ else
+ {
+ unsigned int language_count
+ = hb_ot_layout_script_get_language_tags (face, table_tag, script_index,
+ 0, NULL, NULL);
+ hb_tag_t *language_tags = xnmalloc (language_count,
+ sizeof *language_tags);
+ hb_ot_layout_script_get_language_tags (face, table_tag, script_index, 0,
+ &language_count, language_tags);
+ for (language_index = 0; language_index < script_count; language_index++)
+ if (language_tags[language_index] == language_tag)
+ break;
+ xfree (language_tags);
+ if (language_index == language_count)
+ return 0;
+ }
+
+ for (int j = 0; j < n_features; j++)
+ {
+ hb_tag_t feature_tag = features[j];
+ hb_bool_t negate = 0;
+
+ if (feature_tag == 0)
+ continue;
+ if (feature_tag & 0x80000000)
+ {
+ feature_tag &= 0x7FFFFFFF;
+ negate = 1;
+ }
+
+ unsigned int feature_index;
+ if (hb_ot_layout_language_find_feature (face, table_tag, script_index,
+ language_index, feature_tag,
+ &feature_index) == negate)
+ return 0;
+ }
+ return 1;
+}
+#endif /* !HAVE_LIBOTF */
+#endif /* HAVE_HARFBUZZ */
static const char *const ftfont_booleans [] = {
":antialias",
@@ -2695,6 +3113,10 @@ ftfont_combining_capability (struct font *font)
#endif
}
+static void syms_of_ftfont_for_pdumper (void);
+
+#ifndef USE_CAIRO
+
static struct font_driver const ftfont_driver =
{
/* We can't draw a text without device dependent functions. */
@@ -2703,8 +3125,8 @@ static struct font_driver const ftfont_driver =
.list = ftfont_list,
.match = ftfont_match,
.list_family = ftfont_list_family,
- .open = ftfont_open,
- .close = ftfont_close,
+ .open_font = ftfont_open,
+ .close_font = ftfont_close,
.has_char = ftfont_has_char,
.encode_char = ftfont_encode_char,
.text_extents = ftfont_text_extents,
@@ -2716,18 +3138,28 @@ static struct font_driver const ftfont_driver =
#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
.shape = ftfont_shape,
#endif
-#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
+#if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX
.get_variation_glyphs = ftfont_variation_glyphs,
#endif
.filter_properties = ftfont_filter_properties,
.combining_capability = ftfont_combining_capability,
};
+#endif /* !USE_CAIRO */
+
void
syms_of_ftfont (void)
{
/* Symbolic type of this font-driver. */
DEFSYM (Qfreetype, "freetype");
+#ifdef HAVE_HARFBUZZ
+ DEFSYM (Qfreetypehb, "freetypehb");
+ Fput (Qfreetype, Qfont_driver_superseded_by, Qfreetypehb);
+#endif /* HAVE_HARFBUZZ */
+
+#ifdef HAVE_HAIKU
+ DEFSYM (Qmono, "mono");
+#endif
/* Fontconfig's generic families and their aliases. */
DEFSYM (Qmonospace, "monospace");
@@ -2735,6 +3167,17 @@ syms_of_ftfont (void)
DEFSYM (Qsans, "sans");
DEFSYM (Qsans__serif, "sans serif");
+ /* The boolean-valued font property key specifying the use of leading. */
+ DEFSYM (QCminspace, ":minspace");
+
+ /* Fontconfig's rendering parameters. */
+ DEFSYM (QChinting, ":hinting");
+ DEFSYM (QCautohint, ":autohint");
+ DEFSYM (QChintstyle, ":hintstyle");
+ DEFSYM (QCrgba, ":rgba");
+ DEFSYM (QCembolden, ":embolden");
+ DEFSYM (QClcdfilter, ":lcdfilter");
+
staticpro (&freetype_font_cache);
freetype_font_cache = list1 (Qt);
@@ -2746,5 +3189,21 @@ syms_of_ftfont (void)
staticpro (&ft_face_cache);
ft_face_cache = Qnil;
+ pdumper_do_now_and_after_load (syms_of_ftfont_for_pdumper);
+}
+
+static void
+syms_of_ftfont_for_pdumper (void)
+{
+ PDUMPER_RESET_LV (ft_face_cache, Qnil);
register_font_driver (&ftfont_driver, NULL);
+#ifdef HAVE_HARFBUZZ
+ fthbfont_driver = ftfont_driver;
+ fthbfont_driver.type = Qfreetypehb;
+ fthbfont_driver.otf_capability = hbfont_otf_capability;
+ fthbfont_driver.shape = hbfont_shape;
+ fthbfont_driver.combining_capability = hbfont_combining_capability;
+ fthbfont_driver.begin_hb_font = fthbfont_begin_hb_font;
+ register_font_driver (&fthbfont_driver, NULL);
+#endif /* HAVE_HARFBUZZ */
}