From d921b83e7fef1119d0f3224e1a57deedf6fa48c1 Mon Sep 17 00:00:00 2001 From: Caleb Hearon Date: Sat, 7 Aug 2021 15:53:55 +0000 Subject: [PATCH] select fonts via postscript name on Linux greatly improves font matching accuracy Fixes #1572 --- src/register_font.cc | 55 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/register_font.cc b/src/register_font.cc index 6d421daca..f71a3a003 100644 --- a/src/register_font.cc +++ b/src/register_font.cc @@ -11,6 +11,7 @@ #include #else #include +#include #endif #include @@ -36,8 +37,19 @@ #define IS_PREFERRED_ENC(X) \ X.platform_id == PREFERRED_PLATFORM_ID && X.encoding_id == PREFERRED_ENCODING_ID +#if defined(__APPLE) || defined(_WIN32) #define GET_NAME_RANK(X) \ - (IS_PREFERRED_ENC(X) ? 1 : 0) + (X.name_id == TT_NAME_ID_PREFERRED_FAMILY ? 1 : 0) + ((IS_PREFERRED_ENC(X) ? 1 : 0) << 1) | \ + (X.name_id == TT_NAME_ID_PREFERRED_FAMILY ? 1 : 0) +#else +// On Linux-like OSes using FontConfig, the PostScript name ranks higher than +// preferred family and family name since we'll use it to get perfect font +// matching (see fc_font_map_substitute_hook) +#define GET_NAME_RANK(X) \ + ((IS_PREFERRED_ENC(X) ? 1 : 0) << 2) | \ + ((X.name_id == TT_NAME_ID_PS_NAME ? 1 : 0) << 1) | \ + (X.name_id == TT_NAME_ID_PREFERRED_FAMILY ? 1 : 0) +#endif /* * Return a UTF-8 encoded string given a TrueType name buf+len @@ -105,7 +117,13 @@ get_family_name(FT_Face face) { for (unsigned i = 0; i < FT_Get_Sfnt_Name_Count(face); ++i) { FT_Get_Sfnt_Name(face, i, &name); - if (name.name_id == TT_NAME_ID_FONT_FAMILY || name.name_id == TT_NAME_ID_PREFERRED_FAMILY) { + if ( + name.name_id == TT_NAME_ID_FONT_FAMILY || +#if !defined(__APPLE) && !defined(_WIN32) + name.name_id == TT_NAME_ID_PS_NAME || +#endif + name.name_id == TT_NAME_ID_PREFERRED_FAMILY + ) { char *buf = to_utf8(name.string, name.string_len, name.platform_id, name.encoding_id); if (buf) { @@ -114,6 +132,18 @@ get_family_name(FT_Face face) { best_rank = rank; if (best_buf) free(best_buf); best_buf = buf; + +#if !defined(__APPLE) && !defined(_WIN32) + // Prepend an '@' to the family name + if (name.name_id == TT_NAME_ID_PS_NAME) { + size_t len = strlen(buf); + best_buf = (char *)malloc(len + 2); + best_buf[0] = '@'; + strncpy(best_buf + 1, buf, len); + best_buf[len + 1] = '\0'; + free(buf); + } +#endif } else { free(buf); } @@ -210,6 +240,21 @@ get_pango_font_description(unsigned char* filepath) { return NULL; } +#if !defined(__APPLE) && !defined(_WIN32) +static void +fc_font_map_substitute_hook(FcPattern *pat, gpointer data) { + FcChar8 *family; + + for (int i = 0; FcPatternGetString(pat, FC_FAMILY, i, &family) == FcResultMatch; i++) { + if (family[0] == '@') { + FcPatternAddString(pat, FC_POSTSCRIPT_NAME, (FcChar8 *)family + 1); + FcPatternRemove(pat, FC_FAMILY, i); + i -= 1; + } + } +} +#endif + /* * Register font with the OS */ @@ -234,6 +279,12 @@ register_font(unsigned char *filepath) { // font families. pango_cairo_font_map_set_default(NULL); +#if !defined(__APPLE) && !defined(_WIN32) + PangoFontMap* map = pango_cairo_font_map_get_default(); + PangoFcFontMap* fc_map = PANGO_FC_FONT_MAP(map); + pango_fc_font_map_set_default_substitute(fc_map, fc_font_map_substitute_hook, NULL, NULL); +#endif + return true; }