mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-06-26 10:05:47 +02:00
Add a helper class for building TrueType font tables
This helps reduce the amount of boilerplate code needed in multiple spots throughout the font code, and more importantly it'll help when building TrueType tables whose final size is non-trivial to compute upfront.
This commit is contained in:
parent
7f7ac949ff
commit
f9ecebe63c
@ -313,43 +313,110 @@ function string16(value) {
|
|||||||
return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
|
return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setArray(data, pos, arr) {
|
class TrueTypeTableBuilder {
|
||||||
data.set(arr, pos);
|
#buf;
|
||||||
return pos + arr.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setInt16(view, pos, val) {
|
#bufLength = 1024;
|
||||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
||||||
assert(
|
|
||||||
typeof val === "number" && Math.abs(val) < 2 ** 16,
|
|
||||||
`setInt16: Unexpected input "${val}".`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
view.setInt16(pos, val);
|
|
||||||
return pos + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSafeInt16(view, pos, val) {
|
#hasExactLength = false;
|
||||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
||||||
assert(
|
|
||||||
typeof val === "number" && !Number.isNaN(val),
|
|
||||||
`safeString16: Unexpected input "${val}".`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// clamp value to the 16-bit int range
|
|
||||||
view.setInt16(pos, MathClamp(val, -0x8000, 0x7fff));
|
|
||||||
return pos + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setInt32(view, pos, val) {
|
#pos = 0;
|
||||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
||||||
assert(
|
#view;
|
||||||
typeof val === "number" && Math.abs(val) < 2 ** 32,
|
|
||||||
`setInt32: Unexpected input "${val}".`
|
constructor({ exactLength, minLength }) {
|
||||||
);
|
this.#hasExactLength = !!exactLength;
|
||||||
|
this.#initBuf(exactLength || minLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
#initBuf(minLength) {
|
||||||
|
if (this.#hasExactLength) {
|
||||||
|
this.#bufLength = minLength;
|
||||||
|
} else {
|
||||||
|
// Compute the first power of two that is as big as the `minLength`.
|
||||||
|
while (this.#bufLength < minLength) {
|
||||||
|
this.#bufLength *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const newBuf = new Uint8Array(this.#bufLength);
|
||||||
|
|
||||||
|
if (this.#buf) {
|
||||||
|
newBuf.set(this.#buf, 0);
|
||||||
|
}
|
||||||
|
this.#buf = newBuf;
|
||||||
|
this.#view = new DataView(newBuf.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
get data() {
|
||||||
|
return this.#buf.subarray(0, this.#pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
get length() {
|
||||||
|
return this.#pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
skip(n) {
|
||||||
|
this.#pos += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
setArray(arr) {
|
||||||
|
const newPos = this.#pos + arr.length;
|
||||||
|
|
||||||
|
if (!this.#hasExactLength && newPos > this.#bufLength) {
|
||||||
|
this.#initBuf(newPos);
|
||||||
|
}
|
||||||
|
this.#buf.set(arr, this.#pos);
|
||||||
|
this.#pos = newPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
setInt16(val) {
|
||||||
|
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
||||||
|
assert(
|
||||||
|
typeof val === "number" && Math.abs(val) < 2 ** 16,
|
||||||
|
`setInt16: Unexpected input "${val}".`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const newPos = this.#pos + 2;
|
||||||
|
|
||||||
|
if (!this.#hasExactLength && newPos > this.#bufLength) {
|
||||||
|
this.#initBuf(newPos);
|
||||||
|
}
|
||||||
|
this.#view.setInt16(this.#pos, val);
|
||||||
|
this.#pos = newPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSafeInt16(val) {
|
||||||
|
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
||||||
|
assert(
|
||||||
|
typeof val === "number" && !Number.isNaN(val),
|
||||||
|
`safeString16: Unexpected input "${val}".`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const newPos = this.#pos + 2;
|
||||||
|
|
||||||
|
if (!this.#hasExactLength && newPos > this.#bufLength) {
|
||||||
|
this.#initBuf(newPos);
|
||||||
|
}
|
||||||
|
// clamp value to the 16-bit int range
|
||||||
|
this.#view.setInt16(this.#pos, MathClamp(val, -0x8000, 0x7fff));
|
||||||
|
this.#pos = newPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
setInt32(val) {
|
||||||
|
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
||||||
|
assert(
|
||||||
|
typeof val === "number" && Math.abs(val) < 2 ** 32,
|
||||||
|
`setInt32: Unexpected input "${val}".`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const newPos = this.#pos + 4;
|
||||||
|
|
||||||
|
if (!this.#hasExactLength && newPos > this.#bufLength) {
|
||||||
|
this.#initBuf(newPos);
|
||||||
|
}
|
||||||
|
this.#view.setInt32(this.#pos, val);
|
||||||
|
this.#pos = newPos;
|
||||||
}
|
}
|
||||||
view.setInt32(pos, val);
|
|
||||||
return pos + 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isTrueTypeFile(file) {
|
function isTrueTypeFile(file) {
|
||||||
@ -856,27 +923,24 @@ function createOS2Table(properties, charstrings, override) {
|
|||||||
const winAscent = override.yMax || typoAscent;
|
const winAscent = override.yMax || typoAscent;
|
||||||
const winDescent = -override.yMin || -typoDescent;
|
const winDescent = -override.yMin || -typoDescent;
|
||||||
|
|
||||||
const data = new Uint8Array(96),
|
const os2 = new TrueTypeTableBuilder({ exactLength: 96 });
|
||||||
view = new DataView(data.buffer);
|
os2.setArray([0x00, 0x03]); // version
|
||||||
let pos = 0;
|
os2.setArray([0x02, 0x24]); // xAvgCharWidth
|
||||||
|
os2.setArray([0x01, 0xf4]); // usWeightClass
|
||||||
pos = setArray(data, pos, [0x00, 0x03]); // version
|
os2.setArray([0x00, 0x05]); // usWidthClass
|
||||||
pos = setArray(data, pos, [0x02, 0x24]); // xAvgCharWidth
|
os2.skip(2); // fstype (0 to improve browser compatibility), skip redundant "\x00\x00"
|
||||||
pos = setArray(data, pos, [0x01, 0xf4]); // usWeightClass
|
os2.setArray([0x02, 0x8a]); // ySubscriptXSize
|
||||||
pos = setArray(data, pos, [0x00, 0x05]); // usWidthClass
|
os2.setArray([0x02, 0xbb]); // ySubscriptYSize
|
||||||
pos += 2; // fstype (0 to improve browser compatibility), skip redundant "\x00\x00"
|
os2.skip(2); // ySubscriptXOffset, skip redundant "\x00\x00"
|
||||||
pos = setArray(data, pos, [0x02, 0x8a]); // ySubscriptXSize
|
os2.setArray([0x00, 0x8c]); // ySubscriptYOffset
|
||||||
pos = setArray(data, pos, [0x02, 0xbb]); // ySubscriptYSize
|
os2.setArray([0x02, 0x8a]); // ySuperScriptXSize
|
||||||
pos += 2; // ySubscriptXOffset, skip redundant "\x00\x00"
|
os2.setArray([0x02, 0xbb]); // ySuperScriptYSize
|
||||||
pos = setArray(data, pos, [0x00, 0x8c]); // ySubscriptYOffset
|
os2.skip(2); // ySuperScriptXOffset, skip redundant "\x00\x00"
|
||||||
pos = setArray(data, pos, [0x02, 0x8a]); // ySuperScriptXSize
|
os2.setArray([0x01, 0xdf]); // ySuperScriptYOffset
|
||||||
pos = setArray(data, pos, [0x02, 0xbb]); // ySuperScriptYSize
|
os2.setArray([0x00, 0x31]); // yStrikeOutSize
|
||||||
pos += 2; // ySuperScriptXOffset, skip redundant "\x00\x00"
|
os2.setArray([0x01, 0x02]); // yStrikeOutPosition
|
||||||
pos = setArray(data, pos, [0x01, 0xdf]); // ySuperScriptYOffset
|
os2.skip(2); // sFamilyClass, skip redundant "\x00\x00"
|
||||||
pos = setArray(data, pos, [0x00, 0x31]); // yStrikeOutSize
|
os2.setArray([
|
||||||
pos = setArray(data, pos, [0x01, 0x02]); // yStrikeOutPosition
|
|
||||||
pos += 2; // sFamilyClass, skip redundant "\x00\x00"
|
|
||||||
pos = setArray(data, pos, [
|
|
||||||
0x00,
|
0x00,
|
||||||
0x00,
|
0x00,
|
||||||
0x06,
|
0x06,
|
||||||
@ -888,46 +952,47 @@ function createOS2Table(properties, charstrings, override) {
|
|||||||
0x00,
|
0x00,
|
||||||
0x00,
|
0x00,
|
||||||
]); // Panose
|
]); // Panose
|
||||||
pos = setInt32(view, pos, ulUnicodeRange1); // ulUnicodeRange1 (Bits 0-31)
|
os2.setInt32(ulUnicodeRange1); // ulUnicodeRange1 (Bits 0-31)
|
||||||
pos = setInt32(view, pos, ulUnicodeRange2); // ulUnicodeRange2 (Bits 32-63)
|
os2.setInt32(ulUnicodeRange2); // ulUnicodeRange2 (Bits 32-63)
|
||||||
pos = setInt32(view, pos, ulUnicodeRange3); // ulUnicodeRange3 (Bits 64-95)
|
os2.setInt32(ulUnicodeRange3); // ulUnicodeRange3 (Bits 64-95)
|
||||||
pos = setInt32(view, pos, ulUnicodeRange4); // ulUnicodeRange4 (Bits 96-127)
|
os2.setInt32(ulUnicodeRange4); // ulUnicodeRange4 (Bits 96-127)
|
||||||
pos = setArray(data, pos, [0x2a, 0x32, 0x31, 0x2a]); // achVendID
|
os2.setArray([0x2a, 0x32, 0x31, 0x2a]); // achVendID
|
||||||
pos = setInt16(view, pos, properties.italicAngle ? 1 : 0); // fsSelection
|
os2.setInt16(properties.italicAngle ? 1 : 0); // fsSelection
|
||||||
pos = setInt16(view, pos, firstCharIndex || properties.firstChar); // usFirstCharIndex
|
os2.setInt16(firstCharIndex || properties.firstChar); // usFirstCharIndex
|
||||||
pos = setInt16(view, pos, lastCharIndex || properties.lastChar); // usLastCharIndex
|
os2.setInt16(lastCharIndex || properties.lastChar); // usLastCharIndex
|
||||||
pos = setInt16(view, pos, typoAscent); // sTypoAscender
|
os2.setInt16(typoAscent); // sTypoAscender
|
||||||
pos = setInt16(view, pos, typoDescent); // sTypoDescender
|
os2.setInt16(typoDescent); // sTypoDescender
|
||||||
pos = setArray(data, pos, [0x00, 0x64]); // sTypoLineGap (7%-10% of the unitsPerEM value)
|
os2.setArray([0x00, 0x64]); // sTypoLineGap (7%-10% of the unitsPerEM value)
|
||||||
pos = setInt16(view, pos, winAscent); // usWinAscent
|
os2.setInt16(winAscent); // usWinAscent
|
||||||
pos = setInt16(view, pos, winDescent); // usWinDescent
|
os2.setInt16(winDescent); // usWinDescent
|
||||||
pos += 4; // ulCodePageRange1 (Bits 0-31), skip redundant "\x00\x00\x00\x00"
|
os2.skip(
|
||||||
pos += 4; // ulCodePageRange2 (Bits 32-63), skip redundant "\x00\x00\x00\x00"
|
4 + // ulCodePageRange1 (Bits 0-31), skip redundant "\x00\x00\x00\x00"
|
||||||
pos = setInt16(view, pos, properties.xHeight); // sxHeight
|
4 // ulCodePageRange2 (Bits 32-63), skip redundant "\x00\x00\x00\x00"
|
||||||
pos = setInt16(view, pos, properties.capHeight); // sCapHeight
|
);
|
||||||
pos += 2; // usDefaultChar, skip redundant "\x00\x00"
|
os2.setInt16(properties.xHeight); // sxHeight
|
||||||
pos = setInt16(view, pos, firstCharIndex || properties.firstChar); // usBreakChar
|
os2.setInt16(properties.capHeight); // sCapHeight
|
||||||
setArray(data, pos, [0x00, 0x03]); // usMaxContext
|
os2.skip(2); // usDefaultChar, skip redundant "\x00\x00"
|
||||||
|
os2.setInt16(firstCharIndex || properties.firstChar); // usBreakChar
|
||||||
return data;
|
os2.setArray([0x00, 0x03]); // usMaxContext
|
||||||
|
return os2.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPostTable(properties) {
|
function createPostTable(properties) {
|
||||||
const data = new Uint8Array(32),
|
const post = new TrueTypeTableBuilder({ exactLength: 32 });
|
||||||
view = new DataView(data.buffer);
|
post.setArray([0x00, 0x03, 0x00, 0x00]); // Version number
|
||||||
let pos = 0;
|
post.setInt32(Math.floor(properties.italicAngle * 2 ** 16)); // italicAngle
|
||||||
|
post.skip(
|
||||||
pos = setArray(data, pos, [0x00, 0x03, 0x00, 0x00]); // Version number
|
2 + // underlinePosition, skip redundant "\x00\x00"
|
||||||
pos = setInt32(view, pos, Math.floor(properties.italicAngle * 2 ** 16)); // italicAngle
|
2 // underlineThickness, skip redundant "\x00\x00"
|
||||||
pos += 2; // underlinePosition, skip redundant "\x00\x00"
|
);
|
||||||
pos += 2; // underlineThickness, skip redundant "\x00\x00"
|
post.setInt32(properties.fixedPitch ? 1 : 0); // isFixedPitch
|
||||||
setInt32(view, pos, properties.fixedPitch ? 1 : 0); // isFixedPitch
|
post.skip(
|
||||||
// minMemType42, skip redundant "\x00\x00\x00\x00"
|
4 + // minMemType42, skip redundant "\x00\x00\x00\x00"
|
||||||
// maxMemType42, skip redundant "\x00\x00\x00\x00"
|
4 + // maxMemType42, skip redundant "\x00\x00\x00\x00"
|
||||||
// minMemType1, skip redundant "\x00\x00\x00\x00"
|
4 + // minMemType1, skip redundant "\x00\x00\x00\x00"
|
||||||
// maxMemType1, skip redundant "\x00\x00\x00\x00"
|
4 // maxMemType1, skip redundant "\x00\x00\x00\x00"
|
||||||
|
);
|
||||||
return data;
|
return post.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPostscriptName(name) {
|
function createPostscriptName(name) {
|
||||||
@ -3299,29 +3364,28 @@ class Font {
|
|||||||
"head",
|
"head",
|
||||||
(function fontTableHead() {
|
(function fontTableHead() {
|
||||||
const dateArr = [0x00, 0x00, 0x00, 0x00, 0x9e, 0x0b, 0x7e, 0x27];
|
const dateArr = [0x00, 0x00, 0x00, 0x00, 0x9e, 0x0b, 0x7e, 0x27];
|
||||||
const data = new Uint8Array(54),
|
|
||||||
view = new DataView(data.buffer);
|
|
||||||
let pos = 0;
|
|
||||||
|
|
||||||
pos = setArray(data, pos, [0x00, 0x01, 0x00, 0x00]); // Version number
|
const head = new TrueTypeTableBuilder({ exactLength: 54 });
|
||||||
pos = setArray(data, pos, [0x00, 0x00, 0x10, 0x00]); // fontRevision
|
head.setArray([0x00, 0x01, 0x00, 0x00]); // Version number
|
||||||
pos += 4; // checksumAdjustement, skip redundant "\x00\x00\x00\x00"
|
head.setArray([0x00, 0x00, 0x10, 0x00]); // fontRevision
|
||||||
pos = setArray(data, pos, [0x5f, 0x0f, 0x3c, 0xf5]); // magicNumber
|
head.skip(4); // checksumAdjustement, skip redundant "\x00\x00\x00\x00"
|
||||||
pos += 2; // Flags, skip redundant "\x00\x00"
|
head.setArray([0x5f, 0x0f, 0x3c, 0xf5]); // magicNumber
|
||||||
pos = setSafeInt16(view, pos, unitsPerEm); // unitsPerEM
|
head.skip(2); // Flags, skip redundant "\x00\x00"
|
||||||
pos = setArray(data, pos, dateArr); // creation date
|
head.setSafeInt16(unitsPerEm); // unitsPerEM
|
||||||
pos = setArray(data, pos, dateArr); // modifification date
|
head.setArray(dateArr); // creation date
|
||||||
pos += 2; // xMin, skip redundant "\x00\x00"
|
head.setArray(dateArr); // modifification date
|
||||||
pos = setSafeInt16(view, pos, properties.descent); // yMin
|
head.skip(2); // xMin, skip redundant "\x00\x00"
|
||||||
pos = setArray(data, pos, [0x0f, 0xff]); // xMax
|
head.setSafeInt16(properties.descent); // yMin
|
||||||
pos = setSafeInt16(view, pos, properties.ascent); // yMax
|
head.setArray([0x0f, 0xff]); // xMax
|
||||||
pos = setInt16(view, pos, properties.italicAngle ? 2 : 0); // macStyle
|
head.setSafeInt16(properties.ascent); // yMax
|
||||||
setArray(data, pos, [0x00, 0x11]); // lowestRecPPEM
|
head.setInt16(properties.italicAngle ? 2 : 0); // macStyle
|
||||||
// fontDirectionHint, skip redundant "\x00\x00"
|
head.setArray([0x00, 0x11]); // lowestRecPPEM
|
||||||
// indexToLocFormat, skip redundant "\x00\x00"
|
head.skip(
|
||||||
// glyphDataFormat, skip redundant "\x00\x00"
|
2 + // fontDirectionHint, skip redundant "\x00\x00"
|
||||||
|
2 + // indexToLocFormat, skip redundant "\x00\x00"
|
||||||
return data;
|
2 // glyphDataFormat, skip redundant "\x00\x00"
|
||||||
|
);
|
||||||
|
return head.data;
|
||||||
})()
|
})()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3329,33 +3393,31 @@ class Font {
|
|||||||
builder.addTable(
|
builder.addTable(
|
||||||
"hhea",
|
"hhea",
|
||||||
(function fontTableHhea() {
|
(function fontTableHhea() {
|
||||||
const data = new Uint8Array(36),
|
const hhea = new TrueTypeTableBuilder({ exactLength: 36 });
|
||||||
view = new DataView(data.buffer);
|
hhea.setArray([0x00, 0x01, 0x00, 0x00]); // Version number
|
||||||
let pos = 0;
|
hhea.setSafeInt16(properties.ascent); // Typographic Ascent
|
||||||
|
hhea.setSafeInt16(properties.descent); // Typographic Descent
|
||||||
pos = setArray(data, pos, [0x00, 0x01, 0x00, 0x00]); // Version number
|
hhea.skip(2); // Line Gap, skip redundant "\x00\x00"
|
||||||
pos = setSafeInt16(view, pos, properties.ascent); // Typographic Ascent
|
hhea.setArray([0xff, 0xff]); // advanceWidthMax
|
||||||
pos = setSafeInt16(view, pos, properties.descent); // Typographic Descent
|
hhea.skip(
|
||||||
pos += 2; // Line Gap, skip redundant "\x00\x00"
|
2 + // minLeftSidebearing, skip redundant "\x00\x00"
|
||||||
pos = setArray(data, pos, [0xff, 0xff]); // advanceWidthMax
|
2 + // minRightSidebearing, skip redundant "\x00\x00"
|
||||||
pos += 2; // minLeftSidebearing, skip redundant "\x00\x00"
|
2 // xMaxExtent, skip redundant "\x00\x00"
|
||||||
pos += 2; // minRightSidebearing, skip redundant "\x00\x00"
|
);
|
||||||
pos += 2; // xMaxExtent, skip redundant "\x00\x00"
|
hhea.setSafeInt16(properties.capHeight); // caretSlopeRise
|
||||||
pos = setSafeInt16(view, pos, properties.capHeight); // caretSlopeRise
|
hhea.setSafeInt16(
|
||||||
pos = setSafeInt16(
|
|
||||||
view,
|
|
||||||
pos,
|
|
||||||
Math.tan(properties.italicAngle) * properties.xHeight
|
Math.tan(properties.italicAngle) * properties.xHeight
|
||||||
); // caretSlopeRun
|
); // caretSlopeRun
|
||||||
pos += 2; // caretOffset, skip redundant "\x00\x00"
|
hhea.skip(
|
||||||
pos += 2; // -reserved-, skip redundant "\x00\x00"
|
2 + // caretOffset, skip redundant "\x00\x00"
|
||||||
pos += 2; // -reserved-, skip redundant "\x00\x00"
|
2 + // -reserved-, skip redundant "\x00\x00"
|
||||||
pos += 2; // -reserved-, skip redundant "\x00\x00"
|
2 + // -reserved-, skip redundant "\x00\x00"
|
||||||
pos += 2; // -reserved-, skip redundant "\x00\x00"
|
2 + // -reserved-, skip redundant "\x00\x00"
|
||||||
pos += 2; // metricDataFormat, skip redundant "\x00\x00"
|
2 + // -reserved-, skip redundant "\x00\x00"
|
||||||
setInt16(view, pos, numGlyphs); // Number of HMetrics
|
2 // metricDataFormat, skip redundant "\x00\x00"
|
||||||
|
);
|
||||||
return data;
|
hhea.setInt16(numGlyphs); // Number of HMetrics
|
||||||
|
return hhea.data;
|
||||||
})()
|
})()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3366,10 +3428,9 @@ class Font {
|
|||||||
const charstrings = font.charstrings;
|
const charstrings = font.charstrings;
|
||||||
const cffWidths = font.cff?.widths ?? null;
|
const cffWidths = font.cff?.widths ?? null;
|
||||||
|
|
||||||
const data = new Uint8Array(numGlyphs * 4),
|
const hmtx = new TrueTypeTableBuilder({ exactLength: numGlyphs * 4 });
|
||||||
view = new DataView(data.buffer);
|
|
||||||
// Fake .notdef (width=0 and lsb=0) first, skip redundant assignment.
|
// Fake .notdef (width=0 and lsb=0) first, skip redundant assignment.
|
||||||
let pos = 4;
|
hmtx.skip(4);
|
||||||
|
|
||||||
for (let i = 1, ii = numGlyphs; i < ii; i++) {
|
for (let i = 1, ii = numGlyphs; i < ii; i++) {
|
||||||
let width = 0;
|
let width = 0;
|
||||||
@ -3378,10 +3439,10 @@ class Font {
|
|||||||
} else if (cffWidths) {
|
} else if (cffWidths) {
|
||||||
width = Math.ceil(cffWidths[i] || 0);
|
width = Math.ceil(cffWidths[i] || 0);
|
||||||
}
|
}
|
||||||
pos = setInt16(view, pos, width);
|
hmtx.setInt16(width);
|
||||||
pos += 2; // Use lsb=0, skip redundant assignment.
|
hmtx.skip(2); // Use lsb=0, skip redundant assignment.
|
||||||
}
|
}
|
||||||
return data;
|
return hmtx.data;
|
||||||
})()
|
})()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3389,13 +3450,10 @@ class Font {
|
|||||||
builder.addTable(
|
builder.addTable(
|
||||||
"maxp",
|
"maxp",
|
||||||
(function fontTableMaxp() {
|
(function fontTableMaxp() {
|
||||||
const data = new Uint8Array(6),
|
const maxp = new TrueTypeTableBuilder({ exactLength: 6 });
|
||||||
view = new DataView(data.buffer);
|
maxp.setArray([0x00, 0x00, 0x50, 0x00]); // Version number
|
||||||
|
maxp.setInt16(numGlyphs); // Num of glyphs
|
||||||
setArray(data, 0, [0x00, 0x00, 0x50, 0x00]); // Version number
|
return maxp.data;
|
||||||
setInt16(view, 4, numGlyphs); // Num of glyphs
|
|
||||||
|
|
||||||
return data;
|
|
||||||
})()
|
})()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user