From 53134c0c0bb2d19244dd8c31aa4e8e6d01a657e4 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Thu, 27 Apr 2023 18:01:07 +0200 Subject: [PATCH] [api-minor] Use a local font or fallback on an embedded one (if it exists) for non-embedded fonts (bug 1766039) - Replace FoxitSans with LiberationSans: LiberationSans is already there (for XFA) and we can use it as a good replacement of FoxitSans. - For now we just try to substitue standard fonts, the strategy is the following: * we try to find a font locally from a hardcoded list; * if it fails then we use Liberation as fallback (only for Helvetica for the moment); * else we just fallback on the system serif/sansserif/monospace font. --- external/standard_fonts/FoxitSans.pfb | Bin 15025 -> 0 bytes external/standard_fonts/FoxitSansBold.pfb | Bin 16344 -> 0 bytes .../standard_fonts/FoxitSansBoldItalic.pfb | Bin 16418 -> 0 bytes external/standard_fonts/FoxitSansItalic.pfb | Bin 16339 -> 0 bytes src/core/core_utils.js | 46 +- src/core/evaluator.js | 20 + src/core/font_substitutions.js | 478 ++++++++++++++++++ src/core/fonts.js | 2 + src/core/standard_fonts.js | 8 +- src/display/canvas.js | 3 +- src/display/font_loader.js | 45 +- web/app_options.js | 10 +- 12 files changed, 584 insertions(+), 28 deletions(-) delete mode 100644 external/standard_fonts/FoxitSans.pfb delete mode 100644 external/standard_fonts/FoxitSansBold.pfb delete mode 100644 external/standard_fonts/FoxitSansBoldItalic.pfb delete mode 100644 external/standard_fonts/FoxitSansItalic.pfb create mode 100644 src/core/font_substitutions.js diff --git a/external/standard_fonts/FoxitSans.pfb b/external/standard_fonts/FoxitSans.pfb deleted file mode 100644 index 37f244bd9cf3c60686c11ab9723278040e3675ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15025 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 Zni$D~vCIWrQWpk)bz)RW9#i8~{}=hLJf;8u diff --git a/external/standard_fonts/FoxitSansBoldItalic.pfb b/external/standard_fonts/FoxitSansBoldItalic.pfb deleted file mode 100644 index e1f60b75465d49e186d9109c9082f56d2c66f806..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16418 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: ${fontFamily}.`); + } + return false; + } + } + } + return true; +} + function validateCSSFont(cssFontInfo) { // See https://developer.mozilla.org/en-US/docs/Web/CSS/font-style. const DEFAULT_CSS_FONT_OBLIQUE = "14"; @@ -447,24 +472,8 @@ function validateCSSFont(cssFontInfo) { const { fontFamily, fontWeight, italicAngle } = cssFontInfo; - // See https://developer.mozilla.org/en-US/docs/Web/CSS/string. - const m = /^("|').*("|')$/.exec(fontFamily); - if (m && m[1] === m[2]) { - const re = new RegExp(`[^\\\\]${m[1]}`); - if (re.test(fontFamily.slice(1, -1))) { - warn(`XFA - FontFamily contains unescaped ${m[1]}: ${fontFamily}.`); - return false; - } - } else { - // See https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident. - for (const ident of fontFamily.split(/[ \t]+/)) { - if (/^(\d|(-(\d|-)))/.test(ident) || !/^[\w-\\]+$/.test(ident)) { - warn( - `XFA - FontFamily contains invalid : ${fontFamily}.` - ); - return false; - } - } + if (!validateFontName(fontFamily, true)) { + return false; } const weight = fontWeight ? fontWeight.toString() : ""; @@ -617,6 +626,7 @@ export { stringToUTF16String, toRomanNumerals, validateCSSFont, + validateFontName, XRefEntryException, XRefParseException, }; diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 313259320..c2c7f1e0d 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -68,6 +68,7 @@ import { bidi } from "./bidi.js"; import { ColorSpace } from "./colorspace.js"; import { DecodeStream } from "./decode_stream.js"; import { FontFlags } from "./fonts_utils.js"; +import { getFontSubstitution } from "./font_substitutions.js"; import { getGlyphsUnicode } from "./glyphlist.js"; import { getLookupTableFactory } from "./core_utils.js"; import { getMetrics } from "./metrics.js"; @@ -4174,6 +4175,7 @@ class PartialEvaluator { type, name: baseFontName, loadedName: baseDict.loadedName, + systemFontInfo: null, widths: metrics.widths, defaultWidth: metrics.defaultWidth, isSimulatedFlags: true, @@ -4193,6 +4195,14 @@ class PartialEvaluator { if (standardFontName) { file = await this.fetchStandardFontData(standardFontName); properties.isInternalFont = !!file; + if (!properties.isInternalFont && this.options.useSystemFonts) { + properties.systemFontInfo = getFontSubstitution( + this.idFactory, + this.options.standardFontDataUrl, + baseFontName, + standardFontName + ); + } } return this.extractDataStructures(dict, dict, properties).then( newProperties => { @@ -4264,6 +4274,7 @@ class PartialEvaluator { } let isInternalFont = false; let glyphScaleFactors = null; + let systemFontInfo = null; if (fontFile) { if (fontFile.dict) { const subtypeEntry = fontFile.dict.get("Subtype"); @@ -4296,6 +4307,14 @@ class PartialEvaluator { if (standardFontName) { fontFile = await this.fetchStandardFontData(standardFontName); isInternalFont = !!fontFile; + if (!isInternalFont && this.options.useSystemFonts) { + systemFontInfo = getFontSubstitution( + this.idFactory, + this.options.standardFontDataUrl, + fontName.name, + standardFontName + ); + } } } @@ -4325,6 +4344,7 @@ class PartialEvaluator { isType3Font, cssFontInfo, scaleFactors: glyphScaleFactors, + systemFontInfo, }; if (composite) { diff --git a/src/core/font_substitutions.js b/src/core/font_substitutions.js new file mode 100644 index 000000000..584bef6d3 --- /dev/null +++ b/src/core/font_substitutions.js @@ -0,0 +1,478 @@ +/* Copyright 2023 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { normalizeFontName } from "./fonts_utils.js"; +import { validateFontName } from "./core_utils.js"; + +const NORMAL = { + style: "normal", + weight: "normal", +}; +const BOLD = { + style: "normal", + weight: "bold", +}; +const ITALIC = { + style: "italic", + weight: "normal", +}; +const BOLDITALIC = { + style: "italic", + weight: "bold", +}; + +const substitutionMap = new Map([ + [ + "Times-Roman", + { + local: [ + "Times New Roman", + "Times-Roman", + "Times", + "Liberation Serif", + "Nimbus Roman", + "Nimbus Roman L", + "Tinos", + "Thorndale", + "TeX Gyre Termes", + "FreeSerif", + "DejaVu Serif", + "Bitstream Vera Serif", + "Ubuntu", + ], + style: NORMAL, + ultimate: "serif", + }, + ], + [ + "Times-Bold", + { + local: { + alias: "Times-Roman", + append: "Bold", + }, + style: BOLD, + ultimate: "serif", + }, + ], + [ + "Times-Italic", + { + local: { + alias: "Times-Roman", + append: "Italic", + }, + style: ITALIC, + ultimate: "serif", + }, + ], + [ + "Times-BoldItalic", + { + local: { + alias: "Times-Roman", + append: "Bold Italic", + }, + style: BOLDITALIC, + ultimate: "serif", + }, + ], + [ + "Helvetica", + { + local: [ + "Helvetica", + "Helvetica Neue", + "Arial", + "Arial Nova", + "Liberation Sans", + "Arimo", + "Nimbus Sans", + "Nimbus Sans L", + "A030", + "TeX Gyre Heros", + "FreeSans", + "DejaVu Sans", + "Albany", + "Bitstream Vera Sans", + "Arial Unicode MS", + "Microsoft Sans Serif", + "Apple Symbols", + "Cantarell", + ], + path: "LiberationSans-Regular.ttf", + style: NORMAL, + ultimate: "sans-serif", + }, + ], + [ + "Helvetica-Bold", + { + local: { + alias: "Helvetica", + append: "Bold", + }, + path: "LiberationSans-Bold.ttf", + style: BOLD, + ultimate: "sans-serif", + }, + ], + [ + "Helvetica-Oblique", + { + local: { + alias: "Helvetica", + append: "Italic", + }, + path: "LiberationSans-Italic.ttf", + style: ITALIC, + ultimate: "sans-serif", + }, + ], + [ + "Helvetica-BoldOblique", + { + local: { + alias: "Helvetica", + append: "Bold Italic", + }, + path: "LiberationSans-BoldItalic.ttf", + style: BOLDITALIC, + ultimate: "sans-serif", + }, + ], + [ + "Courier", + { + local: [ + "Courier", + "Courier New", + "Liberation Mono", + "Nimbus Mono", + "Nimbus Mono L", + "Cousine", + "Cumberland", + "TeX Gyre Cursor", + "FreeMono", + ], + style: NORMAL, + ultimate: "monospace", + }, + ], + [ + "Courier-Bold", + { + local: { + alias: "Courier", + append: "Bold", + }, + style: BOLD, + ultimate: "monospace", + }, + ], + [ + "Courier-Oblique", + { + local: { + alias: "Courier", + append: "Italic", + }, + style: ITALIC, + ultimate: "monospace", + }, + ], + [ + "Courier-BoldOblique", + { + local: { + alias: "Courier", + append: "Bold Italic", + }, + style: BOLDITALIC, + ultimate: "monospace", + }, + ], + [ + "ArialBlack", + { + prepend: ["Arial Black"], + style: { + style: "normal", + weight: "900", + }, + fallback: "Helvetica-Bold", + }, + ], + [ + "ArialBlack-Bold", + { + alias: "ArialBlack", + }, + ], + [ + "ArialBlack-Italic", + { + prepend: ["Arial Black Italic"], + local: { + alias: "ArialBlack", + append: "Italic", + }, + style: { + style: "italic", + weight: "900", + }, + fallback: "Helvetica-BoldOblique", + }, + ], + [ + "ArialBlack-BoldItalic", + { + alias: "ArialBlack-Italic", + }, + ], + [ + "ArialNarrow", + { + prepend: [ + "Arial Narrow", + "Liberation Sans Narrow", + "Helvetica Condensed", + "Nimbus Sans Narrow", + "TeX Gyre Heros Cn", + ], + style: NORMAL, + fallback: "Helvetica", + }, + ], + [ + "ArialNarrow-Bold", + { + local: { + alias: "ArialNarrow", + append: "Bold", + }, + style: BOLD, + fallback: "Helvetica-Bold", + }, + ], + [ + "ArialNarrow-Italic", + { + local: { + alias: "ArialNarrow", + append: "Italic", + }, + style: ITALIC, + fallback: "Helvetica-Oblique", + }, + ], + [ + "ArialNarrow-BoldItalic", + { + local: { + alias: "ArialNarrow", + append: "Bold Italic", + }, + style: BOLDITALIC, + fallback: "Helvetica-BoldOblique", + }, + ], + [ + "Calibri", + { + prepend: ["Calibri", "Carlito"], + style: NORMAL, + fallback: "Helvetica", + }, + ], + [ + "Calibri-Bold", + { + local: { + alias: "Calibri", + append: "Bold", + }, + style: BOLD, + fallback: "Helvetica-Bold", + }, + ], + [ + "Calibri-Italic", + { + local: { + alias: "Calibri", + append: "Italic", + }, + style: ITALIC, + fallback: "Helvetica-Oblique", + }, + ], + [ + "Calibri-BoldItalic", + { + local: { + alias: "Calibri", + append: "Bold Italic", + }, + style: BOLDITALIC, + fallback: "Helvetica-BoldOblique", + }, + ], +]); + +const fontAliases = new Map([["Arial-Black", "ArialBlack"]]); + +/** + * Create the src path to use to load a font (see FontFace). + * @param {Array} prepend A list of font names to search first. + * @param {Array|Object} local A list of font names to search. If an + * Object is passed, then local.alias is the name of an other substition font + * and local.append is a String to append to the list of fonts in the alias. + * For example if local.alias is "Foo" and local.append is "Bold" then the + * list of fonts will be "FooSubst1 Bold", "FooSubst2 Bold", etc. + * @returns an String with the local fonts. + */ +function makeLocal(prepend, local) { + let append = ""; + if (!Array.isArray(local)) { + // We are getting our list of fonts in the alias and we'll append Bold, + // Italic or both. + append = ` ${local.append}`; + local = substitutionMap.get(local.alias).local; + } + let prependedPaths = ""; + if (prepend) { + prependedPaths = prepend.map(name => `local(${name})`).join(",") + ","; + } + return ( + prependedPaths + local.map(name => `local(${name}${append})`).join(",") + ); +} + +/** + * Get a font substitution for a given font. + * The general idea is to have enough information to create a CSS rule like + * this: + * @font-face { + * font-family: 'Times'; + * src: local('Times New Roman'), local('Subst1'), local('Subst2'), + * url(.../TimesNewRoman.ttf) + * font-weight: normal; + * font-style: normal; + * } + * or use the FontFace API. + * + * @param {Object} idFactory The ids factory. + * @param {String} localFontPath Path to the fonts directory. + * @param {String} baseFontName The font name to be substituted. + * @param {String} standardFontName The standard font name to use if the base + * font is not available. + * @returns an Object with the CSS, the loaded name, the src and the style. + */ +function getFontSubstitution( + idFactory, + localFontPath, + baseFontName, + standardFontName +) { + let mustAddBaseFont = false; + + // It's possible to have a font name with spaces, commas or dashes, hence we + // just replace them by a dash. + baseFontName = normalizeFontName(baseFontName); + + // First, check if we've a substitution for the base font. + let substitution = substitutionMap.get(baseFontName); + if (!substitution) { + // Check if we've an alias for the base font, Arial-Black is the same as + // ArialBlack + for (const [alias, subst] of fontAliases) { + if (baseFontName.startsWith(alias)) { + baseFontName = `${subst}${baseFontName.substring(alias.length)}`; + substitution = substitutionMap.get(baseFontName); + break; + } + } + } + + if (!substitution) { + // If not, check if we've a substitution for the standard font. + substitution = substitutionMap.get(standardFontName); + mustAddBaseFont = true; + } + + const loadedName = `${idFactory.getDocId()}_sf_${idFactory.createFontId()}`; + if (!substitution) { + if (!validateFontName(baseFontName)) { + // If the baseFontName is not valid we don't want to use it. + return null; + } + // Maybe we'll be lucky and the OS will have the font. + const bold = /bold/gi.test(baseFontName); + const italic = /oblique|italic/gi.test(baseFontName); + const style = + (bold && italic && BOLDITALIC) || + (bold && BOLD) || + (italic && ITALIC) || + NORMAL; + return { + css: `${loadedName},sans-serif`, + loadedName, + src: `local(${baseFontName})`, + style, + }; + } + + while (substitution.alias) { + // If we've an alias, use the substitution for the alias. + // For example, ArialBlack-Bold is an alias for ArialBlack because the bold + // version of Arial Black is not available. + substitution = substitutionMap.get(substitution.alias); + } + + const { fallback, style } = substitution; + + // Prepend the fonts to test before the fallback font. + let prepend = substitution.prepend; + + if (fallback) { + // We've a fallback font: this one is a standard font we want to use in case + // nothing has been found from the prepend list. + prepend ||= substitutionMap.get(substitution.local.alias).prepend; + substitution = substitutionMap.get(fallback); + } + + const { local, path, ultimate } = substitution; + let src = makeLocal(prepend, local); + if (path && localFontPath !== null) { + // PDF.js embeds some fonts we can use. + src += `,url(${localFontPath}${path})`; + } + + // Maybe the OS will have the exact font we want so just prepend it to the + // list. + if (mustAddBaseFont && validateFontName(baseFontName)) { + src = `local(${baseFontName}),${src}`; + } + + return { + css: `${loadedName},${ultimate}`, + loadedName, + src, + style, + }; +} + +export { getFontSubstitution }; diff --git a/src/core/fonts.js b/src/core/fonts.js index 12803fcd2..62502cfa1 100644 --- a/src/core/fonts.js +++ b/src/core/fonts.js @@ -98,6 +98,7 @@ const EXPORT_DATA_PROPERTIES = [ "name", "remeasure", "subtype", + "systemFontInfo", "type", "vertical", ]; @@ -998,6 +999,7 @@ class Font { this.fallbackName = "sans-serif"; } + this.systemFontInfo = properties.systemFontInfo; this.differences = properties.differences; this.widths = properties.widths; this.defaultWidth = properties.defaultWidth; diff --git a/src/core/standard_fonts.js b/src/core/standard_fonts.js index 977d4c0ab..9f025adf3 100644 --- a/src/core/standard_fonts.js +++ b/src/core/standard_fonts.js @@ -100,10 +100,10 @@ const getFontNameToFileMap = getLookupTableFactory(function (t) { t["Courier-Bold"] = "FoxitFixedBold.pfb"; t["Courier-BoldOblique"] = "FoxitFixedBoldItalic.pfb"; t["Courier-Oblique"] = "FoxitFixedItalic.pfb"; - t.Helvetica = "FoxitSans.pfb"; - t["Helvetica-Bold"] = "FoxitSansBold.pfb"; - t["Helvetica-BoldOblique"] = "FoxitSansBoldItalic.pfb"; - t["Helvetica-Oblique"] = "FoxitSansItalic.pfb"; + t.Helvetica = "LiberationSans-Regular.ttf"; + t["Helvetica-Bold"] = "LiberationSans-Bold.ttf"; + t["Helvetica-BoldOblique"] = "LiberationSans-BoldItalic.ttf"; + t["Helvetica-Oblique"] = "LiberationSans-Italic.ttf"; t["Times-Roman"] = "FoxitSerif.pfb"; t["Times-Bold"] = "FoxitSerifBold.pfb"; t["Times-BoldItalic"] = "FoxitSerifBoldItalic.pfb"; diff --git a/src/display/canvas.js b/src/display/canvas.js index 50ce776b0..f3ba13825 100644 --- a/src/display/canvas.js +++ b/src/display/canvas.js @@ -1950,6 +1950,8 @@ class CanvasGraphics { } const name = fontObj.loadedName || "sans-serif"; + const typeface = + fontObj.systemFontInfo?.css || `"${name}", ${fontObj.fallbackName}`; let bold = "normal"; if (fontObj.black) { @@ -1958,7 +1960,6 @@ class CanvasGraphics { bold = "bold"; } const italic = fontObj.italic ? "italic" : "normal"; - const typeface = `"${name}", ${fontObj.fallbackName}`; // Some font backends cannot handle fonts below certain size. // Keeping the font at minimal size and using the fontSizeScale to change diff --git a/src/display/font_loader.js b/src/display/font_loader.js index 307c68838..515c8fc33 100644 --- a/src/display/font_loader.js +++ b/src/display/font_loader.js @@ -19,6 +19,7 @@ import { FeatureTest, shadow, string32, + unreachable, warn, } from "../shared/util.js"; import { isNodeJS } from "../shared/is_node.js"; @@ -30,7 +31,7 @@ class FontLoader { }) { this._document = ownerDocument; - this.nativeFontFaces = []; + this.nativeFontFaces = new Set(); this.styleElement = typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING") ? styleElement @@ -43,10 +44,15 @@ class FontLoader { } addNativeFontFace(nativeFontFace) { - this.nativeFontFaces.push(nativeFontFace); + this.nativeFontFaces.add(nativeFontFace); this._document.fonts.add(nativeFontFace); } + removeNativeFontFace(nativeFontFace) { + this.nativeFontFaces.delete(nativeFontFace); + this._document.fonts.delete(nativeFontFace); + } + insertRule(rule) { if (!this.styleElement) { this.styleElement = this._document.createElement("style"); @@ -62,7 +68,7 @@ class FontLoader { for (const nativeFontFace of this.nativeFontFaces) { this._document.fonts.delete(nativeFontFace); } - this.nativeFontFaces.length = 0; + this.nativeFontFaces.clear(); if (this.styleElement) { // Note: ChildNode.remove doesn't throw if the parentNode is undefined. @@ -71,13 +77,44 @@ class FontLoader { } } + async loadSystemFont(info) { + assert( + !this.disableFontFace, + "loadSystemFont shouldn't be called when `disableFontFace` is set." + ); + + if (this.isFontLoadingAPISupported) { + const { loadedName, src, style } = info; + const fontFace = new FontFace(loadedName, src, style); + this.addNativeFontFace(fontFace); + try { + await fontFace.load(); + } catch { + warn( + `Cannot load system font: ${loadedName} for style ${style.style} and weight ${style.weight}.` + ); + this.removeNativeFontFace(fontFace); + } + return; + } + + unreachable( + "Not implemented: loadSystemFont without the Font Loading API." + ); + } + async bind(font) { // Add the font to the DOM only once; skip if the font is already loaded. - if (font.attached || font.missingFile) { + if (font.attached || (font.missingFile && !font.systemFontInfo)) { return; } font.attached = true; + if (font.systemFontInfo) { + await this.loadSystemFont(font.systemFontInfo); + return; + } + if (this.isFontLoadingAPISupported) { const nativeFontFace = font.createNativeFontFace(); if (nativeFontFace) { diff --git a/web/app_options.js b/web/app_options.js index 7fd75e9ee..f3350f462 100644 --- a/web/app_options.js +++ b/web/app_options.js @@ -210,7 +210,12 @@ const defaultOptions = { cMapUrl: { /** @type {string} */ value: - typeof PDFJSDev === "undefined" ? "../external/bcmaps/" : "../web/cmaps/", + // eslint-disable-next-line no-nested-ternary + typeof PDFJSDev === "undefined" + ? "../external/bcmaps/" + : PDFJSDev.test("MOZCENTRAL") + ? "resource://pdf.js/web/cmaps/" + : "../web/cmaps/", kind: OptionKind.API, }, disableAutoFetch: { @@ -271,8 +276,11 @@ const defaultOptions = { standardFontDataUrl: { /** @type {string} */ value: + // eslint-disable-next-line no-nested-ternary typeof PDFJSDev === "undefined" ? "../external/standard_fonts/" + : PDFJSDev.test("MOZCENTRAL") + ? "resource://pdf.js/web/standard_fonts/" : "../web/standard_fonts/", kind: OptionKind.API, },