mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-06-22 16:05:56 +02:00
Merge pull request #21103 from Snuffleupagus/TrueTypeTableBuilder-2
Use TypedArrays in the `createCmapTable` function
This commit is contained in:
commit
445cb9abf9
@ -20,7 +20,6 @@ import {
|
|||||||
FormatError,
|
FormatError,
|
||||||
info,
|
info,
|
||||||
shadow,
|
shadow,
|
||||||
string32,
|
|
||||||
stringToBytes,
|
stringToBytes,
|
||||||
warn,
|
warn,
|
||||||
} from "../shared/util.js";
|
} from "../shared/util.js";
|
||||||
@ -313,43 +312,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) {
|
||||||
@ -622,12 +688,13 @@ function getRanges(glyphs, toUnicodeExtraMap, numGlyphs) {
|
|||||||
function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
||||||
const ranges = getRanges(glyphs, toUnicodeExtraMap, numGlyphs);
|
const ranges = getRanges(glyphs, toUnicodeExtraMap, numGlyphs);
|
||||||
const numTables = ranges.at(-1)[1] > 0xffff ? 2 : 1;
|
const numTables = ranges.at(-1)[1] > 0xffff ? 2 : 1;
|
||||||
let cmap =
|
|
||||||
"\x00\x00" + // version
|
const cmap = new TrueTypeTableBuilder({ exactLength: 12 });
|
||||||
string16(numTables) + // numTables
|
cmap.skip(2); // version, skip redundant "\x00\x00"
|
||||||
"\x00\x03" + // platformID
|
cmap.setInt16(numTables); // numTables
|
||||||
"\x00\x01" + // encodingID
|
cmap.setArray([0x00, 0x03]); // platformID
|
||||||
string32(4 + numTables * 8); // start of the table record
|
cmap.setArray([0x00, 0x01]); // encodingID
|
||||||
|
cmap.setInt32(4 + numTables * 8); // start of the table record
|
||||||
|
|
||||||
let i, ii, j, jj;
|
let i, ii, j, jj;
|
||||||
for (i = ranges.length - 1; i >= 0; --i) {
|
for (i = ranges.length - 1; i >= 0; --i) {
|
||||||
@ -645,11 +712,11 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
|||||||
const searchParams = OpenTypeFileBuilder.getSearchParams(segCount, 2);
|
const searchParams = OpenTypeFileBuilder.getSearchParams(segCount, 2);
|
||||||
|
|
||||||
// Fill up the 4 parallel arrays describing the segments.
|
// Fill up the 4 parallel arrays describing the segments.
|
||||||
let startCount = "";
|
const startCount = new TrueTypeTableBuilder({}),
|
||||||
let endCount = "";
|
endCount = new TrueTypeTableBuilder({}),
|
||||||
let idDeltas = "";
|
idDeltas = new TrueTypeTableBuilder({}),
|
||||||
let idRangeOffsets = "";
|
idRangeOffsets = new TrueTypeTableBuilder({}),
|
||||||
let glyphsIds = "";
|
glyphsIds = new TrueTypeTableBuilder({});
|
||||||
let bias = 0;
|
let bias = 0;
|
||||||
|
|
||||||
let range, start, end, codes;
|
let range, start, end, codes;
|
||||||
@ -657,8 +724,8 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
|||||||
range = ranges[i];
|
range = ranges[i];
|
||||||
start = range[0];
|
start = range[0];
|
||||||
end = range[1];
|
end = range[1];
|
||||||
startCount += string16(start);
|
startCount.setInt16(start);
|
||||||
endCount += string16(end);
|
endCount.setInt16(end);
|
||||||
codes = range[2];
|
codes = range[2];
|
||||||
let contiguous = true;
|
let contiguous = true;
|
||||||
for (j = 1, jj = codes.length; j < jj; ++j) {
|
for (j = 1, jj = codes.length; j < jj; ++j) {
|
||||||
@ -671,48 +738,58 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
|||||||
const offset = (segCount - i) * 2 + bias * 2;
|
const offset = (segCount - i) * 2 + bias * 2;
|
||||||
bias += end - start + 1;
|
bias += end - start + 1;
|
||||||
|
|
||||||
idDeltas += string16(0);
|
idDeltas.skip(2); // Skip redundant "\x00\x00"
|
||||||
idRangeOffsets += string16(offset);
|
idRangeOffsets.setInt16(offset);
|
||||||
|
|
||||||
for (j = 0, jj = codes.length; j < jj; ++j) {
|
for (j = 0, jj = codes.length; j < jj; ++j) {
|
||||||
glyphsIds += string16(codes[j]);
|
glyphsIds.setInt16(codes[j]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const startCode = codes[0];
|
const startCode = codes[0];
|
||||||
|
|
||||||
idDeltas += string16((startCode - start) & 0xffff);
|
idDeltas.setInt16((startCode - start) & 0xffff);
|
||||||
idRangeOffsets += string16(0);
|
idRangeOffsets.skip(2); // Skip redundant "\x00\x00"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trailingRangesCount > 0) {
|
if (trailingRangesCount > 0) {
|
||||||
endCount += "\xFF\xFF";
|
endCount.setArray([0xff, 0xff]);
|
||||||
startCount += "\xFF\xFF";
|
startCount.setArray([0xff, 0xff]);
|
||||||
idDeltas += "\x00\x01";
|
idDeltas.setArray([0x00, 0x01]);
|
||||||
idRangeOffsets += "\x00\x00";
|
idRangeOffsets.skip(2); // Skip redundant "\x00\x00"
|
||||||
}
|
}
|
||||||
|
|
||||||
const format314 =
|
const format314 = new TrueTypeTableBuilder({
|
||||||
"\x00\x00" + // language
|
exactLength:
|
||||||
string16(2 * segCount) +
|
12 +
|
||||||
string16(searchParams.range) +
|
startCount.length +
|
||||||
string16(searchParams.entry) +
|
endCount.length +
|
||||||
string16(searchParams.rangeShift) +
|
idDeltas.length +
|
||||||
endCount +
|
idRangeOffsets.length +
|
||||||
"\x00\x00" +
|
glyphsIds.length,
|
||||||
startCount +
|
});
|
||||||
idDeltas +
|
format314.skip(2); // language, skip redundant "\x00\x00"
|
||||||
idRangeOffsets +
|
format314.setInt16(2 * segCount);
|
||||||
glyphsIds;
|
format314.setInt16(searchParams.range);
|
||||||
|
format314.setInt16(searchParams.entry);
|
||||||
|
format314.setInt16(searchParams.rangeShift);
|
||||||
|
format314.setArray(endCount.data);
|
||||||
|
format314.skip(2); // Skip redundant "\x00\x00"
|
||||||
|
format314.setArray(startCount.data);
|
||||||
|
format314.setArray(idDeltas.data);
|
||||||
|
format314.setArray(idRangeOffsets.data);
|
||||||
|
format314.setArray(glyphsIds.data);
|
||||||
|
|
||||||
let format31012 = "";
|
let cmap31012 = null,
|
||||||
let header31012 = "";
|
format31012 = null,
|
||||||
|
header31012 = null;
|
||||||
if (numTables > 1) {
|
if (numTables > 1) {
|
||||||
cmap +=
|
cmap31012 = new TrueTypeTableBuilder({ exactLength: 8 });
|
||||||
"\x00\x03" + // platformID
|
cmap31012.setArray([0x00, 0x03]); // platformID
|
||||||
"\x00\x0A" + // encodingID
|
cmap31012.setArray([0x00, 0x0a]); // encodingID
|
||||||
string32(4 + numTables * 8 + 4 + format314.length); // start of the table record
|
cmap31012.setInt32(4 + numTables * 8 + 4 + format314.length); // start of the table record
|
||||||
format31012 = "";
|
|
||||||
|
format31012 = new TrueTypeTableBuilder({});
|
||||||
for (i = 0, ii = ranges.length; i < ii; i++) {
|
for (i = 0, ii = ranges.length; i < ii; i++) {
|
||||||
range = ranges[i];
|
range = ranges[i];
|
||||||
start = range[0];
|
start = range[0];
|
||||||
@ -721,35 +798,43 @@ function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
|
|||||||
for (j = 1, jj = codes.length; j < jj; ++j) {
|
for (j = 1, jj = codes.length; j < jj; ++j) {
|
||||||
if (codes[j] !== codes[j - 1] + 1) {
|
if (codes[j] !== codes[j - 1] + 1) {
|
||||||
end = range[0] + j - 1;
|
end = range[0] + j - 1;
|
||||||
format31012 +=
|
format31012.setInt32(start); // startCharCode
|
||||||
string32(start) + // startCharCode
|
format31012.setInt32(end); // endCharCode
|
||||||
string32(end) + // endCharCode
|
format31012.setInt32(code); // startGlyphID
|
||||||
string32(code); // startGlyphID
|
|
||||||
start = end + 1;
|
start = end + 1;
|
||||||
code = codes[j];
|
code = codes[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
format31012 +=
|
format31012.setInt32(start); // startCharCode
|
||||||
string32(start) + // startCharCode
|
format31012.setInt32(range[1]); // endCharCode
|
||||||
string32(range[1]) + // endCharCode
|
format31012.setInt32(code); // startGlyphID
|
||||||
string32(code); // startGlyphID
|
|
||||||
}
|
}
|
||||||
header31012 =
|
|
||||||
"\x00\x0C" + // format
|
header31012 = new TrueTypeTableBuilder({ exactLength: 16 });
|
||||||
"\x00\x00" + // reserved
|
header31012.setArray([0x00, 0x0c]); // format
|
||||||
string32(format31012.length + 16) + // length
|
header31012.skip(2); // reserved, skip redundant "\x00\x00"
|
||||||
"\x00\x00\x00\x00" + // language
|
header31012.setInt32(format31012.length + 16); // length
|
||||||
string32(format31012.length / 12); // nGroups
|
header31012.skip(4); // language, skip redundant "\x00\x00\x00\x00"
|
||||||
|
header31012.setInt32(format31012.length / 12); // nGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
return stringToBytes(
|
const table = new TrueTypeTableBuilder({
|
||||||
cmap +
|
exactLength:
|
||||||
"\x00\x04" + // format
|
4 +
|
||||||
string16(format314.length + 4) + // length
|
cmap.length +
|
||||||
format314 +
|
(cmap31012?.length ?? 0) +
|
||||||
header31012 +
|
format314.length +
|
||||||
format31012
|
(header31012?.length ?? 0) +
|
||||||
);
|
(format31012?.length ?? 0),
|
||||||
|
});
|
||||||
|
table.setArray(cmap.data);
|
||||||
|
table.setArray(cmap31012?.data ?? []);
|
||||||
|
table.setArray([0x00, 0x04]); // format
|
||||||
|
table.setInt16(format314.length + 4); // length
|
||||||
|
table.setArray(format314.data);
|
||||||
|
table.setArray(header31012?.data ?? []);
|
||||||
|
table.setArray(format31012?.data ?? []);
|
||||||
|
return table.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateOS2Table(os2, file) {
|
function validateOS2Table(os2, file) {
|
||||||
@ -856,27 +941,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 +970,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 +3382,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 +3411,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 +3446,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 +3457,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 +3468,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;
|
|
||||||
})()
|
})()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,6 @@ import {
|
|||||||
FeatureTest,
|
FeatureTest,
|
||||||
isNodeJS,
|
isNodeJS,
|
||||||
shadow,
|
shadow,
|
||||||
string32,
|
|
||||||
unreachable,
|
unreachable,
|
||||||
warn,
|
warn,
|
||||||
} from "../shared/util.js";
|
} from "../shared/util.js";
|
||||||
@ -270,6 +269,14 @@ class FontLoader {
|
|||||||
(data.charCodeAt(offset + 3) & 0xff)
|
(data.charCodeAt(offset + 3) & 0xff)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
function string32(value) {
|
||||||
|
return String.fromCharCode(
|
||||||
|
(value >> 24) & 0xff,
|
||||||
|
(value >> 16) & 0xff,
|
||||||
|
(value >> 8) & 0xff,
|
||||||
|
value & 0xff
|
||||||
|
);
|
||||||
|
}
|
||||||
function spliceString(s, offset, remove, insert) {
|
function spliceString(s, offset, remove, insert) {
|
||||||
const chunk1 = s.substring(0, offset);
|
const chunk1 = s.substring(0, offset);
|
||||||
const chunk2 = s.substring(offset + remove);
|
const chunk2 = s.substring(offset + remove);
|
||||||
|
|||||||
@ -596,21 +596,6 @@ function stringToBytes(str) {
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function string32(value) {
|
|
||||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
||||||
assert(
|
|
||||||
typeof value === "number" && Math.abs(value) < 2 ** 32,
|
|
||||||
`string32: Unexpected input "${value}".`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return String.fromCharCode(
|
|
||||||
(value >> 24) & 0xff,
|
|
||||||
(value >> 16) & 0xff,
|
|
||||||
(value >> 8) & 0xff,
|
|
||||||
value & 0xff
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function objectSize(obj) {
|
function objectSize(obj) {
|
||||||
return Object.keys(obj).length;
|
return Object.keys(obj).length;
|
||||||
}
|
}
|
||||||
@ -1334,7 +1319,6 @@ export {
|
|||||||
ResponseException,
|
ResponseException,
|
||||||
setVerbosityLevel,
|
setVerbosityLevel,
|
||||||
shadow,
|
shadow,
|
||||||
string32,
|
|
||||||
stringToBytes,
|
stringToBytes,
|
||||||
stringToPDFString,
|
stringToPDFString,
|
||||||
stringToUTF8String,
|
stringToUTF8String,
|
||||||
|
|||||||
@ -19,7 +19,6 @@ import {
|
|||||||
createValidAbsoluteUrl,
|
createValidAbsoluteUrl,
|
||||||
getModificationDate,
|
getModificationDate,
|
||||||
getUuid,
|
getUuid,
|
||||||
string32,
|
|
||||||
stringToBytes,
|
stringToBytes,
|
||||||
stringToPDFString,
|
stringToPDFString,
|
||||||
} from "../../src/shared/util.js";
|
} from "../../src/shared/util.js";
|
||||||
@ -72,14 +71,6 @@ describe("util", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("string32", function () {
|
|
||||||
it("converts unsigned 32-bit integers to strings", function () {
|
|
||||||
expect(string32(0x74727565)).toEqual("true");
|
|
||||||
expect(string32(0x74797031)).toEqual("typ1");
|
|
||||||
expect(string32(0x4f54544f)).toEqual("OTTO");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("stringToBytes", function () {
|
describe("stringToBytes", function () {
|
||||||
it("handles non-string arguments", function () {
|
it("handles non-string arguments", function () {
|
||||||
expect(function () {
|
expect(function () {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user