Use TypedArrays in the createNameTable function

This commit is contained in:
Jonas Jenwald 2026-04-14 22:28:29 +02:00
parent 445cb9abf9
commit 0a4e8d024d

View File

@ -302,16 +302,6 @@ function writeUint32(bytes, index, value) {
bytes[index] = value >>> 24; 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 { class TrueTypeTableBuilder {
#buf; #buf;
@ -1019,9 +1009,7 @@ function createPostscriptName(name) {
} }
function createNameTable(name, proto) { function createNameTable(name, proto) {
if (!proto) { proto ||= [[], []]; // no strings and unicode strings
proto = [[], []]; // no strings and unicode strings
}
const strings = [ const strings = [
proto[0][0] || "Original licence", // 0.Copyright proto[0][0] || "Original licence", // 0.Copyright
@ -1035,51 +1023,85 @@ function createNameTable(name, proto) {
proto[0][8] || "Unknown", // 8.Manufacturer proto[0][8] || "Unknown", // 8.Manufacturer
proto[0][9] || "Unknown", // 9.Designer proto[0][9] || "Unknown", // 9.Designer
]; ];
const stringsBytes = strings.map(s => stringToBytes(s));
// Mac want 1-byte per character strings while Windows want // Mac want 1-byte per character strings while Windows want
// 2-bytes per character, so duplicate the names table // 2-bytes per character, so duplicate the names table
const stringsUnicode = []; const stringsUnicodeBytes = new Array(strings.length);
let i, ii, j, jj, str; let i, ii, j, jj, str;
for (i = 0, ii = strings.length; i < ii; i++) { for (i = 0, ii = strings.length; i < ii; i++) {
str = proto[1][i] || strings[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++) { 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 namesBytes = [stringsBytes, stringsUnicodeBytes];
const platforms = ["\x00\x01", "\x00\x03"]; const platformsBytes = [
const encodings = ["\x00\x00", "\x00\x01"]; [0x00, 0x01],
const languages = ["\x00\x00", "\x04\x09"]; [0x00, 0x03],
];
const namesRecordCount = strings.length * platforms.length; const encodingsBytes = [
let nameTable = [0x00, 0x00],
"\x00\x00" + // format [0x00, 0x01],
string16(namesRecordCount) + // Number of names Record ];
string16(namesRecordCount * 12 + 6); // Storage const languagesBytes = [
[0x00, 0x00],
[0x04, 0x09],
];
// Build the name records field // Build the name records field
const nameRecords = [];
let strOffset = 0; let strOffset = 0;
for (i = 0, ii = platforms.length; i < ii; i++) { for (i = 0, ii = platformsBytes.length; i < ii; i++) {
const strs = names[i]; const strs = namesBytes[i];
for (j = 0, jj = strs.length; j < jj; j++) { for (j = 0, jj = strs.length; j < jj; j++) {
str = strs[j]; str = strs[j];
const nameRecord = const nameRecord = new TrueTypeTableBuilder({
platforms[i] + // platform ID exactLength:
encodings[i] + // encoding ID 6 +
languages[i] + // language ID platformsBytes[i].length +
string16(j) + // name ID encodingsBytes[i].length +
string16(str.length) + languagesBytes[i].length,
string16(strOffset); });
nameTable += nameRecord; 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; 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;
} }
/** /**