modern-font
Version:
JavaScript Font Codec.
2,402 lines (2,386 loc) • 145 kB
JavaScript
import { zlibSync, unzlibSync } from 'fflate';
const PKG_NAME = "modern-font";
function assert(condition, msg) {
if (!condition) {
throw new Error(`[${PKG_NAME}] ${msg}`);
}
}
function toBuffer(source) {
if ("buffer" in source) {
const buffer = source.buffer;
if (source.byteOffset > 0 || source.byteLength < source.buffer.byteLength) {
return buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
}
return buffer;
} else {
return source;
}
}
function toDataView(source) {
if ("buffer" in source) {
return new DataView(source.buffer, source.byteOffset, source.byteLength);
} else {
return new DataView(source);
}
}
function stringify(str) {
let newStr = "";
for (let i = 0, l = str.length, ch; i < l; i++) {
ch = str.charCodeAt(i);
if (ch === 0) {
continue;
}
newStr += String.fromCharCode(ch);
}
return newStr;
}
function toUCS2Bytes(str) {
str = stringify(str);
const byteArray = [];
for (let i = 0, l = str.length, ch; i < l; i++) {
ch = str.charCodeAt(i);
byteArray.push(ch >> 8);
byteArray.push(ch & 255);
}
return byteArray;
}
function getUTF8String(bytes) {
let str = "";
for (let i = 0, l = bytes.length; i < l; i++) {
if (bytes[i] < 127) {
str += String.fromCharCode(bytes[i]);
} else {
str += `%${(256 + bytes[i]).toString(16).slice(1)}`;
}
}
return unescape(str);
}
function getUCS2String(bytes) {
let str = "";
for (let i = 0, l = bytes.length; i < l; i += 2) {
str += String.fromCharCode((bytes[i] << 8) + bytes[i + 1]);
}
return str;
}
var __defProp$o = Object.defineProperty;
var __decorateClass$u = (decorators, target, key, kind) => {
var result = void 0 ;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (decorator(target, key, result) ) || result;
if (result) __defProp$o(target, key, result);
return result;
};
const dataTypeToByteLength = {
int8: 1,
int16: 2,
int32: 4,
uint8: 1,
uint16: 2,
uint32: 4,
float32: 4,
float64: 8,
fixed: 4,
longDateTime: 8,
char: 1
};
function defineMethod() {
return function(target, name) {
Object.defineProperty(target.constructor.prototype, name, {
get() {
if (typeof name === "string") {
if (name.startsWith("read")) {
return (...args) => this.read(name.substring("read".length).toLowerCase(), ...args);
} else if (name.startsWith("write")) {
return (...args) => this.write(name.substring("write".length).toLowerCase(), ...args);
}
}
return void 0;
},
configurable: true,
enumerable: true
});
};
}
class FontDataView extends DataView {
constructor(source, byteOffset, byteLength, littleEndian) {
super(toBuffer(source), byteOffset, byteLength);
this.littleEndian = littleEndian;
}
cursor = 0;
readColumn(column) {
if (column.size) {
const array = Array.from({ length: column.size }, (_, i) => {
return this.read(column.type, column.offset + i);
});
switch (column.type) {
case "char":
return array.join("");
default:
return array;
}
} else {
return this.read(column.type, column.offset);
}
}
writeColumn(column, value) {
if (column.size) {
Array.from({ length: column.size }, (_, i) => {
this.write(column.type, value[i], column.offset + i);
});
} else {
this.write(column.type, value, column.offset);
}
}
read(type, byteOffset = this.cursor, littleEndian = this.littleEndian) {
switch (type) {
case "char":
return this.readChar(byteOffset);
case "fixed":
return this.readFixed(byteOffset, littleEndian);
case "longDateTime":
return this.readLongDateTime(byteOffset, littleEndian);
}
const key = `get${type.replace(/^\S/, (s) => s.toUpperCase())}`;
const self = this;
const method = self[key]?.bind(self);
const result = method?.(byteOffset, littleEndian);
this.cursor += dataTypeToByteLength[type];
return result;
}
readUint24(byteOffset = this.cursor) {
const [i, j, k] = this.readBytes(byteOffset, 3);
return (i << 16) + (j << 8) + k;
}
readBytes(byteOffset, length) {
if (length == null) {
length = byteOffset;
byteOffset = this.cursor;
}
const array = [];
for (let i = 0; i < length; ++i) {
array.push(this.getUint8(byteOffset + i));
}
this.cursor = byteOffset + length;
return array;
}
readString(byteOffset, length) {
const bytes = this.readBytes(byteOffset, length);
let str = "";
for (let i = 0, len = bytes.length; i < len; i++) {
str += String.fromCharCode(bytes[i]);
}
return str;
}
readFixed(byteOffset, littleEndian) {
const val = this.readInt32(byteOffset, littleEndian) / 65536;
return Math.ceil(val * 1e5) / 1e5;
}
readLongDateTime(byteOffset = this.cursor, littleEndian) {
const time = this.readUint32(byteOffset + 4, littleEndian);
const date = /* @__PURE__ */ new Date();
date.setTime(time * 1e3 + -20775456e5);
return date;
}
readChar(byteOffset) {
return this.readString(byteOffset, 1);
}
write(type, value, byteOffset = this.cursor, littleEndian = this.littleEndian) {
switch (type) {
case "char":
return this.writeChar(value, byteOffset);
case "fixed":
return this.writeFixed(value, byteOffset);
case "longDateTime":
return this.writeLongDateTime(value, byteOffset);
}
const key = `set${type.replace(/^\S/, (s) => s.toUpperCase())}`;
const self = this;
const method = self[key]?.bind(self);
const result = method?.(byteOffset, value, littleEndian);
this.cursor += dataTypeToByteLength[type.toLowerCase()];
return result;
}
writeString(str = "", byteOffset = this.cursor) {
const length = str.replace(/[^\x00-\xFF]/g, "11").length;
this.seek(byteOffset);
for (let i = 0, l = str.length, charCode; i < l; ++i) {
charCode = str.charCodeAt(i) || 0;
if (charCode > 127) {
this.writeUint16(charCode);
} else {
this.writeUint8(charCode);
}
}
this.cursor += length;
return this;
}
writeChar(value, byteOffset) {
return this.writeString(value, byteOffset);
}
writeFixed(value, byteOffset) {
this.writeInt32(Math.round(value * 65536), byteOffset);
return this;
}
writeLongDateTime(value, byteOffset = this.cursor) {
const delta = -20775456e5;
if (typeof value === "undefined") {
value = delta;
} else if (typeof value.getTime === "function") {
value = value.getTime();
} else if (/^\d+$/.test(value)) {
value = +value;
} else {
value = Date.parse(value);
}
const time = Math.round((value - delta) / 1e3);
this.writeUint32(0, byteOffset);
this.writeUint32(time, byteOffset + 4);
return this;
}
writeBytes(value, byteOffset = this.cursor) {
let len;
if (Array.isArray(value)) {
len = value.length;
for (let i = 0; i < len; ++i) {
this.setUint8(byteOffset + i, value[i]);
}
} else {
const view = toDataView(value);
len = view.byteLength;
for (let i = 0; i < len; ++i) {
this.setUint8(byteOffset + i, view.getUint8(i));
}
}
this.cursor = byteOffset + len;
return this;
}
seek(byteOffset) {
this.cursor = byteOffset;
return this;
}
}
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "readInt8");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "readInt16");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "readInt32");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "readUint8");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "readUint16");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "readUint32");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "readFloat32");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "readFloat64");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "writeInt8");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "writeInt16");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "writeInt32");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "writeUint8");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "writeUint16");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "writeUint32");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "writeFloat32");
__decorateClass$u([
defineMethod()
], FontDataView.prototype, "writeFloat64");
const definitions = /* @__PURE__ */ new WeakMap();
function defineColumn(options) {
const config = typeof options === "object" ? options : { type: options };
const { size = 1, type } = config;
return (target, name) => {
if (typeof name !== "string")
return;
let definition = definitions.get(target);
if (!definition) {
definition = {
columns: [],
byteLength: 0
};
definitions.set(target, definition);
}
const column = {
...config,
name,
byteLength: size * dataTypeToByteLength[type],
offset: config.offset ?? definition.columns.reduce((offset, column2) => offset + column2.byteLength, 0)
};
definition.columns.push(column);
definition.byteLength = definition.columns.reduce((byteLength, column2) => {
return byteLength + dataTypeToByteLength[column2.type] * (column2.size ?? 1);
}, 0);
Object.defineProperty(target.constructor.prototype, name, {
get() {
return this.view.readColumn(column);
},
set(value) {
this.view.writeColumn(column, value);
},
configurable: true,
enumerable: true
});
};
}
class FontDataObject {
view;
constructor(source, byteOffset, byteLength, littleEndian) {
this.view = new FontDataView(source, byteOffset, byteLength, littleEndian);
}
}
class BaseFont extends FontDataObject {
get buffer() {
return this.view.buffer;
}
toBuffer() {
return this.view.buffer.slice(this.view.byteOffset, this.view.byteOffset + this.view.byteLength);
}
toBlob() {
return new Blob(
[new Uint8Array(this.view.buffer, this.view.byteOffset, this.view.byteLength)],
{ type: this.mimeType }
);
}
toFontFace(family) {
return new FontFace(family, this.view.buffer);
}
}
var __defProp$n = Object.defineProperty;
var __decorateClass$t = (decorators, target, key, kind) => {
var result = void 0 ;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (decorator(target, key, result) ) || result;
if (result) __defProp$n(target, key, result);
return result;
};
const _EOT = class _EOT extends BaseFont {
format = "EmbeddedOpenType";
mimeType = "application/vnd.ms-fontobject";
// FamilyNameSize
// FamilyName
// Padding2
// StyleNameSize
// StyleName
// Padding3
// VersionNameSize
// VersionName
// Padding4
// FullNameSize
// FullName
// FontData
static from(ttf) {
const sfnt = ttf.sfnt;
const name = sfnt.name;
const names = name.names;
const FamilyName = toUCS2Bytes(names.fontFamily || "");
const FamilyNameSize = FamilyName.length;
const StyleName = toUCS2Bytes(names.fontStyle || "");
const StyleNameSize = StyleName.length;
const VersionName = toUCS2Bytes(names.version || "");
const VersionNameSize = VersionName.length;
const FullName = toUCS2Bytes(names.fullName || "");
const FullNameSize = FullName.length;
const size = 82 + 4 + FamilyNameSize + 4 + StyleNameSize + 4 + VersionNameSize + 4 + FullNameSize + 2 + ttf.view.byteLength;
const eot = new _EOT(new ArrayBuffer(size), 0, size, true);
eot.EOTSize = eot.view.byteLength;
eot.FontDataSize = ttf.view.byteLength;
eot.Version = 131073;
eot.Flags = 0;
eot.Charset = 1;
eot.MagicNumber = 20556;
eot.Padding1 = 0;
eot.CheckSumAdjustment = sfnt.head.checkSumAdjustment;
const os2 = sfnt.os2;
if (os2) {
eot.FontPANOSE = os2.fontPANOSE;
eot.Italic = os2.fsSelection;
eot.Weight = os2.usWeightClass;
eot.fsType = os2.fsType;
eot.UnicodeRange = os2.ulUnicodeRange;
eot.CodePageRange = os2.ulCodePageRange;
}
eot.view.writeUint16(FamilyNameSize);
eot.view.writeBytes(FamilyName);
eot.view.writeUint16(0);
eot.view.writeUint16(StyleNameSize);
eot.view.writeBytes(StyleName);
eot.view.writeUint16(0);
eot.view.writeUint16(VersionNameSize);
eot.view.writeBytes(VersionName);
eot.view.writeUint16(0);
eot.view.writeUint16(FullNameSize);
eot.view.writeBytes(FullName);
eot.view.writeUint16(0);
eot.view.writeUint16(0);
eot.view.writeBytes(ttf.view);
return eot;
}
};
__decorateClass$t([
defineColumn("uint32")
], _EOT.prototype, "EOTSize");
__decorateClass$t([
defineColumn("uint32")
], _EOT.prototype, "FontDataSize");
__decorateClass$t([
defineColumn("uint32")
], _EOT.prototype, "Version");
__decorateClass$t([
defineColumn("uint32")
], _EOT.prototype, "Flags");
__decorateClass$t([
defineColumn({ type: "uint8", size: 10 })
], _EOT.prototype, "FontPANOSE");
__decorateClass$t([
defineColumn("uint8")
], _EOT.prototype, "Charset");
__decorateClass$t([
defineColumn("uint8")
], _EOT.prototype, "Italic");
__decorateClass$t([
defineColumn("uint32")
], _EOT.prototype, "Weight");
__decorateClass$t([
defineColumn("uint16")
], _EOT.prototype, "fsType");
__decorateClass$t([
defineColumn("uint16")
], _EOT.prototype, "MagicNumber");
__decorateClass$t([
defineColumn({ type: "uint8", size: 16 })
], _EOT.prototype, "UnicodeRange");
__decorateClass$t([
defineColumn({ type: "uint8", size: 8 })
], _EOT.prototype, "CodePageRange");
__decorateClass$t([
defineColumn("uint32")
], _EOT.prototype, "CheckSumAdjustment");
__decorateClass$t([
defineColumn({ type: "uint8", size: 16 })
], _EOT.prototype, "Reserved");
__decorateClass$t([
defineColumn("uint16")
], _EOT.prototype, "Padding1");
let EOT = _EOT;
var __defProp$m = Object.defineProperty;
var __decorateClass$s = (decorators, target, key, kind) => {
var result = void 0 ;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (decorator(target, key, result) ) || result;
if (result) __defProp$m(target, key, result);
return result;
};
class TableDirectory extends FontDataObject {
constructor(buffer, byteOffset) {
super(buffer, byteOffset, 16);
}
}
__decorateClass$s([
defineColumn({ type: "char", size: 4 })
], TableDirectory.prototype, "tag");
__decorateClass$s([
defineColumn("uint32")
], TableDirectory.prototype, "checkSum");
__decorateClass$s([
defineColumn("uint32")
], TableDirectory.prototype, "offset");
__decorateClass$s([
defineColumn("uint32")
], TableDirectory.prototype, "length");
const cffStandardEncoding = [
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"space",
"exclam",
"quotedbl",
"numbersign",
"dollar",
"percent",
"ampersand",
"quoteright",
"parenleft",
"parenright",
"asterisk",
"plus",
"comma",
"hyphen",
"period",
"slash",
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"colon",
"semicolon",
"less",
"equal",
"greater",
"question",
"at",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"bracketleft",
"backslash",
"bracketright",
"asciicircum",
"underscore",
"quoteleft",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"braceleft",
"bar",
"braceright",
"asciitilde",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"exclamdown",
"cent",
"sterling",
"fraction",
"yen",
"florin",
"section",
"currency",
"quotesingle",
"quotedblleft",
"guillemotleft",
"guilsinglleft",
"guilsinglright",
"fi",
"fl",
"",
"endash",
"dagger",
"daggerdbl",
"periodcentered",
"",
"paragraph",
"bullet",
"quotesinglbase",
"quotedblbase",
"quotedblright",
"guillemotright",
"ellipsis",
"perthousand",
"",
"questiondown",
"",
"grave",
"acute",
"circumflex",
"tilde",
"macron",
"breve",
"dotaccent",
"dieresis",
"",
"ring",
"cedilla",
"",
"hungarumlaut",
"ogonek",
"caron",
"emdash",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"AE",
"",
"ordfeminine",
"",
"",
"",
"",
"Lslash",
"Oslash",
"OE",
"ordmasculine",
"",
"",
"",
"",
"",
"ae",
"",
"",
"",
"dotlessi",
"",
"",
"lslash",
"oslash",
"oe",
"germandbls"
];
const cffExpertEncoding = [
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"space",
"exclamsmall",
"Hungarumlautsmall",
"",
"dollaroldstyle",
"dollarsuperior",
"ampersandsmall",
"Acutesmall",
"parenleftsuperior",
"parenrightsuperior",
"twodotenleader",
"onedotenleader",
"comma",
"hyphen",
"period",
"fraction",
"zerooldstyle",
"oneoldstyle",
"twooldstyle",
"threeoldstyle",
"fouroldstyle",
"fiveoldstyle",
"sixoldstyle",
"sevenoldstyle",
"eightoldstyle",
"nineoldstyle",
"colon",
"semicolon",
"commasuperior",
"threequartersemdash",
"periodsuperior",
"questionsmall",
"",
"asuperior",
"bsuperior",
"centsuperior",
"dsuperior",
"esuperior",
"",
"",
"isuperior",
"",
"",
"lsuperior",
"msuperior",
"nsuperior",
"osuperior",
"",
"",
"rsuperior",
"ssuperior",
"tsuperior",
"",
"ff",
"fi",
"fl",
"ffi",
"ffl",
"parenleftinferior",
"",
"parenrightinferior",
"Circumflexsmall",
"hyphensuperior",
"Gravesmall",
"Asmall",
"Bsmall",
"Csmall",
"Dsmall",
"Esmall",
"Fsmall",
"Gsmall",
"Hsmall",
"Ismall",
"Jsmall",
"Ksmall",
"Lsmall",
"Msmall",
"Nsmall",
"Osmall",
"Psmall",
"Qsmall",
"Rsmall",
"Ssmall",
"Tsmall",
"Usmall",
"Vsmall",
"Wsmall",
"Xsmall",
"Ysmall",
"Zsmall",
"colonmonetary",
"onefitted",
"rupiah",
"Tildesmall",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"exclamdownsmall",
"centoldstyle",
"Lslashsmall",
"",
"",
"Scaronsmall",
"Zcaronsmall",
"Dieresissmall",
"Brevesmall",
"Caronsmall",
"",
"Dotaccentsmall",
"",
"",
"Macronsmall",
"",
"",
"figuredash",
"hypheninferior",
"",
"",
"Ogoneksmall",
"Ringsmall",
"Cedillasmall",
"",
"",
"",
"onequarter",
"onehalf",
"threequarters",
"questiondownsmall",
"oneeighth",
"threeeighths",
"fiveeighths",
"seveneighths",
"onethird",
"twothirds",
"",
"",
"zerosuperior",
"onesuperior",
"twosuperior",
"threesuperior",
"foursuperior",
"fivesuperior",
"sixsuperior",
"sevensuperior",
"eightsuperior",
"ninesuperior",
"zeroinferior",
"oneinferior",
"twoinferior",
"threeinferior",
"fourinferior",
"fiveinferior",
"sixinferior",
"seveninferior",
"eightinferior",
"nineinferior",
"centinferior",
"dollarinferior",
"periodinferior",
"commainferior",
"Agravesmall",
"Aacutesmall",
"Acircumflexsmall",
"Atildesmall",
"Adieresissmall",
"Aringsmall",
"AEsmall",
"Ccedillasmall",
"Egravesmall",
"Eacutesmall",
"Ecircumflexsmall",
"Edieresissmall",
"Igravesmall",
"Iacutesmall",
"Icircumflexsmall",
"Idieresissmall",
"Ethsmall",
"Ntildesmall",
"Ogravesmall",
"Oacutesmall",
"Ocircumflexsmall",
"Otildesmall",
"Odieresissmall",
"OEsmall",
"Oslashsmall",
"Ugravesmall",
"Uacutesmall",
"Ucircumflexsmall",
"Udieresissmall",
"Yacutesmall",
"Thornsmall",
"Ydieresissmall"
];
class Glyph {
index;
name;
isComposite = false;
components = [];
pathCommands = [];
constructor(options) {
const config = { ...options };
this.index = config.index ?? 0;
if (config.name === ".notdef") {
config.unicode = void 0;
} else if (config.name === ".null") {
config.unicode = 0;
}
if (config.unicode === 0 && config.name !== ".null") {
throw new Error('The unicode value "0" is reserved for the glyph name ".null" and cannot be used by any other glyph.');
}
this.name = config.name ?? null;
if (config.unicode) {
this.unicode = config.unicode;
}
if (config.unicodes) {
this.unicodes = config.unicodes;
} else if (config.unicode) {
this.unicodes = [config.unicode];
}
}
getPathCommands(x = 0, y = 0, fontSize = 72, options = {}, sfnt) {
const scale = 1 / (sfnt?.unitsPerEm ?? 1e3) * fontSize;
const { xScale = scale, yScale = scale } = options;
const pathCommands = this.pathCommands;
const commands = [];
for (let i = 0, len = pathCommands.length; i < len; i += 1) {
const cmd = pathCommands[i];
if (cmd.type === "M") {
commands.push({ type: "M", x: x + cmd.x * xScale, y: y + -cmd.y * yScale });
} else if (cmd.type === "L") {
commands.push({ type: "L", x: x + cmd.x * xScale, y: y + -cmd.y * yScale });
} else if (cmd.type === "Q") {
commands.push({ type: "Q", x1: x + cmd.x1 * xScale, y1: y + -cmd.y1 * yScale, x: x + cmd.x * xScale, y: y + -cmd.y * yScale });
} else if (cmd.type === "C") {
commands.push({ type: "C", x1: x + cmd.x1 * xScale, y1: y + -cmd.y1 * yScale, x2: x + cmd.x2 * xScale, y2: y + -cmd.y2 * yScale, x: x + cmd.x * xScale, y: y + -cmd.y * yScale });
} else if (cmd.type === "Z") {
commands.push({ type: "Z" });
}
}
return commands;
}
}
class CffGlyph extends Glyph {
parse(cff, code, glyphs) {
const self = this;
const { nominalWidthX, defaultWidthX, gsubrsBias, subrsBias } = cff;
const paintType = cff.topDict.paintType;
const index = this.index;
let c1x;
let c1y;
let c2x;
let c2y;
const pathCommands = [];
const stack = [];
let nStems = 0;
let haveWidth = false;
let open = false;
let width = defaultWidthX;
let x = 0;
let y = 0;
function lineTo(x2, y2) {
pathCommands.push({ type: "L", x: x2, y: y2 });
}
function curveTo(c1x2, c1y2, c2x2, c2y2, x2, y2) {
pathCommands.push({ type: "C", x1: c1x2, y1: c1y2, x2: c2x2, y2: c2y2, x: x2, y: y2 });
}
function moveTo(x2, y2) {
if (open && paintType !== 2) {
closePath();
}
open = true;
pathCommands.push({ type: "M", x: x2, y: y2 });
}
function closePath() {
pathCommands.push({ type: "Z" });
}
function extend(commands) {
pathCommands.push(...commands);
}
function parseStems() {
const hasWidthArg = stack.length % 2 !== 0;
if (hasWidthArg && !haveWidth) {
width = stack.shift() + nominalWidthX;
}
nStems += stack.length >> 1;
stack.length = 0;
haveWidth = true;
}
function parse(code2) {
let b1;
let b2;
let b3;
let b4;
let codeIndex;
let subrCode;
let jpx;
let jpy;
let c3x;
let c3y;
let c4x;
let c4y;
let i = 0;
while (i < code2.length) {
let v = code2[i++];
switch (v) {
case 1:
parseStems();
break;
case 3:
parseStems();
break;
case 4:
if (stack.length > 1 && !haveWidth) {
width = stack.shift() + nominalWidthX;
haveWidth = true;
}
y += stack.pop();
moveTo(x, y);
break;
case 5:
while (stack.length > 0) {
x += stack.shift();
y += stack.shift();
lineTo(x, y);
}
break;
case 6:
while (stack.length > 0) {
x += stack.shift();
lineTo(x, y);
if (stack.length === 0) {
break;
}
y += stack.shift();
lineTo(x, y);
}
break;
case 7:
while (stack.length > 0) {
y += stack.shift();
lineTo(x, y);
if (stack.length === 0) {
break;
}
x += stack.shift();
lineTo(x, y);
}
break;
case 8:
while (stack.length > 0) {
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + stack.shift();
curveTo(c1x, c1y, c2x, c2y, x, y);
}
break;
case 10:
codeIndex = stack.pop() + subrsBias;
subrCode = cff.subrs[codeIndex];
if (subrCode) {
parse(subrCode);
}
break;
case 11:
return;
case 12:
v = code2[i];
i += 1;
switch (v) {
case 35:
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
jpx = c2x + stack.shift();
jpy = c2y + stack.shift();
c3x = jpx + stack.shift();
c3y = jpy + stack.shift();
c4x = c3x + stack.shift();
c4y = c3y + stack.shift();
x = c4x + stack.shift();
y = c4y + stack.shift();
stack.shift();
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
curveTo(c3x, c3y, c4x, c4y, x, y);
break;
case 34:
c1x = x + stack.shift();
c1y = y;
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
jpx = c2x + stack.shift();
jpy = c2y;
c3x = jpx + stack.shift();
c3y = c2y;
c4x = c3x + stack.shift();
c4y = y;
x = c4x + stack.shift();
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
curveTo(c3x, c3y, c4x, c4y, x, y);
break;
case 36:
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
jpx = c2x + stack.shift();
jpy = c2y;
c3x = jpx + stack.shift();
c3y = c2y;
c4x = c3x + stack.shift();
c4y = c3y + stack.shift();
x = c4x + stack.shift();
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
curveTo(c3x, c3y, c4x, c4y, x, y);
break;
case 37:
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
jpx = c2x + stack.shift();
jpy = c2y + stack.shift();
c3x = jpx + stack.shift();
c3y = jpy + stack.shift();
c4x = c3x + stack.shift();
c4y = c3y + stack.shift();
if (Math.abs(c4x - x) > Math.abs(c4y - y)) {
x = c4x + stack.shift();
} else {
y = c4y + stack.shift();
}
curveTo(c1x, c1y, c2x, c2y, jpx, jpy);
curveTo(c3x, c3y, c4x, c4y, x, y);
break;
default:
console.warn(`Glyph ${index}: unknown operator ${1200 + v}`);
stack.length = 0;
}
break;
case 14:
if (stack.length >= 4) {
const acharName = cffStandardEncoding[stack.pop()];
const bcharName = cffStandardEncoding[stack.pop()];
const ady = stack.pop();
const adx = stack.pop();
if (acharName && bcharName) {
self.isComposite = true;
self.components = [];
const acharGlyphIndex = cff.charset.indexOf(acharName);
const bcharGlyphIndex = cff.charset.indexOf(bcharName);
self.components.push({
glyphIndex: bcharGlyphIndex,
dx: 0,
dy: 0
});
self.components.push({
glyphIndex: acharGlyphIndex,
dx: adx,
dy: ady
});
extend(glyphs.get(bcharGlyphIndex).pathCommands);
const shiftedCommands = JSON.parse(JSON.stringify(glyphs.get(acharGlyphIndex).pathCommands));
for (let i2 = 0; i2 < shiftedCommands.length; i2 += 1) {
const cmd = shiftedCommands[i2];
if (cmd.type !== "Z") {
cmd.x += adx;
cmd.y += ady;
}
if (cmd.type === "Q" || cmd.type === "C") {
cmd.x1 += adx;
cmd.y1 += ady;
}
if (cmd.type === "C") {
cmd.x2 += adx;
cmd.y2 += ady;
}
}
extend(shiftedCommands);
}
} else if (stack.length > 0 && !haveWidth) {
width = stack.shift() + nominalWidthX;
haveWidth = true;
}
if (open && paintType !== 2) {
closePath();
open = false;
}
break;
case 18:
parseStems();
break;
case 19:
// hintmask
case 20:
parseStems();
i += nStems + 7 >> 3;
break;
case 21:
if (stack.length > 2 && !haveWidth) {
width = stack.shift() + nominalWidthX;
haveWidth = true;
}
y += stack.pop();
x += stack.pop();
moveTo(x, y);
break;
case 22:
if (stack.length > 1 && !haveWidth) {
width = stack.shift() + nominalWidthX;
haveWidth = true;
}
x += stack.pop();
moveTo(x, y);
break;
case 23:
parseStems();
break;
case 24:
while (stack.length > 2) {
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + stack.shift();
curveTo(c1x, c1y, c2x, c2y, x, y);
}
x += stack.shift();
y += stack.shift();
lineTo(x, y);
break;
case 25:
while (stack.length > 6) {
x += stack.shift();
y += stack.shift();
lineTo(x, y);
}
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + stack.shift();
curveTo(c1x, c1y, c2x, c2y, x, y);
break;
case 26:
if (stack.length % 2) {
x += stack.shift();
}
while (stack.length > 0) {
c1x = x;
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x;
y = c2y + stack.shift();
curveTo(c1x, c1y, c2x, c2y, x, y);
}
break;
case 27:
if (stack.length % 2) {
y += stack.shift();
}
while (stack.length > 0) {
c1x = x + stack.shift();
c1y = y;
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y;
curveTo(c1x, c1y, c2x, c2y, x, y);
}
break;
case 28:
b1 = code2[i];
b2 = code2[i + 1];
stack.push((b1 << 24 | b2 << 16) >> 16);
i += 2;
break;
case 29:
codeIndex = stack.pop() + gsubrsBias;
subrCode = cff.gsubrs[codeIndex];
if (subrCode) {
parse(subrCode);
}
break;
case 30:
while (stack.length > 0) {
c1x = x;
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + (stack.length === 1 ? stack.shift() : 0);
curveTo(c1x, c1y, c2x, c2y, x, y);
if (stack.length === 0) {
break;
}
c1x = x + stack.shift();
c1y = y;
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
y = c2y + stack.shift();
x = c2x + (stack.length === 1 ? stack.shift() : 0);
curveTo(c1x, c1y, c2x, c2y, x, y);
}
break;
case 31:
while (stack.length > 0) {
c1x = x + stack.shift();
c1y = y;
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
y = c2y + stack.shift();
x = c2x + (stack.length === 1 ? stack.shift() : 0);
curveTo(c1x, c1y, c2x, c2y, x, y);
if (stack.length === 0) {
break;
}
c1x = x;
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + (stack.length === 1 ? stack.shift() : 0);
curveTo(c1x, c1y, c2x, c2y, x, y);
}
break;
default:
if (v < 32) {
console.warn(`Glyph ${index}: unknown operator ${v}`);
} else if (v < 247) {
stack.push(v - 139);
} else if (v < 251) {
b1 = code2[i];
i += 1;
stack.push((v - 247) * 256 + b1 + 108);
} else if (v < 255) {
b1 = code2[i];
i += 1;
stack.push(-(v - 251) * 256 - b1 - 108);
} else {
b1 = code2[i];
b2 = code2[i + 1];
b3 = code2[i + 2];
b4 = code2[i + 3];
i += 4;
stack.push((b1 << 24 | b2 << 16 | b3 << 8 | b4) / 65536);
}
}
}
}
parse(code);
this.pathCommands = pathCommands;
if (haveWidth) {
this.advanceWidth = width;
}
}
}
class GlyphSet {
constructor(_sfnt) {
this._sfnt = _sfnt;
}
_items = [];
get(index) {
const _glyph = this._items[index];
let glyph;
if (_glyph) {
glyph = _glyph;
} else {
glyph = this._get(index);
const metric = this._sfnt.hmtx.metrics[index];
if (metric) {
glyph.advanceWidth = glyph.advanceWidth || metric.advanceWidth;
glyph.leftSideBearing = glyph.leftSideBearing || metric.leftSideBearing;
}
const unicodes = this._sfnt.cmap.glyphIndexToUnicodesMap.get(index);
if (unicodes) {
glyph.unicode ??= unicodes[0];
glyph.unicodes ??= unicodes;
}
this._items[index] = glyph;
}
return glyph;
}
}
class CffGlyphSet extends GlyphSet {
get length() {
return this._sfnt.cff.charStringsIndex.offsets.length - 1;
}
_get(index) {
const cff = this._sfnt.cff;
const glyph = new CffGlyph({ index });
glyph.parse(cff, cff.charStringsIndex.get(index), this);
glyph.name = cff.charset[index];
return glyph;
}
}
var __defProp$l = Object.defineProperty;
var __decorateClass$r = (decorators, target, key, kind) => {
var result = void 0 ;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (decorator(target, key, result) ) || result;
if (result) __defProp$l(target, key, result);
return result;
};
class CffIndex extends FontDataObject {
_offsets;
get offsets() {
return this._offsets ??= this.readOffsets();
}
_objects;
get objects() {
return this._objects ??= this.readObjects();
}
constructor(source, byteOffset, byteLength, littleEndian) {
super(source, byteOffset, byteLength, littleEndian);
this._init();
}
_init() {
const reader = this.view;
const count = this.count;
const offsetSize = this.offsetSize;
this.objectOffset = (count + 1) * offsetSize + 2;
this.endOffset = reader.byteOffset + this.objectOffset + this.offsets[count];
}
readOffsets() {
const reader = this.view;
const count = this.count;
const offsetSize = this.offsetSize;
reader.seek(3);
const offsets = [];
for (let i = 0, l = count + 1; i < l; i++) {
const reader2 = this.view;
let v = 0;
for (let i2 = 0; i2 < offsetSize; i2++) {
v <<= 8;
v += reader2.readUint8();
}
offsets.push(v);
}
return offsets;
}
readObjects() {
const objects = [];
for (let i = 0, len = this.count; i < len; i++) {
objects.push(this.get(i));
}
return objects;
}
get(index) {
const offsets = this.offsets;
const objectOffset = this.objectOffset;
const start = objectOffset + offsets[index];
const end = objectOffset + offsets[index + 1];
const len = end - start;
if (this._isString) {
return this.view.readString(start, len);
} else {
return this.view.readBytes(start, len);
}
}
}
__decorateClass$r([
defineColumn("uint16")
], CffIndex.prototype, "count");
__decorateClass$r([
defineColumn("uint8")
], CffIndex.prototype, "offsetSize");
class CffNumberIndex extends CffIndex {
_isString = false;
}
class CffStringIndex extends CffIndex {
_isString = true;
}
const cffStandardStrings = [
".notdef",
"space",
"exclam",
"quotedbl",
"numbersign",
"dollar",
"percent",
"ampersand",
"quoteright",
"parenleft",
"parenright",
"asterisk",
"plus",
"comma",
"hyphen",
"period",
"slash",
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"colon",
"semicolon",
"less",
"equal",
"greater",
"question",
"at",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"bracketleft",
"backslash",
"bracketright",
"asciicircum",
"underscore",
"quoteleft",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"braceleft",
"bar",
"braceright",
"asciitilde",
"exclamdown",
"cent",
"sterling",
"fraction",
"yen",
"florin",
"section",
"currency",
"quotesingle",
"quotedblleft",
"guillemotleft",
"guilsinglleft",
"guilsinglright",
"fi",
"fl",
"endash",
"dagger",
"daggerdbl",
"periodcentered",
"paragraph",
"bullet",
"quotesinglbase",
"quotedblbase",
"quotedblright",
"guillemotright",
"ellipsis",
"perthousand",
"questiondown",
"grave",
"acute",
"circumflex",
"tilde",
"macron",
"breve",
"dotaccent",
"dieresis",
"ring",
"cedilla",
"hungarumlaut",
"ogonek",
"caron",
"emdash",
"AE",
"ordfeminine",
"Lslash",
"Oslash",
"OE",
"ordmasculine",
"ae",
"dotlessi",
"lslash",
"oslash",
"oe",
"germandbls",
"onesuperior",
"logicalnot",
"mu",
"trademark",
"Eth",
"onehalf",
"plusminus",
"Thorn",
"onequarter",
"divide",
"brokenbar",
"degree",
"thorn",
"threequarters",
"twosuperior",
"registered",
"minus",
"eth",
"multiply",
"threesuperior",
"copyright",
"Aacute",
"Acircumflex",
"Adieresis",
"Agrave",
"Aring",
"Atilde",
"Ccedilla",
"Eacute",
"Ecircumflex",
"Edieresis",
"Egrave",
"Iacute",
"Icircumflex",
"Idieresis",
"Igrave",
"Ntilde",
"Oacute",
"Ocircumflex",
"Odieresis",
"Ograve",
"Otilde",
"Scaron",
"Uacute",
"Ucircumflex",
"Udieresis",
"Ugrave",
"Yacute",
"Ydieresis",
"Zcaron",
"aacute",
"acircumflex",
"adieresis",
"agrave",
"aring",
"atilde",
"ccedilla",
"eacute",
"ecircumflex",
"edieresis",
"egrave",
"iacute",
"icircumflex",
"idieresis",
"igrave",
"ntilde",
"oacute",
"ocircumflex",
"odieresis",
"ograve",
"otilde",
"scaron",
"uacute",
"ucircumflex",
"udieresis",
"ugrave",
"yacute",
"ydieresis",
"zcaron",
"exclamsmall",
"Hungarumlautsmall",
"dollaroldstyle",
"dollarsuperior",
"ampersandsmall",
"Acutesmall",
"parenleftsuperior",
"parenrightsuperior",
"266 ff",
"onedotenleader",
"zerooldstyle",
"oneoldstyle",
"twooldstyle",
"threeoldstyle",
"fouroldstyle",
"fiveoldstyle",
"sixoldstyle",
"sevenoldstyle",
"eightoldstyle",
"nineoldstyle",
"commasuperior",
"threequartersemdash",
"periodsuperior",
"questionsmall",
"asuperior",
"bsuperior",
"centsuperior",
"dsuperior",
"esuperior",
"isuperior",
"lsuperior",
"msuperior",
"nsuperior",
"osuperior",
"rsuperior",
"ssuperior",
"tsuperior",
"ff",
"ffi",
"ffl",
"parenleftinferior",
"parenrightinferior",
"Circumflexsmall",
"hyphensuperior",
"Gravesmall",
"Asmall",
"Bsmall",
"Csmall",
"Dsmall",
"Esmall",
"Fsmall",
"Gsmall",
"Hsmall",
"Ismall",
"Jsmall",
"Ksmall",
"Lsmall",
"Msmall",
"Nsmall",
"Osmall",
"Psmall",
"Qsmall",
"Rsmall",
"Ssmall",
"Tsmall",
"Usmall",
"Vsmall",
"Wsmall",
"Xsmall",
"Ysmall",
"Zsmall",
"colonmonetary",
"onefitted",
"rupiah",
"Tildesmall",
"exclamdownsmall",
"centoldstyle",
"Lslashsmall",
"Scaronsmall",
"Zcaronsmall",
"Dieresissmall",
"Brevesmall",
"Caronsmall",
"Dotaccentsmall",
"Macronsmall",
"figuredash",
"hypheninferior",
"Ogoneksmall",
"Ringsmall",
"Cedillasmall",
"questiondownsmall",
"oneeighth",
"threeeighths",
"fiveeighths",
"seveneighths",
"onethird",
"twothirds",
"zerosuperior",
"foursuperior",
"fivesuperior",
"sixsuperior",
"sevensuperior",
"eightsuperior",
"ninesuperior",
"zeroinferior",
"oneinferior",
"twoinferior",
"threeinferior",
"fourinferior",
"fiveinferior",
"sixinferior",
"seveninferior",
"eightinferior",
"nineinferior",
"centinferior",
"dollarinferior",
"periodinferior",
"commainferior",
"Agravesmall",
"Aacutesmall",
"Acircumflexsmall",
"Atildesmall",
"Adieresissmall",
"Aringsmall",
"AEsmall",
"Ccedillasmall",
"Egravesmall",
"Eacutesmall",
"Ecircumflexsmall",
"Edieresissmall",
"Igravesmall",
"Iacutesmall",
"Icircumflexsmall",
"Idieresissmall",
"Ethsmall",
"Ntildesmall",
"Ogravesmall",
"Oacutesmall",
"Ocircumflexsmall",
"Otildesmall",
"Odieresissmall",
"OEsmall",
"Oslashsmall",
"Ugravesmall",
"Uacutesmall",
"Ucircumflexsmall",
"Udieresissmall",
"Yacutesmall",
"Thornsmall",
"Ydieresissmall",
"001.000",
"001.001",
"001.002",
"001.003",
"Black",
"Bold",
"Book",
"Light",
"Medium",
"Regular",
"Roman",
"Semibold"
];
const cffISOAdobeStrings = [
".notdef",
"space",
"exclam",
"quotedbl",
"numbersign",
"dollar",
"percent",
"ampersand",
"quoteright",
"parenleft",
"parenright",
"asterisk",
"plus",
"comma",
"hyphen",
"period",
"slash",
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"colon",
"semicolon",
"less",
"equal",
"greater",
"question",
"at",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"bracketleft",
"backslash",
"bracketright",
"asciicircum",
"underscore",
"quoteleft",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"braceleft",
"bar",
"braceright",
"asciitilde",
"exclamdown",
"cent",
"sterling",
"fraction",
"yen",
"florin",
"section",
"currency",
"quotesingle",
"quotedblleft",
"guillemotleft",
"guilsinglleft",
"guilsinglright",
"fi",
"fl",
"endash",
"dagger",
"daggerdbl",
"periodcentered",
"paragraph",
"bullet",
"quotesinglbase",
"quotedblbase",
"quotedblright",
"guillemotright",
"ellipsis",
"perthousand",
"questiondown",
"grave",
"acute",
"circumflex",
"tilde",
"macron",
"breve",
"dotaccent",
"dieresis",
"ring",
"cedilla",
"hungarumlaut",
"ogonek",
"caron",
"emdash",
"AE",
"ordfeminine",
"Lslash",
"Oslash",
"OE",
"ordmasculine",
"ae",
"dotlessi",
"lslash",
"oslash",
"oe",
"germandbls",
"onesuperior",
"logicalnot",
"mu",
"trademark",
"Eth",
"onehalf",
"plusminus",
"Thorn",
"onequarter",
"divide",
"brokenbar",
"degree",
"thorn",
"threequarters",
"twosuperior",
"registered",
"minus",
"eth",
"multiply",
"threesuperior",
"copyright",
"Aacute",
"Acircumflex",
"Adieresis",
"Agrave",
"Aring",
"Atilde",
"Ccedilla",
"Eacute",
"Ecircumflex",
"Edieresis",
"Egrave",
"Iacute",
"Icircumflex",
"Idieresis",
"Igrave",
"Ntilde",
"Oacute",
"Ocircumflex",
"Odieresis",
"Ograve",
"Otilde",
"Scaron",
"Uacute",
"Ucircumflex",
"Udieresis",
"Ugrave",
"Yacute",
"Ydieresis",
"Zcaron",
"aacute",
"acircumflex",
"adieresis",
"agrave",
"aring",
"atilde",
"ccedilla",
"eacute",
"ecircumflex",
"edieresis",
"egrave",
"iacute",
"icircumflex",
"idieresis",
"igrave",
"ntilde",
"oacute",
"ocircumflex",
"odieresis",
"ograve",
"otilde",
"scaron",
"uacute",
"ucircumflex",
"udieresis",
"ugrave",
"yacute",
"ydieresis",
"zcaron"
];
const cffIExpertStrings = [
".notdef",
"space",
"exclamsmall",
"Hungarumlautsmall",
"dollaroldstyle",
"dollarsuperior",
"ampersandsmall",
"Acutesmall",
"parenleftsuperior",
"parenrightsuperior",
"twodotenleader",
"onedotenleader",
"comma",
"hyphen",
"period",
"fraction",
"zerooldstyle",
"oneoldstyle",
"twooldstyle",
"threeoldstyle",
"fouroldstyle",
"fiveoldstyle",
"sixoldstyle",
"sevenoldstyle",
"eightoldstyle",
"nineoldstyle",
"colon",
"semicolon",
"commasuperior",
"threequartersemdash",
"periodsuperior",
"questionsmall",
"asuperior",
"bsuperior",
"centsuperior",
"dsuperior",
"esuperior",
"isuperior",
"lsuperior",
"msuperior",
"nsuperior",
"osuperior",
"rsuperior",
"ssuperior",
"tsuperior",
"ff",
"fi",
"fl",
"ffi",
"ffl",
"parenleftinferior",
"parenrightinferior",
"Circumflexsmall",
"hyphensuperior",
"Gravesmall",
"Asmall",
"Bsmall",
"Csmall",
"Dsmall",
"Esmall",
"Fsmall",
"Gsmall",
"Hsmall",
"Ismall",
"Jsmall",
"Ksmall",
"Lsmall",
"Msmall",
"Nsmall",
"Osmall",
"Psmall",
"Qsmall",
"Rsmall",
"Ssmall",
"Tsmall",
"Usmall",
"Vsmall",
"Wsmall",
"Xsmall",
"Ysmall",
"Zsmall",
"colonmonetary",
"onefitted",
"rupiah",
"Tildesmall",
"exclamdownsmall",
"centoldstyle",
"Lslashsmall",
"Scaronsmall",
"Zcaronsmall",
"Dieresissmall",
"Brevesmall",
"Caronsmall",
"Dotaccentsmall",
"Macronsmall",
"figuredash",
"hypheninferior",
"Ogoneksmall",
"Ringsmall",
"Cedillasmall",
"onequarter",
"onehalf",
"threequarters",
"questiondownsmall",
"oneeighth",
"threeeighths",
"fiveeighths",
"seveneighths",
"onethird",
"twothirds",
"zerosuperior",
"onesuperior",
"twosuperior",
"threesuperior",
"foursuperior",
"fivesuperior",
"sixsuperior",
"sevensuperior",
"eightsuperior",
"ninesuperior",
"zeroinferior",
"oneinferior",
"twoinferior",
"threeinferior",
"fourinferior",
"fiveinferior",
"sixinferior",
"seveninferior",
"eightinferior",
"nineinferior",
"centinferior",
"dollarinferior",
"periodinferior",
"commainferior",
"Agravesmall",
"Aacutesmall",
"Acircumflexsmall",
"Atildesmall",
"Adieresissmall",
"Aringsmall",
"AEsmall",
"Ccedillasmall",
"Egravesmall",
"Eacutesmall",
"Ecircumflexsmall",
"Edieresissmall",
"Igravesmall",
"Iacutesmall",
"Icircumfle