Skip to content

Commit

Permalink
select fonts via postscript name on Linux
Browse files Browse the repository at this point in the history
greatly improves font matching accuracy

Fixes Automattic#1572
  • Loading branch information
chearon committed Feb 9, 2022
1 parent 27a70ec commit 4d691da
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/prebuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
name: ${{ matrix.canvas_tag}}, Node.js ${{ matrix.node }}, Linux
runs-on: ubuntu-latest
container:
image: chearon/canvas-prebuilt:7
image: chearon/canvas-prebuilt:9
env:
CANVAS_VERSION_TO_BUILD: ${{ matrix.canvas_tag }}
steps:
Expand Down
62 changes: 60 additions & 2 deletions src/register_font.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <windows.h>
#else
#include <fontconfig/fontconfig.h>
#include <pango/pangofc-fontmap.h>
#endif

#include <ft2build.h>
Expand All @@ -32,11 +33,29 @@
#define PREFERRED_ENCODING_ID TT_MS_ID_UNICODE_CS
#endif

// With PangoFcFontMaps (the pango font module on Linux) we're able to add a
// hook that lets us get perfect matching. Tie the conditions for enabling that
// feature to one variable
#if !defined(__APPLE) && !defined(_WIN32) && PANGO_VERSION_CHECK(1, 47, 0)
#define PERFECT_MATCHES_ENABLED
#endif

#define IS_PREFERRED_ENC(X) \
X.platform_id == PREFERRED_PLATFORM_ID && X.encoding_id == PREFERRED_ENCODING_ID

#ifdef PERFECT_MATCHES_ENABLED
// 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)
#else
#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)
#endif

/*
* Return a UTF-8 encoded string given a TrueType name buf+len
Expand Down Expand Up @@ -104,7 +123,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 ||
#ifdef PERFECT_MATCHES_ENABLED
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) {
Expand All @@ -113,6 +138,18 @@ get_family_name(FT_Face face) {
best_rank = rank;
if (best_buf) free(best_buf);
best_buf = buf;

#ifdef PERFECT_MATCHES_ENABLED
// 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);
}
Expand Down Expand Up @@ -209,6 +246,21 @@ get_pango_font_description(unsigned char* filepath) {
return NULL;
}

#ifdef PERFECT_MATCHES_ENABLED
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
*/
Expand All @@ -233,6 +285,12 @@ register_font(unsigned char *filepath) {
// font families.
pango_cairo_font_map_set_default(NULL);

#ifdef PERFECT_MATCHES_ENABLED
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;
}

Expand Down

0 comments on commit 4d691da

Please sign in to comment.