Merge pull request #21112 from Snuffleupagus/createNameTable-TypedArray

Use TypedArrays in the `createNameTable` function
This commit is contained in:
Jonas Jenwald 2026-04-16 22:48:52 +02:00 committed by GitHub
commit 302b4cb008
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -302,16 +302,6 @@ function writeUint32(bytes, index, value) {
bytes[index] = value >>> 24;
}
function string16(value) {
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
assert(
typeof value === "number" && Math.abs(value) < 2 ** 16,
`string16: Unexpected input "${value}".`
);
}
return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
}
class TrueTypeTableBuilder {
#buf;
@ -712,21 +702,18 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
const searchParams = OpenTypeFileBuilder.getSearchParams(segCount, 2);
// Fill up the 4 parallel arrays describing the segments.
const startCount = new TrueTypeTableBuilder({}),
endCount = new TrueTypeTableBuilder({}),
idDeltas = new TrueTypeTableBuilder({}),
idRangeOffsets = new TrueTypeTableBuilder({}),
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({});
let bias = 0;
let range, start, end, codes;
for (i = 0, ii = bmpLength; i < ii; i++) {
range = ranges[i];
start = range[0];
end = range[1];
const [start, end, codes] = ranges[i];
startCount.setInt16(start);
endCount.setInt16(end);
codes = range[2];
let contiguous = true;
for (j = 1, jj = codes.length; j < jj; ++j) {
if (codes[j] !== codes[j - 1] + 1) {
@ -790,14 +777,13 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
cmap31012.setInt32(4 + numTables * 8 + 4 + format314.length); // start of the table record
format31012 = new TrueTypeTableBuilder({});
for (i = 0, ii = ranges.length; i < ii; i++) {
range = ranges[i];
start = range[0];
codes = range[2];
for (const range of ranges) {
let start = range[0];
const codes = range[2];
let code = codes[0];
for (j = 1, jj = codes.length; j < jj; ++j) {
if (codes[j] !== codes[j - 1] + 1) {
end = range[0] + j - 1;
const end = range[0] + j - 1;
format31012.setInt32(start); // startCharCode
format31012.setInt32(end); // endCharCode
format31012.setInt32(code); // startGlyphID
@ -1019,9 +1005,7 @@ function createPostscriptName(name) {
}
function createNameTable(name, proto) {
if (!proto) {
proto = [[], []]; // no strings and unicode strings
}
proto ||= [[], []]; // no strings and unicode strings
const strings = [
proto[0][0] || "Original licence", // 0.Copyright
@ -1035,51 +1019,85 @@ function createNameTable(name, proto) {
proto[0][8] || "Unknown", // 8.Manufacturer
proto[0][9] || "Unknown", // 9.Designer
];
const stringsBytes = strings.map(s => stringToBytes(s));
// Mac want 1-byte per character strings while Windows want
// 2-bytes per character, so duplicate the names table
const stringsUnicode = [];
const stringsUnicodeBytes = new Array(strings.length);
let i, ii, j, jj, str;
for (i = 0, ii = strings.length; i < ii; i++) {
str = proto[1][i] || strings[i];
const strBufUnicode = [];
const strUnicode = new TrueTypeTableBuilder({
exactLength: str.length * 2,
});
for (j = 0, jj = str.length; j < jj; j++) {
strBufUnicode.push(string16(str.charCodeAt(j)));
strUnicode.setInt16(str.charCodeAt(j));
}
stringsUnicode.push(strBufUnicode.join(""));
stringsUnicodeBytes[i] = strUnicode.data;
}
const names = [strings, stringsUnicode];
const platforms = ["\x00\x01", "\x00\x03"];
const encodings = ["\x00\x00", "\x00\x01"];
const languages = ["\x00\x00", "\x04\x09"];
const namesRecordCount = strings.length * platforms.length;
let nameTable =
"\x00\x00" + // format
string16(namesRecordCount) + // Number of names Record
string16(namesRecordCount * 12 + 6); // Storage
const namesBytes = [stringsBytes, stringsUnicodeBytes];
const platformsBytes = [
[0x00, 0x01],
[0x00, 0x03],
];
const encodingsBytes = [
[0x00, 0x00],
[0x00, 0x01],
];
const languagesBytes = [
[0x00, 0x00],
[0x04, 0x09],
];
// Build the name records field
const nameRecords = [];
let strOffset = 0;
for (i = 0, ii = platforms.length; i < ii; i++) {
const strs = names[i];
for (i = 0, ii = platformsBytes.length; i < ii; i++) {
const strs = namesBytes[i];
for (j = 0, jj = strs.length; j < jj; j++) {
str = strs[j];
const nameRecord =
platforms[i] + // platform ID
encodings[i] + // encoding ID
languages[i] + // language ID
string16(j) + // name ID
string16(str.length) +
string16(strOffset);
nameTable += nameRecord;
const nameRecord = new TrueTypeTableBuilder({
exactLength:
6 +
platformsBytes[i].length +
encodingsBytes[i].length +
languagesBytes[i].length,
});
nameRecord.setArray(platformsBytes[i]); // platform ID
nameRecord.setArray(encodingsBytes[i]); // encoding ID
nameRecord.setArray(languagesBytes[i]); // language ID
nameRecord.setInt16(j); // name ID
nameRecord.setInt16(str.length);
nameRecord.setInt16(strOffset);
nameRecords.push(nameRecord.data);
strOffset += str.length;
}
}
return stringToBytes(nameTable + strings.join("") + stringsUnicode.join(""));
const namesRecordCount = stringsBytes.length * platformsBytes.length;
const nameTable = new TrueTypeTableBuilder({
exactLength:
6 +
Math.sumPrecise(nameRecords.map(arr => arr.length)) +
Math.sumPrecise(stringsBytes.map(arr => arr.length)) +
Math.sumPrecise(stringsUnicodeBytes.map(arr => arr.length)),
});
nameTable.skip(2); // format, skip redundant "\x00\x00"
nameTable.setInt16(namesRecordCount); // Number of names Record
nameTable.setInt16(namesRecordCount * 12 + 6); // Storage
for (const arr of nameRecords) {
nameTable.setArray(arr);
}
for (const arr of stringsBytes) {
nameTable.setArray(arr);
}
for (const arr of stringsUnicodeBytes) {
nameTable.setArray(arr);
}
return nameTable.data;
}
/**