From 10389c5017f062cd53a3242634a86c54f3ef5f5f Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sun, 10 Dec 2023 22:13:22 +0100 Subject: [PATCH] Add the font Linux Libertine as a possible substitution for Times New Roman and try to load the font family (guessed from the font name) before trying the local substitution. The local(...) command expects to have a real font name and not a predefined substitution it's why we try the font family. --- src/core/font_substitutions.js | 50 ++++++++++++++++++++++++++-- test/unit/font_substitutions_spec.js | 32 +++++++++++------- 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/src/core/font_substitutions.js b/src/core/font_substitutions.js index c22976ba20f20..ec973b84919ff 100644 --- a/src/core/font_substitutions.js +++ b/src/core/font_substitutions.js @@ -48,6 +48,8 @@ const substitutionMap = new Map([ "Thorndale", "TeX Gyre Termes", "FreeSerif", + "Linux Libertine O", + "Libertinus Serif", "DejaVu Serif", "Bitstream Vera Serif", "Ubuntu", @@ -148,6 +150,8 @@ const substitutionMap = new Map([ "Cumberland", "TeX Gyre Cursor", "FreeMono", + "Linux Libertine Mono O", + "Libertinus Mono", ], style: NORMAL, ultimate: "monospace", @@ -323,6 +327,48 @@ function getStyleToAppend(style) { return ""; } +function getFamilyName(str) { + // See https://gitlab.freedesktop.org/fontconfig/fontconfig/-/blob/14d466b30a8ab4a9d789977ed94f2c30e7209267/src/fcname.c#L137. + const keywords = new Set([ + "thin", + "extralight", + "ultralight", + "demilight", + "semilight", + "light", + "book", + "regular", + "normal", + "medium", + "demibold", + "semibold", + "bold", + "extrabold", + "ultrabold", + "black", + "heavy", + "extrablack", + "ultrablack", + "roman", + "italic", + "oblique", + "ultracondensed", + "extracondensed", + "condensed", + "semicondensed", + "normal", + "semiexpanded", + "expanded", + "extraexpanded", + "ultraexpanded", + "bolditalic", + ]); + return str + .split(/[- ,+]+/g) + .filter(tok => !keywords.has(tok.toLowerCase())) + .join(" "); +} + /** * Generate font description. * @param {Object} param0, font substitution description. @@ -470,7 +516,7 @@ function getFontSubstitution( (italic && ITALIC) || NORMAL; substitutionInfo = { - css: loadedName, + css: `"${getFamilyName(baseFontName)}",${loadedName}`, guessFallback: true, loadedName, baseFontName, @@ -492,7 +538,7 @@ function getFontSubstitution( const fallback = guessFallback ? "" : `,${ultimate}`; substitutionInfo = { - css: `${loadedName}${fallback}`, + css: `"${getFamilyName(baseFontName)}",${loadedName}${fallback}`, guessFallback, loadedName, baseFontName, diff --git a/test/unit/font_substitutions_spec.js b/test/unit/font_substitutions_spec.js index 8e5c78e6aa275..8b7edd86d0a9a 100644 --- a/test/unit/font_substitutions_spec.js +++ b/test/unit/font_substitutions_spec.js @@ -40,7 +40,7 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+)$/); + expect(fontSubstitution.css).toMatch(/^"Foo",g_d(\d+)_sf(\d+)$/); }); it("should substitute an unknown bold font", () => { @@ -63,7 +63,7 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+)$/); + expect(fontSubstitution.css).toMatch(/^"Foo",g_d(\d+)_sf(\d+)$/); }); it("should substitute an unknown italic font", () => { @@ -86,7 +86,7 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+)$/); + expect(fontSubstitution.css).toMatch(/^"Foo",g_d(\d+)_sf(\d+)$/); }); it("should substitute an unknown bold italic font", () => { @@ -109,7 +109,7 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+)$/); + expect(fontSubstitution.css).toMatch(/^"Foo",g_d(\d+)_sf(\d+)$/); }); it("should substitute an unknown font but with a standard font", () => { @@ -140,7 +140,7 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+),sans-serif$/); + expect(fontSubstitution.css).toMatch(/^"Foo",g_d(\d+)_sf(\d+),sans-serif$/); }); it("should substitute an unknown font but with a standard italic font", () => { @@ -173,7 +173,7 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+),sans-serif$/); + expect(fontSubstitution.css).toMatch(/^"Foo",g_d(\d+)_sf(\d+),sans-serif$/); }); it("should substitute an unknown font but with a standard bold font", () => { @@ -205,7 +205,7 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+),sans-serif$/); + expect(fontSubstitution.css).toMatch(/^"Foo",g_d(\d+)_sf(\d+),sans-serif$/); }); it("should substitute an unknown font but with a standard bold italic font", () => { @@ -240,7 +240,7 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+),sans-serif$/); + expect(fontSubstitution.css).toMatch(/^"Foo",g_d(\d+)_sf(\d+),sans-serif$/); }); it("should substitute Calibri", () => { @@ -271,7 +271,9 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+),sans-serif$/); + expect(fontSubstitution.css).toMatch( + /^"Calibri",g_d(\d+)_sf(\d+),sans-serif$/ + ); }); it("should substitute Calibri-Bold", () => { @@ -304,7 +306,9 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+),sans-serif$/); + expect(fontSubstitution.css).toMatch( + /^"Calibri",g_d(\d+)_sf(\d+),sans-serif$/ + ); }); it("should substitute Arial Black", () => { @@ -337,7 +341,9 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+),sans-serif$/); + expect(fontSubstitution.css).toMatch( + /^"ArialBlack",g_d(\d+)_sf(\d+),sans-serif$/ + ); }); it("should substitute Arial Black Bold", () => { @@ -370,6 +376,8 @@ describe("getFontSubstitution", function () { }, }) ); - expect(fontSubstitution.css).toMatch(/^g_d(\d+)_sf(\d+),sans-serif$/); + expect(fontSubstitution.css).toMatch( + /^"ArialBlack",g_d(\d+)_sf(\d+),sans-serif$/ + ); }); });