mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-06-04 01:01:00 +02:00
Merge pull request #21220 from Snuffleupagus/DataBuilder
Replace `TrueTypeTableBuilder` and `CompilerOutput` with a single class
This commit is contained in:
commit
e8d3d19f67
@ -28,6 +28,7 @@ import {
|
||||
ISOAdobeCharset,
|
||||
} from "./charsets.js";
|
||||
import { ExpertEncoding, StandardEncoding } from "./encodings.js";
|
||||
import { DataBuilder } from "./data_builder.js";
|
||||
|
||||
// Maximum subroutine call depth of type 2 charstrings. Matches OTS.
|
||||
const MAX_SUBR_NESTING = 10;
|
||||
@ -1365,51 +1366,6 @@ class CFFOffsetTracker {
|
||||
}
|
||||
}
|
||||
|
||||
class CompilerOutput {
|
||||
#buf;
|
||||
|
||||
#bufLength = 1024;
|
||||
|
||||
#pos = 0;
|
||||
|
||||
constructor(minLength) {
|
||||
// Note: Usually the compiled size is smaller than the initial data,
|
||||
// however in some cases it may increase slightly.
|
||||
this.#initBuf(minLength);
|
||||
}
|
||||
|
||||
#initBuf(minLength) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
get data() {
|
||||
return this.#buf.subarray(0, this.#pos);
|
||||
}
|
||||
|
||||
get length() {
|
||||
return this.#pos;
|
||||
}
|
||||
|
||||
add(data) {
|
||||
const newPos = this.#pos + data.length;
|
||||
if (newPos > this.#bufLength) {
|
||||
// It should be very rare that the buffer needs to grow.
|
||||
this.#initBuf(newPos);
|
||||
}
|
||||
this.#buf.set(data, this.#pos);
|
||||
this.#pos = newPos;
|
||||
}
|
||||
}
|
||||
|
||||
// Takes a CFF and converts it to the binary representation.
|
||||
class CFFCompiler {
|
||||
constructor(cff) {
|
||||
@ -1418,14 +1374,14 @@ class CFFCompiler {
|
||||
|
||||
compile() {
|
||||
const cff = this.cff;
|
||||
const output = new CompilerOutput(cff.rawFileLength);
|
||||
const output = new DataBuilder({ minLength: cff.rawFileLength });
|
||||
|
||||
// Compile the five entries that must be in order.
|
||||
const header = this.compileHeader(cff.header);
|
||||
output.add(header);
|
||||
output.setArray(header);
|
||||
|
||||
const nameIndex = this.compileNameIndex(cff.names);
|
||||
output.add(nameIndex);
|
||||
output.setArray(nameIndex);
|
||||
|
||||
if (cff.isCIDFont) {
|
||||
// The spec is unclear on how font matrices should relate to each other
|
||||
@ -1465,14 +1421,14 @@ class CFFCompiler {
|
||||
output.length,
|
||||
cff.isCIDFont
|
||||
);
|
||||
output.add(compiled.output);
|
||||
output.setArray(compiled.output);
|
||||
const topDictTracker = compiled.trackers[0];
|
||||
|
||||
const stringIndex = this.compileStringIndex(cff.strings.strings);
|
||||
output.add(stringIndex);
|
||||
output.setArray(stringIndex);
|
||||
|
||||
const globalSubrIndex = this.compileIndex(cff.globalSubrIndex);
|
||||
output.add(globalSubrIndex);
|
||||
output.setArray(globalSubrIndex);
|
||||
|
||||
// Now start on the other entries that have no specific order.
|
||||
if (cff.encoding && cff.topDict.hasName("Encoding")) {
|
||||
@ -1485,7 +1441,7 @@ class CFFCompiler {
|
||||
} else {
|
||||
const encoding = this.compileEncoding(cff.encoding);
|
||||
topDictTracker.setEntryLocation("Encoding", [output.length], output);
|
||||
output.add(encoding);
|
||||
output.setArray(encoding);
|
||||
}
|
||||
}
|
||||
const charset = this.compileCharset(
|
||||
@ -1495,23 +1451,23 @@ class CFFCompiler {
|
||||
cff.isCIDFont
|
||||
);
|
||||
topDictTracker.setEntryLocation("charset", [output.length], output);
|
||||
output.add(charset);
|
||||
output.setArray(charset);
|
||||
|
||||
const charStrings = this.compileCharStrings(cff.charStrings);
|
||||
topDictTracker.setEntryLocation("CharStrings", [output.length], output);
|
||||
output.add(charStrings);
|
||||
output.setArray(charStrings);
|
||||
|
||||
if (cff.isCIDFont) {
|
||||
// For some reason FDSelect must be in front of FDArray on windows. OSX
|
||||
// and linux don't seem to care.
|
||||
topDictTracker.setEntryLocation("FDSelect", [output.length], output);
|
||||
const fdSelect = this.compileFDSelect(cff.fdSelect);
|
||||
output.add(fdSelect);
|
||||
output.setArray(fdSelect);
|
||||
// It is unclear if the sub font dictionary can have CID related
|
||||
// dictionary keys, but the sanitizer doesn't like them so remove them.
|
||||
compiled = this.compileTopDicts(cff.fdArray, output.length, true);
|
||||
topDictTracker.setEntryLocation("FDArray", [output.length], output);
|
||||
output.add(compiled.output);
|
||||
output.setArray(compiled.output);
|
||||
const fontDictTrackers = compiled.trackers;
|
||||
|
||||
this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output);
|
||||
@ -1521,7 +1477,7 @@ class CFFCompiler {
|
||||
|
||||
// If the font data ends with INDEX whose object data is zero-length,
|
||||
// the sanitizer will bail out. Add a dummy byte to avoid that.
|
||||
output.add([0]);
|
||||
output.setArray([0]);
|
||||
|
||||
return output.data;
|
||||
}
|
||||
@ -1689,7 +1645,7 @@ class CFFCompiler {
|
||||
[privateDictData.length, outputLength],
|
||||
output
|
||||
);
|
||||
output.add(privateDictData);
|
||||
output.setArray(privateDictData);
|
||||
|
||||
if (privateDict.subrsIndex && privateDict.hasName("Subrs")) {
|
||||
const subrs = this.compileIndex(privateDict.subrsIndex);
|
||||
@ -1698,7 +1654,7 @@ class CFFCompiler {
|
||||
[privateDictData.length],
|
||||
output
|
||||
);
|
||||
output.add(subrs);
|
||||
output.setArray(subrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
125
src/core/data_builder.js
Normal file
125
src/core/data_builder.js
Normal file
@ -0,0 +1,125 @@
|
||||
/* Copyright 2026 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 { assert } from "../shared/util.js";
|
||||
import { MathClamp } from "../shared/math_clamp.js";
|
||||
|
||||
class DataBuilder {
|
||||
#buf;
|
||||
|
||||
#bufLength = 1024;
|
||||
|
||||
#hasExactLength = false;
|
||||
|
||||
#pos = 0;
|
||||
|
||||
#view;
|
||||
|
||||
constructor({ exactLength = 0, minLength = 0 }) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
export { DataBuilder };
|
||||
@ -58,10 +58,10 @@ import {
|
||||
import { IdentityToUnicodeMap, ToUnicodeMap } from "./to_unicode_map.js";
|
||||
import { CFFFont } from "./cff_font.js";
|
||||
import { compileFontInfo } from "./obj_bin_transform_core.js";
|
||||
import { DataBuilder } from "./data_builder.js";
|
||||
import { FontRendererFactory } from "./font_renderer.js";
|
||||
import { getFontBasicMetrics } from "./metrics.js";
|
||||
import { GlyfTable } from "./glyf.js";
|
||||
import { MathClamp } from "../shared/math_clamp.js";
|
||||
import { OpenTypeFileBuilder } from "./opentype_file_builder.js";
|
||||
import { Stream } from "./stream.js";
|
||||
import { Type1Font } from "./type1_font.js";
|
||||
@ -302,112 +302,6 @@ function writeUint32(bytes, index, value) {
|
||||
bytes[index] = value >>> 24;
|
||||
}
|
||||
|
||||
class TrueTypeTableBuilder {
|
||||
#buf;
|
||||
|
||||
#bufLength = 1024;
|
||||
|
||||
#hasExactLength = false;
|
||||
|
||||
#pos = 0;
|
||||
|
||||
#view;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
function isTrueTypeFile(file) {
|
||||
const header = file.peekBytes(4),
|
||||
str = bytesToString(header);
|
||||
@ -679,7 +573,7 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
||||
const ranges = getRanges(glyphs, toUnicodeExtraMap, numGlyphs);
|
||||
const numTables = ranges.at(-1)[1] > 0xffff ? 2 : 1;
|
||||
|
||||
const cmap = new TrueTypeTableBuilder({ exactLength: 12 });
|
||||
const cmap = new DataBuilder({ exactLength: 12 });
|
||||
cmap.skip(2); // version, skip redundant "\x00\x00"
|
||||
cmap.setInt16(numTables); // numTables
|
||||
cmap.setArray([0x00, 0x03]); // platformID
|
||||
@ -703,11 +597,11 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
||||
|
||||
// Fill up the 4 parallel arrays describing the segments.
|
||||
const segmentsLength = bmpLength * 2 + trailingRangesCount * 2;
|
||||
const startCount = new TrueTypeTableBuilder({ exactLength: segmentsLength }),
|
||||
endCount = new TrueTypeTableBuilder({ exactLength: segmentsLength }),
|
||||
idDeltas = new TrueTypeTableBuilder({ exactLength: segmentsLength }),
|
||||
idRangeOffsets = new TrueTypeTableBuilder({ exactLength: segmentsLength }),
|
||||
glyphsIds = new TrueTypeTableBuilder({});
|
||||
const startCount = new DataBuilder({ exactLength: segmentsLength }),
|
||||
endCount = new DataBuilder({ exactLength: segmentsLength }),
|
||||
idDeltas = new DataBuilder({ exactLength: segmentsLength }),
|
||||
idRangeOffsets = new DataBuilder({ exactLength: segmentsLength }),
|
||||
glyphsIds = new DataBuilder({});
|
||||
let bias = 0;
|
||||
|
||||
for (i = 0, ii = bmpLength; i < ii; i++) {
|
||||
@ -746,7 +640,7 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
||||
idRangeOffsets.skip(2); // Skip redundant "\x00\x00"
|
||||
}
|
||||
|
||||
const format314 = new TrueTypeTableBuilder({
|
||||
const format314 = new DataBuilder({
|
||||
exactLength:
|
||||
12 +
|
||||
startCount.length +
|
||||
@ -771,12 +665,12 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
||||
format31012 = null,
|
||||
header31012 = null;
|
||||
if (numTables > 1) {
|
||||
cmap31012 = new TrueTypeTableBuilder({ exactLength: 8 });
|
||||
cmap31012 = new DataBuilder({ exactLength: 8 });
|
||||
cmap31012.setArray([0x00, 0x03]); // platformID
|
||||
cmap31012.setArray([0x00, 0x0a]); // encodingID
|
||||
cmap31012.setInt32(4 + numTables * 8 + 4 + format314.length); // start of the table record
|
||||
|
||||
format31012 = new TrueTypeTableBuilder({});
|
||||
format31012 = new DataBuilder({});
|
||||
for (const range of ranges) {
|
||||
let start = range[0];
|
||||
const codes = range[2];
|
||||
@ -796,7 +690,7 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
||||
format31012.setInt32(code); // startGlyphID
|
||||
}
|
||||
|
||||
header31012 = new TrueTypeTableBuilder({ exactLength: 16 });
|
||||
header31012 = new DataBuilder({ exactLength: 16 });
|
||||
header31012.setArray([0x00, 0x0c]); // format
|
||||
header31012.skip(2); // reserved, skip redundant "\x00\x00"
|
||||
header31012.setInt32(format31012.length + 16); // length
|
||||
@ -804,7 +698,7 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
||||
header31012.setInt32(format31012.length / 12); // nGroups
|
||||
}
|
||||
|
||||
const table = new TrueTypeTableBuilder({
|
||||
const table = new DataBuilder({
|
||||
exactLength:
|
||||
4 +
|
||||
cmap.length +
|
||||
@ -927,7 +821,7 @@ function createOS2Table(properties, charstrings, override) {
|
||||
const winAscent = override.yMax || typoAscent;
|
||||
const winDescent = -override.yMin || -typoDescent;
|
||||
|
||||
const os2 = new TrueTypeTableBuilder({ exactLength: 96 });
|
||||
const os2 = new DataBuilder({ exactLength: 96 });
|
||||
os2.setArray([0x00, 0x03]); // version
|
||||
os2.setArray([0x02, 0x24]); // xAvgCharWidth
|
||||
os2.setArray([0x01, 0xf4]); // usWeightClass
|
||||
@ -982,7 +876,7 @@ function createOS2Table(properties, charstrings, override) {
|
||||
}
|
||||
|
||||
function createPostTable(properties) {
|
||||
const post = new TrueTypeTableBuilder({ exactLength: 32 });
|
||||
const post = new DataBuilder({ exactLength: 32 });
|
||||
post.setArray([0x00, 0x03, 0x00, 0x00]); // Version number
|
||||
post.setInt32(Math.floor(properties.italicAngle * 2 ** 16)); // italicAngle
|
||||
post.skip(
|
||||
@ -1028,7 +922,7 @@ function createNameTable(name, proto) {
|
||||
for (i = 0, ii = strings.length; i < ii; i++) {
|
||||
str = proto[1][i] || strings[i];
|
||||
|
||||
const strUnicode = new TrueTypeTableBuilder({
|
||||
const strUnicode = new DataBuilder({
|
||||
exactLength: str.length * 2,
|
||||
});
|
||||
for (j = 0, jj = str.length; j < jj; j++) {
|
||||
@ -1058,7 +952,7 @@ function createNameTable(name, proto) {
|
||||
const strs = namesBytes[i];
|
||||
for (j = 0, jj = strs.length; j < jj; j++) {
|
||||
str = strs[j];
|
||||
const nameRecord = new TrueTypeTableBuilder({
|
||||
const nameRecord = new DataBuilder({
|
||||
exactLength:
|
||||
6 +
|
||||
platformsBytes[i].length +
|
||||
@ -1078,7 +972,7 @@ function createNameTable(name, proto) {
|
||||
}
|
||||
|
||||
const namesRecordCount = stringsBytes.length * platformsBytes.length;
|
||||
const nameTable = new TrueTypeTableBuilder({
|
||||
const nameTable = new DataBuilder({
|
||||
exactLength:
|
||||
6 +
|
||||
Math.sumPrecise(nameRecords.map(arr => arr.length)) +
|
||||
@ -3407,7 +3301,7 @@ class Font {
|
||||
(function fontTableHead() {
|
||||
const dateArr = [0x00, 0x00, 0x00, 0x00, 0x9e, 0x0b, 0x7e, 0x27];
|
||||
|
||||
const head = new TrueTypeTableBuilder({ exactLength: 54 });
|
||||
const head = new DataBuilder({ exactLength: 54 });
|
||||
head.setArray([0x00, 0x01, 0x00, 0x00]); // Version number
|
||||
head.setArray([0x00, 0x00, 0x10, 0x00]); // fontRevision
|
||||
head.skip(4); // checksumAdjustement, skip redundant "\x00\x00\x00\x00"
|
||||
@ -3435,7 +3329,7 @@ class Font {
|
||||
builder.addTable(
|
||||
"hhea",
|
||||
(function fontTableHhea() {
|
||||
const hhea = new TrueTypeTableBuilder({ exactLength: 36 });
|
||||
const hhea = new DataBuilder({ exactLength: 36 });
|
||||
hhea.setArray([0x00, 0x01, 0x00, 0x00]); // Version number
|
||||
hhea.setSafeInt16(properties.ascent); // Typographic Ascent
|
||||
hhea.setSafeInt16(properties.descent); // Typographic Descent
|
||||
@ -3470,7 +3364,7 @@ class Font {
|
||||
const charstrings = font.charstrings;
|
||||
const cffWidths = font.cff?.widths ?? null;
|
||||
|
||||
const hmtx = new TrueTypeTableBuilder({ exactLength: numGlyphs * 4 });
|
||||
const hmtx = new DataBuilder({ exactLength: numGlyphs * 4 });
|
||||
// Fake .notdef (width=0 and lsb=0) first, skip redundant assignment.
|
||||
hmtx.skip(4);
|
||||
|
||||
@ -3492,7 +3386,7 @@ class Font {
|
||||
builder.addTable(
|
||||
"maxp",
|
||||
(function fontTableMaxp() {
|
||||
const maxp = new TrueTypeTableBuilder({ exactLength: 6 });
|
||||
const maxp = new DataBuilder({ exactLength: 6 });
|
||||
maxp.setArray([0x00, 0x00, 0x50, 0x00]); // Version number
|
||||
maxp.setInt16(numGlyphs); // Num of glyphs
|
||||
return maxp.data;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user