Convert src/core/fonts.js to use standard classes

Obviously the `Font`-class is still *very* large, given particularly how TrueType fonts are handled, however this patch-series at least improves things by moving a number of functions/classes into their own files.
As a follow-up it might make sense to try and re-factor/extract the TrueType parsing into its own file, since all of this code is quite old, however that's probably best left for another time.

For e.g. `gulp mozcentral`, the *built* `pdf.worker.js` files decreases from `1 620 332` to `1 617 466` bytes with this patch-series.
This commit is contained in:
Jonas Jenwald 2021-05-02 17:42:48 +02:00
parent cadc20d8b9
commit b487edd05d

View File

@ -157,9 +157,8 @@ function adjustToUnicode(properties, builtInEncoding) {
properties.toUnicode.amend(toUnicode); properties.toUnicode.amend(toUnicode);
} }
const Glyph = (function GlyphClosure() { class Glyph {
// eslint-disable-next-line no-shadow constructor(
function Glyph(
fontChar, fontChar,
unicode, unicode,
accent, accent,
@ -179,7 +178,7 @@ const Glyph = (function GlyphClosure() {
this.isInFont = isInFont; this.isInFont = isInFont;
} }
Glyph.prototype.matchesForCache = function ( matchesForCache(
fontChar, fontChar,
unicode, unicode,
accent, accent,
@ -199,183 +198,32 @@ const Glyph = (function GlyphClosure() {
this.isSpace === isSpace && this.isSpace === isSpace &&
this.isInFont === isInFont this.isInFont === isInFont
); );
};
return Glyph;
})();
/**
* 'Font' is the class the outside world should use, it encapsulate all the font
* decoding logics whatever type it is (assuming the font type is supported).
*
* For example to read a Type1 font and to attach it to the document:
* var type1Font = new Font("MyFontName", binaryFile, propertiesObject);
* type1Font.bind();
*/
const Font = (function FontClosure() {
// eslint-disable-next-line no-shadow
function Font(name, file, properties) {
let charCode;
this.name = name;
this.loadedName = properties.loadedName;
this.isType3Font = properties.isType3Font;
this.missingFile = false;
this.cssFontInfo = properties.cssFontInfo;
this.glyphCache = Object.create(null);
this.isSerifFont = !!(properties.flags & FontFlags.Serif);
this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);
let type = properties.type;
let subtype = properties.subtype;
this.type = type;
this.subtype = subtype;
let fallbackName = "sans-serif";
if (this.isMonospace) {
fallbackName = "monospace";
} else if (this.isSerifFont) {
fallbackName = "serif";
} }
this.fallbackName = fallbackName; }
this.differences = properties.differences; function int16(b0, b1) {
this.widths = properties.widths;
this.defaultWidth = properties.defaultWidth;
this.composite = properties.composite;
this.cMap = properties.cMap;
this.capHeight = properties.capHeight / PDF_GLYPH_SPACE_UNITS;
this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS;
this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS;
this.fontMatrix = properties.fontMatrix;
this.bbox = properties.bbox;
this.defaultEncoding = properties.defaultEncoding;
this.toUnicode = properties.toUnicode;
this.fallbackToUnicode = properties.fallbackToUnicode || new ToUnicodeMap();
this.toFontChar = [];
if (properties.type === "Type3") {
for (charCode = 0; charCode < 256; charCode++) {
this.toFontChar[charCode] =
this.differences[charCode] || properties.defaultEncoding[charCode];
}
this.fontType = FontType.TYPE3;
return;
}
this.cidEncoding = properties.cidEncoding;
this.vertical = !!properties.vertical;
if (this.vertical) {
this.vmetrics = properties.vmetrics;
this.defaultVMetrics = properties.defaultVMetrics;
}
if (!file || file.isEmpty) {
if (file) {
// Some bad PDF generators will include empty font files,
// attempting to recover by assuming that no file exists.
warn('Font file is empty in "' + name + '" (' + this.loadedName + ")");
}
this.fallbackToSystemFont(properties);
return;
}
// Parse the font file to determine the correct type/subtype, rather than
// relying on the (often incorrect) data in the font dictionary; (see e.g.
// issue6782.pdf, issue7598.pdf, and issue9949.pdf).
[type, subtype] = getFontFileType(file, properties);
if (type !== this.type || subtype !== this.subtype) {
info(
"Inconsistent font file Type/SubType, expected: " +
`${this.type}/${this.subtype} but found: ${type}/${subtype}.`
);
}
let data;
try {
switch (type) {
case "MMType1":
info("MMType1 font (" + name + "), falling back to Type1.");
/* falls through */
case "Type1":
case "CIDFontType0":
this.mimetype = "font/opentype";
const cff =
subtype === "Type1C" || subtype === "CIDFontType0C"
? new CFFFont(file, properties)
: new Type1Font(name, file, properties);
adjustWidths(properties);
// Wrap the CFF data inside an OTF font file
data = this.convert(name, cff, properties);
break;
case "OpenType":
case "TrueType":
case "CIDFontType2":
this.mimetype = "font/opentype";
// Repair the TrueType file. It is can be damaged in the point of
// view of the sanitizer
data = this.checkAndRepair(name, file, properties);
if (this.isOpenType) {
adjustWidths(properties);
type = "OpenType";
}
break;
default:
throw new FormatError(`Font ${type} is not supported`);
}
} catch (e) {
warn(e);
this.fallbackToSystemFont(properties);
return;
}
this.data = data;
this.fontType = getFontType(type, subtype);
// Transfer some properties again that could change during font conversion
this.fontMatrix = properties.fontMatrix;
this.widths = properties.widths;
this.defaultWidth = properties.defaultWidth;
this.toUnicode = properties.toUnicode;
this.seacMap = properties.seacMap;
}
function int16(b0, b1) {
return (b0 << 8) + b1; return (b0 << 8) + b1;
} }
function writeSignedInt16(bytes, index, value) { function writeSignedInt16(bytes, index, value) {
bytes[index + 1] = value; bytes[index + 1] = value;
bytes[index] = value >>> 8; bytes[index] = value >>> 8;
} }
function signedInt16(b0, b1) { function signedInt16(b0, b1) {
const value = (b0 << 8) + b1; const value = (b0 << 8) + b1;
return value & (1 << 15) ? value - 0x10000 : value; return value & (1 << 15) ? value - 0x10000 : value;
} }
function int32(b0, b1, b2, b3) { function int32(b0, b1, b2, b3) {
return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
} }
function string16(value) { function string16(value) {
return String.fromCharCode((value >> 8) & 0xff, value & 0xff); return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
} }
function safeString16(value) { function safeString16(value) {
// clamp value to the 16-bit int range // clamp value to the 16-bit int range
if (value > 0x7fff) { if (value > 0x7fff) {
value = 0x7fff; value = 0x7fff;
@ -383,26 +231,26 @@ const Font = (function FontClosure() {
value = -0x8000; value = -0x8000;
} }
return String.fromCharCode((value >> 8) & 0xff, value & 0xff); return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
} }
function isTrueTypeFile(file) { function isTrueTypeFile(file) {
const header = file.peekBytes(4); const header = file.peekBytes(4);
return ( return (
readUint32(header, 0) === 0x00010000 || bytesToString(header) === "true" readUint32(header, 0) === 0x00010000 || bytesToString(header) === "true"
); );
} }
function isTrueTypeCollectionFile(file) { function isTrueTypeCollectionFile(file) {
const header = file.peekBytes(4); const header = file.peekBytes(4);
return bytesToString(header) === "ttcf"; return bytesToString(header) === "ttcf";
} }
function isOpenTypeFile(file) { function isOpenTypeFile(file) {
const header = file.peekBytes(4); const header = file.peekBytes(4);
return bytesToString(header) === "OTTO"; return bytesToString(header) === "OTTO";
} }
function isType1File(file) { function isType1File(file) {
const header = file.peekBytes(2); const header = file.peekBytes(2);
// All Type1 font programs must begin with the comment '%!' (0x25 + 0x21). // All Type1 font programs must begin with the comment '%!' (0x25 + 0x21).
if (header[0] === 0x25 && header[1] === 0x21) { if (header[0] === 0x25 && header[1] === 0x21) {
@ -414,14 +262,14 @@ const Font = (function FontClosure() {
return true; return true;
} }
return false; return false;
} }
/** /**
* Compared to other font formats, the header in CFF files is not constant * Compared to other font formats, the header in CFF files is not constant
* but contains version numbers. To reduce the possibility of misclassifying * but contains version numbers. To reduce the possibility of misclassifying
* font files as CFF, it's recommended to check for other font formats first. * font files as CFF, it's recommended to check for other font formats first.
*/ */
function isCFFFile(file) { function isCFFFile(file) {
const header = file.peekBytes(4); const header = file.peekBytes(4);
if ( if (
/* major version, [1, 255] */ header[0] >= 1 && /* major version, [1, 255] */ header[0] >= 1 &&
@ -433,9 +281,9 @@ const Font = (function FontClosure() {
return true; return true;
} }
return false; return false;
} }
function getFontFileType(file, { type, subtype, composite }) { function getFontFileType(file, { type, subtype, composite }) {
let fileType, fileSubtype; let fileType, fileSubtype;
if (isTrueTypeFile(file) || isTrueTypeCollectionFile(file)) { if (isTrueTypeFile(file) || isTrueTypeCollectionFile(file)) {
@ -471,9 +319,9 @@ const Font = (function FontClosure() {
} }
return [fileType, fileSubtype]; return [fileType, fileSubtype];
} }
function buildToFontChar(encoding, glyphsUnicodeMap, differences) { function buildToFontChar(encoding, glyphsUnicodeMap, differences) {
const toFontChar = []; const toFontChar = [];
let unicode; let unicode;
for (let i = 0, ii = encoding.length; i < ii; i++) { for (let i = 0, ii = encoding.length; i < ii; i++) {
@ -489,9 +337,9 @@ const Font = (function FontClosure() {
} }
} }
return toFontChar; return toFontChar;
} }
/** /**
* Rebuilds the char code to glyph ID map by moving all char codes to the * Rebuilds the char code to glyph ID map by moving all char codes to the
* private use area. This is done to avoid issues with various problematic * private use area. This is done to avoid issues with various problematic
* unicode areas where either a glyph won't be drawn or is deformed by a * unicode areas where either a glyph won't be drawn or is deformed by a
@ -502,7 +350,7 @@ const Font = (function FontClosure() {
* font that we build * font that we build
* 'charCodeToGlyphId' - maps the new font char codes to glyph ids * 'charCodeToGlyphId' - maps the new font char codes to glyph ids
*/ */
function adjustMapping(charCodeToGlyphId, hasGlyph, newGlyphZeroId) { function adjustMapping(charCodeToGlyphId, hasGlyph, newGlyphZeroId) {
const newMap = Object.create(null); const newMap = Object.create(null);
const toFontChar = []; const toFontChar = [];
let privateUseAreaIndex = 0; let privateUseAreaIndex = 0;
@ -538,9 +386,9 @@ const Font = (function FontClosure() {
charCodeToGlyphId: newMap, charCodeToGlyphId: newMap,
nextAvailableFontCharCode, nextAvailableFontCharCode,
}; };
} }
function getRanges(glyphs, numGlyphs) { function getRanges(glyphs, numGlyphs) {
// Array.sort() sorts by characters, not numerically, so convert to an // Array.sort() sorts by characters, not numerically, so convert to an
// array of characters. // array of characters.
const codes = []; const codes = [];
@ -580,9 +428,9 @@ const Font = (function FontClosure() {
} }
return ranges; return ranges;
} }
function createCmapTable(glyphs, numGlyphs) { function createCmapTable(glyphs, numGlyphs) {
const ranges = getRanges(glyphs, numGlyphs); const ranges = getRanges(glyphs, numGlyphs);
const numTables = ranges[ranges.length - 1][1] > 0xffff ? 2 : 1; const numTables = ranges[ranges.length - 1][1] > 0xffff ? 2 : 1;
let cmap = let cmap =
@ -713,9 +561,9 @@ const Font = (function FontClosure() {
header31012 + header31012 +
format31012 format31012
); );
} }
function validateOS2Table(os2, file) { function validateOS2Table(os2, file) {
file.pos = (file.start || 0) + os2.offset; file.pos = (file.start || 0) + os2.offset;
const version = file.getUint16(); const version = file.getUint16();
// TODO verify all OS/2 tables fields, but currently we validate only those // TODO verify all OS/2 tables fields, but currently we validate only those
@ -740,9 +588,9 @@ const Font = (function FontClosure() {
// OS/2 appears to be valid, resetting some fields // OS/2 appears to be valid, resetting some fields
os2.data[8] = os2.data[9] = 0; // IE rejects fonts if fsType != 0 os2.data[8] = os2.data[9] = 0; // IE rejects fonts if fsType != 0
return true; return true;
} }
function createOS2Table(properties, charstrings, override) { function createOS2Table(properties, charstrings, override) {
override = override || { override = override || {
unitsPerEm: 0, unitsPerEm: 0,
yMax: 0, yMax: 0,
@ -857,9 +705,9 @@ const Font = (function FontClosure() {
string16(firstCharIndex || properties.firstChar) + // usBreakChar string16(firstCharIndex || properties.firstChar) + // usBreakChar
"\x00\x03" "\x00\x03"
); // usMaxContext ); // usMaxContext
} }
function createPostTable(properties) { function createPostTable(properties) {
const angle = Math.floor(properties.italicAngle * 2 ** 16); const angle = Math.floor(properties.italicAngle * 2 ** 16);
return ( return (
"\x00\x03\x00\x00" + // Version number "\x00\x03\x00\x00" + // Version number
@ -872,9 +720,9 @@ const Font = (function FontClosure() {
"\x00\x00\x00\x00" + // minMemType1 "\x00\x00\x00\x00" + // minMemType1
"\x00\x00\x00\x00" "\x00\x00\x00\x00"
); // maxMemType1 ); // maxMemType1
} }
function createNameTable(name, proto) { function createNameTable(name, proto) {
if (!proto) { if (!proto) {
proto = [[], []]; // no strings and unicode strings proto = [[], []]; // no strings and unicode strings
} }
@ -937,18 +785,157 @@ const Font = (function FontClosure() {
nameTable += strings.join("") + stringsUnicode.join(""); nameTable += strings.join("") + stringsUnicode.join("");
return nameTable; return nameTable;
}
/**
* 'Font' is the class the outside world should use, it encapsulate all the font
* decoding logics whatever type it is (assuming the font type is supported).
*/
class Font {
constructor(name, file, properties) {
this.name = name;
this.mimetype = null;
this.disableFontFace = false;
this.loadedName = properties.loadedName;
this.isType3Font = properties.isType3Font;
this.missingFile = false;
this.cssFontInfo = properties.cssFontInfo;
this.glyphCache = Object.create(null);
this.isSerifFont = !!(properties.flags & FontFlags.Serif);
this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);
let type = properties.type;
let subtype = properties.subtype;
this.type = type;
this.subtype = subtype;
let fallbackName = "sans-serif";
if (this.isMonospace) {
fallbackName = "monospace";
} else if (this.isSerifFont) {
fallbackName = "serif";
}
this.fallbackName = fallbackName;
this.differences = properties.differences;
this.widths = properties.widths;
this.defaultWidth = properties.defaultWidth;
this.composite = properties.composite;
this.cMap = properties.cMap;
this.capHeight = properties.capHeight / PDF_GLYPH_SPACE_UNITS;
this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS;
this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS;
this.fontMatrix = properties.fontMatrix;
this.bbox = properties.bbox;
this.defaultEncoding = properties.defaultEncoding;
this.toUnicode = properties.toUnicode;
this.fallbackToUnicode = properties.fallbackToUnicode || new ToUnicodeMap();
this.toFontChar = [];
if (properties.type === "Type3") {
for (let charCode = 0; charCode < 256; charCode++) {
this.toFontChar[charCode] =
this.differences[charCode] || properties.defaultEncoding[charCode];
}
this.fontType = FontType.TYPE3;
return;
} }
Font.prototype = { this.cidEncoding = properties.cidEncoding;
name: null, this.vertical = !!properties.vertical;
font: null, if (this.vertical) {
mimetype: null, this.vmetrics = properties.vmetrics;
disableFontFace: false, this.defaultVMetrics = properties.defaultVMetrics;
}
if (!file || file.isEmpty) {
if (file) {
// Some bad PDF generators will include empty font files,
// attempting to recover by assuming that no file exists.
warn('Font file is empty in "' + name + '" (' + this.loadedName + ")");
}
this.fallbackToSystemFont(properties);
return;
}
// Parse the font file to determine the correct type/subtype, rather than
// relying on the (often incorrect) data in the font dictionary; (see e.g.
// issue6782.pdf, issue7598.pdf, and issue9949.pdf).
[type, subtype] = getFontFileType(file, properties);
if (type !== this.type || subtype !== this.subtype) {
info(
"Inconsistent font file Type/SubType, expected: " +
`${this.type}/${this.subtype} but found: ${type}/${subtype}.`
);
}
let data;
try {
switch (type) {
case "MMType1":
info("MMType1 font (" + name + "), falling back to Type1.");
/* falls through */
case "Type1":
case "CIDFontType0":
this.mimetype = "font/opentype";
const cff =
subtype === "Type1C" || subtype === "CIDFontType0C"
? new CFFFont(file, properties)
: new Type1Font(name, file, properties);
adjustWidths(properties);
// Wrap the CFF data inside an OTF font file
data = this.convert(name, cff, properties);
break;
case "OpenType":
case "TrueType":
case "CIDFontType2":
this.mimetype = "font/opentype";
// Repair the TrueType file. It is can be damaged in the point of
// view of the sanitizer
data = this.checkAndRepair(name, file, properties);
if (this.isOpenType) {
adjustWidths(properties);
type = "OpenType";
}
break;
default:
throw new FormatError(`Font ${type} is not supported`);
}
} catch (e) {
warn(e);
this.fallbackToSystemFont(properties);
return;
}
this.data = data;
this.fontType = getFontType(type, subtype);
// Transfer some properties again that could change during font conversion
this.fontMatrix = properties.fontMatrix;
this.widths = properties.widths;
this.defaultWidth = properties.defaultWidth;
this.toUnicode = properties.toUnicode;
this.seacMap = properties.seacMap;
}
get renderer() { get renderer() {
const renderer = FontRendererFactory.create(this, SEAC_ANALYSIS_ENABLED); const renderer = FontRendererFactory.create(this, SEAC_ANALYSIS_ENABLED);
return shadow(this, "renderer", renderer); return shadow(this, "renderer", renderer);
}, }
exportData(extraProperties = false) { exportData(extraProperties = false) {
const exportDataProperties = extraProperties const exportDataProperties = extraProperties
@ -965,7 +952,7 @@ const Font = (function FontClosure() {
} }
} }
return data; return data;
}, }
fallbackToSystemFont(properties) { fallbackToSystemFont(properties) {
this.missingFile = true; this.missingFile = true;
@ -985,8 +972,7 @@ const Font = (function FontClosure() {
fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName; fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;
this.bold = fontName.search(/bold/gi) !== -1; this.bold = fontName.search(/bold/gi) !== -1;
this.italic = this.italic =
fontName.search(/oblique/gi) !== -1 || fontName.search(/oblique/gi) !== -1 || fontName.search(/italic/gi) !== -1;
fontName.search(/italic/gi) !== -1;
// Use 'name' instead of 'fontName' here because the original // Use 'name' instead of 'fontName' here because the original
// name ArialBlack for example will be replaced by Helvetica. // name ArialBlack for example will be replaced by Helvetica.
@ -1034,8 +1020,7 @@ const Font = (function FontClosure() {
} }
} }
const isIdentityUnicode = const isIdentityUnicode = this.toUnicode instanceof IdentityToUnicodeMap;
this.toUnicode instanceof IdentityToUnicodeMap;
if (!isIdentityUnicode) { if (!isIdentityUnicode) {
this.toUnicode.forEach(function (charCode, unicodeCharCode) { this.toUnicode.forEach(function (charCode, unicodeCharCode) {
map[+charCode] = unicodeCharCode; map[+charCode] = unicodeCharCode;
@ -1094,9 +1079,9 @@ const Font = (function FontClosure() {
} }
this.loadedName = fontName.split("-")[0]; this.loadedName = fontName.split("-")[0];
this.fontType = getFontType(type, subtype); this.fontType = getFontType(type, subtype);
}, }
checkAndRepair: function Font_checkAndRepair(name, font, properties) { checkAndRepair(name, font, properties) {
const VALID_TABLES = [ const VALID_TABLES = [
"OS/2", "OS/2",
"cmap", "cmap",
@ -1496,13 +1481,7 @@ const Font = (function FontClosure() {
}; };
} }
function sanitizeMetrics( function sanitizeMetrics(file, header, metrics, numGlyphs, dupFirstEntry) {
file,
header,
metrics,
numGlyphs,
dupFirstEntry
) {
if (!header) { if (!header) {
if (metrics) { if (metrics) {
metrics.data = null; metrics.data = null;
@ -1958,11 +1937,7 @@ const Font = (function FontClosure() {
const NAME_RECORD_LENGTH = 12; const NAME_RECORD_LENGTH = 12;
let i, ii; let i, ii;
for ( for (i = 0; i < numRecords && font.pos + NAME_RECORD_LENGTH <= end; i++) {
i = 0;
i < numRecords && font.pos + NAME_RECORD_LENGTH <= end;
i++
) {
const r = { const r = {
platform: font.getUint16(), platform: font.getUint16(),
encoding: font.getUint16(), encoding: font.getUint16(),
@ -2141,8 +2116,7 @@ const Font = (function FontClosure() {
funcId = functionsCalled.pop(); funcId = functionsCalled.pop();
data = pc.data; data = pc.data;
i = pc.i; i = pc.i;
ttContext.functionsStackDeltas[funcId] = ttContext.functionsStackDeltas[funcId] = stack.length - pc.stackTop;
stack.length - pc.stackTop;
} }
} else if (op === 0x89) { } else if (op === 0x89) {
// IDEF - instruction definition // IDEF - instruction definition
@ -2562,8 +2536,7 @@ const Font = (function FontClosure() {
} else if (cmapPlatformId === 0) { } else if (cmapPlatformId === 0) {
// Default Unicode semantics, use the charcodes as is. // Default Unicode semantics, use the charcodes as is.
for (let i = 0; i < cmapMappingsLength; ++i) { for (let i = 0; i < cmapMappingsLength; ++i) {
charCodeToGlyphId[cmapMappings[i].charCode] = charCodeToGlyphId[cmapMappings[i].charCode] = cmapMappings[i].glyphId;
cmapMappings[i].glyphId;
} }
} else { } else {
// When there is only a (1, 0) cmap table, the char code is a single // When there is only a (1, 0) cmap table, the char code is a single
@ -2687,9 +2660,9 @@ const Font = (function FontClosure() {
builder.addTable(tableTag, tables[tableTag].data); builder.addTable(tableTag, tables[tableTag].data);
} }
return builder.toArray(); return builder.toArray();
}, }
convert: function Font_convert(fontName, font, properties) { convert(fontName, font, properties) {
// TODO: Check the charstring widths to determine this. // TODO: Check the charstring widths to determine this.
properties.fixedPitch = false; properties.fixedPitch = false;
@ -2882,7 +2855,7 @@ const Font = (function FontClosure() {
builder.addTable("post", createPostTable(properties)); builder.addTable("post", createPostTable(properties));
return builder.toArray(); return builder.toArray();
}, }
get spaceWidth() { get spaceWidth() {
// trying to estimate space character width // trying to estimate space character width
@ -2918,7 +2891,7 @@ const Font = (function FontClosure() {
} }
width = width || this.defaultWidth; width = width || this.defaultWidth;
return shadow(this, "spaceWidth", width); return shadow(this, "spaceWidth", width);
}, }
/** /**
* @private * @private
@ -3012,9 +2985,9 @@ const Font = (function FontClosure() {
this.glyphCache[charcode] = glyph; this.glyphCache[charcode] = glyph;
} }
return glyph; return glyph;
}, }
charsToGlyphs: function Font_charsToGlyphs(chars) { charsToGlyphs(chars) {
let charsCache = this.charsCache; let charsCache = this.charsCache;
let glyphs, glyph, charcode; let glyphs, glyph, charcode;
@ -3060,7 +3033,7 @@ const Font = (function FontClosure() {
// Enter the translated string into the cache // Enter the translated string into the cache
return (charsCache[charsCacheKey] = glyphs); return (charsCache[charsCacheKey] = glyphs);
}, }
/** /**
* Chars can have different sizes (depends on the encoding). * Chars can have different sizes (depends on the encoding).
@ -3088,11 +3061,11 @@ const Font = (function FontClosure() {
} }
return positions; return positions;
}, }
get glyphCacheValues() { get glyphCacheValues() {
return Object.values(this.glyphCache); return Object.values(this.glyphCache);
}, }
/** /**
* Encode a js string using font encoding. * Encode a js string using font encoding.
@ -3129,9 +3102,7 @@ const Font = (function FontClosure() {
? this.cMap.getCharCodeLength(charCode) ? this.cMap.getCharCodeLength(charCode)
: 1; : 1;
for (let j = charCodeLength - 1; j >= 0; j--) { for (let j = charCodeLength - 1; j >= 0; j--) {
currentBuf.push( currentBuf.push(String.fromCharCode((charCode >> (8 * j)) & 0xff));
String.fromCharCode((charCode >> (8 * j)) & 0xff)
);
} }
continue; continue;
} }
@ -3148,33 +3119,27 @@ const Font = (function FontClosure() {
buffers.push(currentBuf.join("")); buffers.push(currentBuf.join(""));
return buffers; return buffers;
}, }
}; }
return Font; class ErrorFont {
})(); constructor(error) {
const ErrorFont = (function ErrorFontClosure() {
// eslint-disable-next-line no-shadow
function ErrorFont(error) {
this.error = error; this.error = error;
this.loadedName = "g_font_error"; this.loadedName = "g_font_error";
this.missingFile = true; this.missingFile = true;
} }
ErrorFont.prototype = { charsToGlyphs() {
charsToGlyphs: function ErrorFont_charsToGlyphs() {
return []; return [];
}, }
encodeString: function ErrorFont_encodeString(chars) {
encodeString(chars) {
return [chars]; return [chars];
}, }
exportData(extraProperties = false) { exportData(extraProperties = false) {
return { error: this.error }; return { error: this.error };
}, }
}; }
return ErrorFont;
})();
export { ErrorFont, Font }; export { ErrorFont, Font };