fallbackToSystemFont()

in src/core/fonts.js [1162:1311]


  fallbackToSystemFont(properties) {
    this.missingFile = true;
    // The file data is not specified. Trying to fix the font name
    // to be used with the canvas.font.
    const { name, type } = this;
    let fontName = normalizeFontName(name);
    const stdFontMap = getStdFontMap(),
      nonStdFontMap = getNonStdFontMap();
    const isStandardFont = !!stdFontMap[fontName];
    const isMappedToStandardFont = !!(
      nonStdFontMap[fontName] && stdFontMap[nonStdFontMap[fontName]]
    );

    fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;

    const fontBasicMetricsMap = getFontBasicMetrics();
    const metrics = fontBasicMetricsMap[fontName];
    if (metrics) {
      if (isNaN(this.ascent)) {
        this.ascent = metrics.ascent / PDF_GLYPH_SPACE_UNITS;
      }
      if (isNaN(this.descent)) {
        this.descent = metrics.descent / PDF_GLYPH_SPACE_UNITS;
      }
      if (isNaN(this.capHeight)) {
        this.capHeight = metrics.capHeight / PDF_GLYPH_SPACE_UNITS;
      }
    }

    this.bold = /bold/gi.test(fontName);
    this.italic = /oblique|italic/gi.test(fontName);

    // Use 'name' instead of 'fontName' here because the original
    // name ArialBlack for example will be replaced by Helvetica.
    this.black = /Black/g.test(name);

    // Use 'name' instead of 'fontName' here because the original
    // name ArialNarrow for example will be replaced by Helvetica.
    const isNarrow = /Narrow/g.test(name);

    // if at least one width is present, remeasure all chars when exists
    this.remeasure =
      (!isStandardFont || isNarrow) && Object.keys(this.widths).length > 0;
    if (
      (isStandardFont || isMappedToStandardFont) &&
      type === "CIDFontType2" &&
      this.cidEncoding.startsWith("Identity-")
    ) {
      const cidToGidMap = properties.cidToGidMap;
      // Standard fonts might be embedded as CID font without glyph mapping.
      // Building one based on GlyphMapForStandardFonts.
      const map = [];
      applyStandardFontGlyphMap(map, getGlyphMapForStandardFonts());

      if (/Arial-?Black/i.test(name)) {
        applyStandardFontGlyphMap(map, getSupplementalGlyphMapForArialBlack());
      } else if (/Calibri/i.test(name)) {
        applyStandardFontGlyphMap(map, getSupplementalGlyphMapForCalibri());
      }

      // Always update the glyph mapping with the `cidToGidMap` when it exists
      // (fixes issue12418_reduced.pdf).
      if (cidToGidMap) {
        for (const charCode in map) {
          const cid = map[charCode];
          if (cidToGidMap[cid] !== undefined) {
            map[+charCode] = cidToGidMap[cid];
          }
        }
        // When the /CIDToGIDMap is "incomplete", fallback to the included
        // /ToUnicode-map regardless of its encoding (fixes issue11915.pdf).
        if (
          cidToGidMap.length !== this.toUnicode.length &&
          properties.hasIncludedToUnicodeMap &&
          this.toUnicode instanceof IdentityToUnicodeMap
        ) {
          this.toUnicode.forEach(function (charCode, unicodeCharCode) {
            const cid = map[charCode];
            if (cidToGidMap[cid] === undefined) {
              map[+charCode] = unicodeCharCode;
            }
          });
        }
      }

      if (!(this.toUnicode instanceof IdentityToUnicodeMap)) {
        this.toUnicode.forEach(function (charCode, unicodeCharCode) {
          map[+charCode] = unicodeCharCode;
        });
      }
      this.toFontChar = map;
      this.toUnicode = new ToUnicodeMap(map);
    } else if (/Symbol/i.test(fontName)) {
      this.toFontChar = buildToFontChar(
        SymbolSetEncoding,
        getGlyphsUnicode(),
        this.differences
      );
    } else if (/Dingbats/i.test(fontName)) {
      this.toFontChar = buildToFontChar(
        ZapfDingbatsEncoding,
        getDingbatsGlyphsUnicode(),
        this.differences
      );
    } else if (isStandardFont || isMappedToStandardFont) {
      const map = buildToFontChar(
        this.defaultEncoding,
        getGlyphsUnicode(),
        this.differences
      );

      if (
        type === "CIDFontType2" &&
        !this.cidEncoding.startsWith("Identity-") &&
        !(this.toUnicode instanceof IdentityToUnicodeMap)
      ) {
        this.toUnicode.forEach(function (charCode, unicodeCharCode) {
          map[+charCode] = unicodeCharCode;
        });
      }
      this.toFontChar = map;
    } else {
      const glyphsUnicodeMap = getGlyphsUnicode();
      const map = [];
      this.toUnicode.forEach((charCode, unicodeCharCode) => {
        if (!this.composite) {
          const glyphName =
            this.differences[charCode] || this.defaultEncoding[charCode];
          const unicode = getUnicodeForGlyph(glyphName, glyphsUnicodeMap);
          if (unicode !== -1) {
            unicodeCharCode = unicode;
          }
        }
        map[+charCode] = unicodeCharCode;
      });

      // Attempt to improve the glyph mapping for (some) composite fonts that
      // appear to lack meaningful ToUnicode data.
      if (this.composite && this.toUnicode instanceof IdentityToUnicodeMap) {
        if (/Tahoma|Verdana/i.test(name)) {
          // Fixes issue15719.pdf and issue11242_reduced.pdf.
          applyStandardFontGlyphMap(map, getGlyphMapForStandardFonts());
        }
      }
      this.toFontChar = map;
    }

    amendFallbackToUnicode(properties);
    this.loadedName = fontName.split("-", 1)[0];
  }