diff --git a/scripts/woff2/assets/LiberationSans-Regular-2048.ttf b/scripts/woff2/assets/LiberationSans-Regular-2048.ttf new file mode 100644 index 0000000000..ff514cddee Binary files /dev/null and b/scripts/woff2/assets/LiberationSans-Regular-2048.ttf differ diff --git a/scripts/woff2/assets/LiberationSans-Regular.ttf b/scripts/woff2/assets/LiberationSans-Regular.ttf new file mode 100644 index 0000000000..006f615ebe Binary files /dev/null and b/scripts/woff2/assets/LiberationSans-Regular.ttf differ diff --git a/scripts/woff2/woff2-esbuild-plugins.js b/scripts/woff2/woff2-esbuild-plugins.js index bcb59ec1d2..e53dd0299e 100644 --- a/scripts/woff2/woff2-esbuild-plugins.js +++ b/scripts/woff2/woff2-esbuild-plugins.js @@ -123,6 +123,17 @@ module.exports.woff2ServerPlugin = (options = {}) => { "./assets/NotoEmoji-Regular-2048.ttf", ); + const liberationPath = path.resolve( + __dirname, + "./assets/LiberationSans-Regular.ttf", + ); + + // need to use the same em size as built-in fonts, otherwise pyftmerge throws (modified manually with font forge) + const liberationPath_2048 = path.resolve( + __dirname, + "./assets/LiberationSans-Regular-2048.ttf", + ); + const xiaolaiFont = Font.create(fs.readFileSync(xiaolaiPath), { type: "ttf", }); @@ -130,6 +141,10 @@ module.exports.woff2ServerPlugin = (options = {}) => { type: "ttf", }); + const liberationFont = Font.create(fs.readFileSync(liberationPath), { + type: "ttf", + }); + const sortedFonts = Array.from(fonts.entries()).sort( ([family1], [family2]) => (family1 > family2 ? 1 : -1), ); @@ -141,13 +156,6 @@ module.exports.woff2ServerPlugin = (options = {}) => { continue; } - const fallbackFontsPaths = []; - const shouldIncludeXiaolaiFallback = family.includes("Excalifont"); - - if (shouldIncludeXiaolaiFallback) { - fallbackFontsPaths.push(xiaolaiPath); - } - const baseFont = Regular[0]; const tempPaths = Regular.map((_, index) => path.resolve(outputDir, `temp_${family}_${index}.ttf`), @@ -165,10 +173,18 @@ module.exports.woff2ServerPlugin = (options = {}) => { const mergedFontPath = path.resolve(outputDir, `${family}.ttf`); + const fallbackFontsPaths = []; + const shouldIncludeXiaolaiFallback = family.includes("Excalifont"); + + if (shouldIncludeXiaolaiFallback) { + fallbackFontsPaths.push(xiaolaiPath); + } + + // add liberation as fallback to all fonts, so that unknown characters are rendered similarly to how browser renders them (Helvetica, Arial, etc.) if (baseFont.data.head.unitsPerEm === 2048) { - fallbackFontsPaths.push(emojiPath_2048); + fallbackFontsPaths.push(emojiPath_2048, liberationPath_2048); } else { - fallbackFontsPaths.push(emojiPath); + fallbackFontsPaths.push(emojiPath, liberationPath); } // drop Vertical related metrics, otherwise it does not allow us to merge the fonts @@ -196,10 +212,12 @@ module.exports.woff2ServerPlugin = (options = {}) => { const base = baseFont.data.name[field]; const xiaolai = xiaolaiFont.data.name[field]; const emoji = emojiFont.data.name[field]; + const liberation = liberationFont.data.name[field]; + // liberation font return shouldIncludeXiaolaiFallback - ? `${base} & ${xiaolai} & ${emoji}` - : `${base} & ${emoji}`; + ? `${base} & ${xiaolai} & ${emoji} & ${liberation}` + : `${base} & ${emoji} & ${liberation}`; }; mergedFont.set({