pdf-codec 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/dist/content-write.cjs +26 -5
- package/dist/content-write.d.cts +1 -1
- package/dist/content-write.d.ts +1 -1
- package/dist/content-write.js +27 -6
- package/dist/{embedded-font-CLedn-mT.d.cts → embedded-font-BU6Jgcof.d.cts} +7 -1
- package/dist/{embedded-font-CbqkKgBl.d.ts → embedded-font-fREdbxnr.d.ts} +7 -1
- package/dist/embedded-font-write.d.cts +1 -1
- package/dist/embedded-font-write.d.ts +1 -1
- package/dist/embedded-font.cjs +22 -5
- package/dist/embedded-font.d.cts +2 -2
- package/dist/embedded-font.d.ts +2 -2
- package/dist/embedded-font.js +22 -5
- package/dist/{font-registry-yby02snZ.d.cts → font-registry-B5qL0Vi0.d.cts} +1 -1
- package/dist/{font-registry-Cn7P9lAh.d.ts → font-registry-mgdbNP8_.d.ts} +1 -1
- package/dist/font-registry.d.cts +1 -1
- package/dist/font-registry.d.ts +1 -1
- package/dist/gpos-table.cjs +189 -0
- package/dist/gpos-table.d.cts +6 -0
- package/dist/gpos-table.d.ts +6 -0
- package/dist/gpos-table.js +188 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/math-table.cjs +7 -21
- package/dist/math-table.js +7 -21
- package/dist/measure.d.cts +1 -1
- package/dist/measure.d.ts +1 -1
- package/dist/ot-layout-common.cjs +95 -0
- package/dist/ot-layout-common.d.cts +10 -0
- package/dist/ot-layout-common.d.ts +10 -0
- package/dist/ot-layout-common.js +93 -0
- package/dist/write.d.cts +2 -2
- package/dist/write.d.ts +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_sfnt = require("./sfnt.cjs");
|
|
3
|
+
const require_ot_layout_common = require("./ot-layout-common.cjs");
|
|
4
|
+
//#region src/gpos-table.ts
|
|
5
|
+
const GPOS_HEADER_SIZE = 10;
|
|
6
|
+
const SCRIPT_RECORD_SIZE = 6;
|
|
7
|
+
const FEATURE_RECORD_SIZE = 6;
|
|
8
|
+
const LANG_SYS_HEADER_SIZE = 6;
|
|
9
|
+
const FEATURE_HEADER_SIZE = 4;
|
|
10
|
+
const LOOKUP_HEADER_SIZE = 6;
|
|
11
|
+
const EXTENSION_POS_HEADER_SIZE = 8;
|
|
12
|
+
const LOOKUP_TYPE_PAIR_POS = 2;
|
|
13
|
+
const LOOKUP_TYPE_EXTENSION_POS = 9;
|
|
14
|
+
const KERN_FEATURE_TAG = "kern";
|
|
15
|
+
const PREFERRED_SCRIPT_TAGS = ["latn", "DFLT"];
|
|
16
|
+
function readTag(bytes, offset) {
|
|
17
|
+
return String.fromCharCode(require_sfnt.u8(bytes, offset), require_sfnt.u8(bytes, offset + 1), require_sfnt.u8(bytes, offset + 2), require_sfnt.u8(bytes, offset + 3));
|
|
18
|
+
}
|
|
19
|
+
function valueRecordSize(valueFormat) {
|
|
20
|
+
let size = 0;
|
|
21
|
+
for (let bit = valueFormat; bit !== 0; bit >>= 1) size += (bit & 1) * 2;
|
|
22
|
+
return size;
|
|
23
|
+
}
|
|
24
|
+
const VALUE_FORMAT_X_ADVANCE = 4;
|
|
25
|
+
function xAdvanceOffset(valueFormat) {
|
|
26
|
+
if ((valueFormat & VALUE_FORMAT_X_ADVANCE) === 0) return;
|
|
27
|
+
return valueRecordSize(valueFormat & 3);
|
|
28
|
+
}
|
|
29
|
+
const PAIR_POS_FORMAT_1_HEADER_SIZE = 10;
|
|
30
|
+
const PAIR_VALUE_RECORD_GLYPH_SIZE = 2;
|
|
31
|
+
function parsePairPosFormat1(bytes, subtableOffset) {
|
|
32
|
+
if (!require_sfnt.hasBytes(bytes, subtableOffset, PAIR_POS_FORMAT_1_HEADER_SIZE)) return;
|
|
33
|
+
const coverage = require_ot_layout_common.parseCoverage(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 2));
|
|
34
|
+
if (coverage === void 0) return;
|
|
35
|
+
const valueFormat1 = require_sfnt.u16(bytes, subtableOffset + 4);
|
|
36
|
+
const valueFormat2 = require_sfnt.u16(bytes, subtableOffset + 6);
|
|
37
|
+
const pairSetCount = require_sfnt.u16(bytes, subtableOffset + 8);
|
|
38
|
+
const pairSetOffsetsOffset = subtableOffset + PAIR_POS_FORMAT_1_HEADER_SIZE;
|
|
39
|
+
if (!require_sfnt.hasBytes(bytes, pairSetOffsetsOffset, pairSetCount * 2)) return;
|
|
40
|
+
const recordSize = PAIR_VALUE_RECORD_GLYPH_SIZE + valueRecordSize(valueFormat1) + valueRecordSize(valueFormat2);
|
|
41
|
+
const advanceOffset = xAdvanceOffset(valueFormat1);
|
|
42
|
+
return (leftGlyphId, rightGlyphId) => {
|
|
43
|
+
const coverageIndex = coverage.coverageIndex(leftGlyphId);
|
|
44
|
+
if (coverageIndex === void 0 || coverageIndex >= pairSetCount) return;
|
|
45
|
+
const pairSetOffset = subtableOffset + require_sfnt.u16(bytes, pairSetOffsetsOffset + coverageIndex * 2);
|
|
46
|
+
if (!require_sfnt.hasBytes(bytes, pairSetOffset, 2)) return;
|
|
47
|
+
const pairValueCount = require_sfnt.u16(bytes, pairSetOffset);
|
|
48
|
+
const recordsOffset = pairSetOffset + 2;
|
|
49
|
+
if (!require_sfnt.hasBytes(bytes, recordsOffset, pairValueCount * recordSize)) return;
|
|
50
|
+
let low = 0;
|
|
51
|
+
let high = pairValueCount - 1;
|
|
52
|
+
while (low <= high) {
|
|
53
|
+
const mid = low + high >> 1;
|
|
54
|
+
const recordOffset = recordsOffset + mid * recordSize;
|
|
55
|
+
const secondGlyph = require_sfnt.u16(bytes, recordOffset);
|
|
56
|
+
if (rightGlyphId < secondGlyph) high = mid - 1;
|
|
57
|
+
else if (rightGlyphId > secondGlyph) low = mid + 1;
|
|
58
|
+
else return advanceOffset === void 0 ? 0 : require_sfnt.i16(bytes, recordOffset + PAIR_VALUE_RECORD_GLYPH_SIZE + advanceOffset);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const PAIR_POS_FORMAT_2_HEADER_SIZE = 16;
|
|
63
|
+
function parsePairPosFormat2(bytes, subtableOffset) {
|
|
64
|
+
if (!require_sfnt.hasBytes(bytes, subtableOffset, PAIR_POS_FORMAT_2_HEADER_SIZE)) return;
|
|
65
|
+
const coverage = require_ot_layout_common.parseCoverage(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 2));
|
|
66
|
+
const classDef1 = require_ot_layout_common.parseClassDef(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 8));
|
|
67
|
+
const classDef2 = require_ot_layout_common.parseClassDef(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 10));
|
|
68
|
+
if (coverage === void 0 || classDef1 === void 0 || classDef2 === void 0) return;
|
|
69
|
+
const valueFormat1 = require_sfnt.u16(bytes, subtableOffset + 4);
|
|
70
|
+
const valueFormat2 = require_sfnt.u16(bytes, subtableOffset + 6);
|
|
71
|
+
const class1Count = require_sfnt.u16(bytes, subtableOffset + 12);
|
|
72
|
+
const class2Count = require_sfnt.u16(bytes, subtableOffset + 14);
|
|
73
|
+
const class2RecordSize = valueRecordSize(valueFormat1) + valueRecordSize(valueFormat2);
|
|
74
|
+
const class1RecordSize = class2Count * class2RecordSize;
|
|
75
|
+
const matrixOffset = subtableOffset + PAIR_POS_FORMAT_2_HEADER_SIZE;
|
|
76
|
+
if (!require_sfnt.hasBytes(bytes, matrixOffset, class1Count * class1RecordSize)) return;
|
|
77
|
+
const advanceOffset = xAdvanceOffset(valueFormat1);
|
|
78
|
+
return (leftGlyphId, rightGlyphId) => {
|
|
79
|
+
if (coverage.coverageIndex(leftGlyphId) === void 0) return;
|
|
80
|
+
const class1 = classDef1(leftGlyphId);
|
|
81
|
+
const class2 = classDef2(rightGlyphId);
|
|
82
|
+
if (class1 >= class1Count || class2 >= class2Count) return;
|
|
83
|
+
if (advanceOffset === void 0) return 0;
|
|
84
|
+
return require_sfnt.i16(bytes, matrixOffset + class1 * class1RecordSize + class2 * class2RecordSize + advanceOffset);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function parseSubtable(bytes, lookupType, subtableOffset) {
|
|
88
|
+
if (lookupType === LOOKUP_TYPE_EXTENSION_POS) {
|
|
89
|
+
if (!require_sfnt.hasBytes(bytes, subtableOffset, EXTENSION_POS_HEADER_SIZE) || require_sfnt.u16(bytes, subtableOffset) !== 1) return;
|
|
90
|
+
const extensionLookupType = require_sfnt.u16(bytes, subtableOffset + 2);
|
|
91
|
+
if (extensionLookupType === LOOKUP_TYPE_EXTENSION_POS) return;
|
|
92
|
+
return parseSubtable(bytes, extensionLookupType, subtableOffset + require_sfnt.u32(bytes, subtableOffset + 4));
|
|
93
|
+
}
|
|
94
|
+
if (lookupType !== LOOKUP_TYPE_PAIR_POS) return;
|
|
95
|
+
if (!require_sfnt.hasBytes(bytes, subtableOffset, 2)) return;
|
|
96
|
+
const posFormat = require_sfnt.u16(bytes, subtableOffset);
|
|
97
|
+
if (posFormat === 1) return parsePairPosFormat1(bytes, subtableOffset);
|
|
98
|
+
if (posFormat === 2) return parsePairPosFormat2(bytes, subtableOffset);
|
|
99
|
+
}
|
|
100
|
+
function parseLookupSubtables(bytes, lookupOffset) {
|
|
101
|
+
if (!require_sfnt.hasBytes(bytes, lookupOffset, LOOKUP_HEADER_SIZE)) return [];
|
|
102
|
+
const lookupType = require_sfnt.u16(bytes, lookupOffset);
|
|
103
|
+
const subTableCount = require_sfnt.u16(bytes, lookupOffset + 4);
|
|
104
|
+
const offsetsOffset = lookupOffset + LOOKUP_HEADER_SIZE;
|
|
105
|
+
if (!require_sfnt.hasBytes(bytes, offsetsOffset, subTableCount * 2)) return [];
|
|
106
|
+
const subtables = [];
|
|
107
|
+
for (let i = 0; i < subTableCount; i++) {
|
|
108
|
+
const subtable = parseSubtable(bytes, lookupType, lookupOffset + require_sfnt.u16(bytes, offsetsOffset + i * 2));
|
|
109
|
+
if (subtable !== void 0) subtables.push(subtable);
|
|
110
|
+
}
|
|
111
|
+
return subtables;
|
|
112
|
+
}
|
|
113
|
+
function parseDefaultLangSysFeatureIndices(bytes, scriptOffset) {
|
|
114
|
+
if (!require_sfnt.hasBytes(bytes, scriptOffset, 2)) return [];
|
|
115
|
+
const defaultLangSysOffset = require_sfnt.u16(bytes, scriptOffset);
|
|
116
|
+
if (defaultLangSysOffset === 0) return [];
|
|
117
|
+
const langSysOffset = scriptOffset + defaultLangSysOffset;
|
|
118
|
+
if (!require_sfnt.hasBytes(bytes, langSysOffset, LANG_SYS_HEADER_SIZE)) return [];
|
|
119
|
+
const featureIndexCount = require_sfnt.u16(bytes, langSysOffset + 4);
|
|
120
|
+
const indicesOffset = langSysOffset + LANG_SYS_HEADER_SIZE;
|
|
121
|
+
if (!require_sfnt.hasBytes(bytes, indicesOffset, featureIndexCount * 2)) return [];
|
|
122
|
+
const indices = [];
|
|
123
|
+
for (let i = 0; i < featureIndexCount; i++) indices.push(require_sfnt.u16(bytes, indicesOffset + i * 2));
|
|
124
|
+
return indices;
|
|
125
|
+
}
|
|
126
|
+
function findScriptOffset(bytes, scriptListOffset) {
|
|
127
|
+
if (!require_sfnt.hasBytes(bytes, scriptListOffset, 2)) return;
|
|
128
|
+
const scriptCount = require_sfnt.u16(bytes, scriptListOffset);
|
|
129
|
+
const recordsOffset = scriptListOffset + 2;
|
|
130
|
+
if (!require_sfnt.hasBytes(bytes, recordsOffset, scriptCount * SCRIPT_RECORD_SIZE) || scriptCount === 0) return;
|
|
131
|
+
for (const wanted of PREFERRED_SCRIPT_TAGS) for (let i = 0; i < scriptCount; i++) {
|
|
132
|
+
const recordOffset = recordsOffset + i * SCRIPT_RECORD_SIZE;
|
|
133
|
+
if (readTag(bytes, recordOffset) === wanted) return scriptListOffset + require_sfnt.u16(bytes, recordOffset + 4);
|
|
134
|
+
}
|
|
135
|
+
return scriptListOffset + require_sfnt.u16(bytes, recordsOffset + 4);
|
|
136
|
+
}
|
|
137
|
+
function collectKernLookupIndices(bytes, featureListOffset, featureIndices) {
|
|
138
|
+
if (!require_sfnt.hasBytes(bytes, featureListOffset, 2)) return [];
|
|
139
|
+
const featureCount = require_sfnt.u16(bytes, featureListOffset);
|
|
140
|
+
const recordsOffset = featureListOffset + 2;
|
|
141
|
+
if (!require_sfnt.hasBytes(bytes, recordsOffset, featureCount * FEATURE_RECORD_SIZE)) return [];
|
|
142
|
+
const lookupIndices = [];
|
|
143
|
+
const seen = /* @__PURE__ */ new Set();
|
|
144
|
+
for (const featureIndex of featureIndices) {
|
|
145
|
+
if (featureIndex >= featureCount) continue;
|
|
146
|
+
const recordOffset = recordsOffset + featureIndex * FEATURE_RECORD_SIZE;
|
|
147
|
+
if (readTag(bytes, recordOffset) !== KERN_FEATURE_TAG) continue;
|
|
148
|
+
const featureOffset = featureListOffset + require_sfnt.u16(bytes, recordOffset + 4);
|
|
149
|
+
if (!require_sfnt.hasBytes(bytes, featureOffset, FEATURE_HEADER_SIZE)) continue;
|
|
150
|
+
const lookupIndexCount = require_sfnt.u16(bytes, featureOffset + 2);
|
|
151
|
+
const indicesOffset = featureOffset + FEATURE_HEADER_SIZE;
|
|
152
|
+
if (!require_sfnt.hasBytes(bytes, indicesOffset, lookupIndexCount * 2)) continue;
|
|
153
|
+
for (let i = 0; i < lookupIndexCount; i++) {
|
|
154
|
+
const lookupIndex = require_sfnt.u16(bytes, indicesOffset + i * 2);
|
|
155
|
+
if (!seen.has(lookupIndex)) {
|
|
156
|
+
seen.add(lookupIndex);
|
|
157
|
+
lookupIndices.push(lookupIndex);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return lookupIndices;
|
|
162
|
+
}
|
|
163
|
+
function buildGposKernLookup(font) {
|
|
164
|
+
const bytes = require_sfnt.sfntTableBytes(font, "GPOS");
|
|
165
|
+
if (bytes === void 0 || !require_sfnt.hasBytes(bytes, 0, GPOS_HEADER_SIZE) || require_sfnt.u16(bytes, 0) !== 1) return;
|
|
166
|
+
const scriptOffset = findScriptOffset(bytes, require_sfnt.u16(bytes, 4));
|
|
167
|
+
if (scriptOffset === void 0) return;
|
|
168
|
+
const lookupIndices = collectKernLookupIndices(bytes, require_sfnt.u16(bytes, 6), parseDefaultLangSysFeatureIndices(bytes, scriptOffset));
|
|
169
|
+
if (lookupIndices.length === 0) return;
|
|
170
|
+
const lookupListOffset = require_sfnt.u16(bytes, 8);
|
|
171
|
+
if (!require_sfnt.hasBytes(bytes, lookupListOffset, 2)) return;
|
|
172
|
+
const lookupCount = require_sfnt.u16(bytes, lookupListOffset);
|
|
173
|
+
const lookupOffsetsOffset = lookupListOffset + 2;
|
|
174
|
+
if (!require_sfnt.hasBytes(bytes, lookupOffsetsOffset, lookupCount * 2)) return;
|
|
175
|
+
const subtables = [];
|
|
176
|
+
for (const lookupIndex of lookupIndices) {
|
|
177
|
+
if (lookupIndex >= lookupCount) continue;
|
|
178
|
+
subtables.push(...parseLookupSubtables(bytes, lookupListOffset + require_sfnt.u16(bytes, lookupOffsetsOffset + lookupIndex * 2)));
|
|
179
|
+
}
|
|
180
|
+
if (subtables.length === 0) return;
|
|
181
|
+
return (leftGlyphId, rightGlyphId) => {
|
|
182
|
+
for (const subtable of subtables) {
|
|
183
|
+
const adjustment = subtable(leftGlyphId, rightGlyphId);
|
|
184
|
+
if (adjustment !== void 0) return adjustment;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
exports.buildGposKernLookup = buildGposKernLookup;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { t as SfntFont } from "./sfnt-V08bb5ut.cjs";
|
|
2
|
+
//#region src/gpos-table.d.ts
|
|
3
|
+
type GposKernLookup = (leftGlyphId: number, rightGlyphId: number) => number | undefined;
|
|
4
|
+
declare function buildGposKernLookup(font: SfntFont): GposKernLookup | undefined;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { GposKernLookup, buildGposKernLookup };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { t as SfntFont } from "./sfnt-V08bb5ut.js";
|
|
2
|
+
//#region src/gpos-table.d.ts
|
|
3
|
+
type GposKernLookup = (leftGlyphId: number, rightGlyphId: number) => number | undefined;
|
|
4
|
+
declare function buildGposKernLookup(font: SfntFont): GposKernLookup | undefined;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { GposKernLookup, buildGposKernLookup };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { hasBytes, i16, sfntTableBytes, u16, u32, u8 } from "./sfnt.js";
|
|
2
|
+
import { parseClassDef, parseCoverage } from "./ot-layout-common.js";
|
|
3
|
+
//#region src/gpos-table.ts
|
|
4
|
+
const GPOS_HEADER_SIZE = 10;
|
|
5
|
+
const SCRIPT_RECORD_SIZE = 6;
|
|
6
|
+
const FEATURE_RECORD_SIZE = 6;
|
|
7
|
+
const LANG_SYS_HEADER_SIZE = 6;
|
|
8
|
+
const FEATURE_HEADER_SIZE = 4;
|
|
9
|
+
const LOOKUP_HEADER_SIZE = 6;
|
|
10
|
+
const EXTENSION_POS_HEADER_SIZE = 8;
|
|
11
|
+
const LOOKUP_TYPE_PAIR_POS = 2;
|
|
12
|
+
const LOOKUP_TYPE_EXTENSION_POS = 9;
|
|
13
|
+
const KERN_FEATURE_TAG = "kern";
|
|
14
|
+
const PREFERRED_SCRIPT_TAGS = ["latn", "DFLT"];
|
|
15
|
+
function readTag(bytes, offset) {
|
|
16
|
+
return String.fromCharCode(u8(bytes, offset), u8(bytes, offset + 1), u8(bytes, offset + 2), u8(bytes, offset + 3));
|
|
17
|
+
}
|
|
18
|
+
function valueRecordSize(valueFormat) {
|
|
19
|
+
let size = 0;
|
|
20
|
+
for (let bit = valueFormat; bit !== 0; bit >>= 1) size += (bit & 1) * 2;
|
|
21
|
+
return size;
|
|
22
|
+
}
|
|
23
|
+
const VALUE_FORMAT_X_ADVANCE = 4;
|
|
24
|
+
function xAdvanceOffset(valueFormat) {
|
|
25
|
+
if ((valueFormat & VALUE_FORMAT_X_ADVANCE) === 0) return;
|
|
26
|
+
return valueRecordSize(valueFormat & 3);
|
|
27
|
+
}
|
|
28
|
+
const PAIR_POS_FORMAT_1_HEADER_SIZE = 10;
|
|
29
|
+
const PAIR_VALUE_RECORD_GLYPH_SIZE = 2;
|
|
30
|
+
function parsePairPosFormat1(bytes, subtableOffset) {
|
|
31
|
+
if (!hasBytes(bytes, subtableOffset, PAIR_POS_FORMAT_1_HEADER_SIZE)) return;
|
|
32
|
+
const coverage = parseCoverage(bytes, subtableOffset + u16(bytes, subtableOffset + 2));
|
|
33
|
+
if (coverage === void 0) return;
|
|
34
|
+
const valueFormat1 = u16(bytes, subtableOffset + 4);
|
|
35
|
+
const valueFormat2 = u16(bytes, subtableOffset + 6);
|
|
36
|
+
const pairSetCount = u16(bytes, subtableOffset + 8);
|
|
37
|
+
const pairSetOffsetsOffset = subtableOffset + PAIR_POS_FORMAT_1_HEADER_SIZE;
|
|
38
|
+
if (!hasBytes(bytes, pairSetOffsetsOffset, pairSetCount * 2)) return;
|
|
39
|
+
const recordSize = PAIR_VALUE_RECORD_GLYPH_SIZE + valueRecordSize(valueFormat1) + valueRecordSize(valueFormat2);
|
|
40
|
+
const advanceOffset = xAdvanceOffset(valueFormat1);
|
|
41
|
+
return (leftGlyphId, rightGlyphId) => {
|
|
42
|
+
const coverageIndex = coverage.coverageIndex(leftGlyphId);
|
|
43
|
+
if (coverageIndex === void 0 || coverageIndex >= pairSetCount) return;
|
|
44
|
+
const pairSetOffset = subtableOffset + u16(bytes, pairSetOffsetsOffset + coverageIndex * 2);
|
|
45
|
+
if (!hasBytes(bytes, pairSetOffset, 2)) return;
|
|
46
|
+
const pairValueCount = u16(bytes, pairSetOffset);
|
|
47
|
+
const recordsOffset = pairSetOffset + 2;
|
|
48
|
+
if (!hasBytes(bytes, recordsOffset, pairValueCount * recordSize)) return;
|
|
49
|
+
let low = 0;
|
|
50
|
+
let high = pairValueCount - 1;
|
|
51
|
+
while (low <= high) {
|
|
52
|
+
const mid = low + high >> 1;
|
|
53
|
+
const recordOffset = recordsOffset + mid * recordSize;
|
|
54
|
+
const secondGlyph = u16(bytes, recordOffset);
|
|
55
|
+
if (rightGlyphId < secondGlyph) high = mid - 1;
|
|
56
|
+
else if (rightGlyphId > secondGlyph) low = mid + 1;
|
|
57
|
+
else return advanceOffset === void 0 ? 0 : i16(bytes, recordOffset + PAIR_VALUE_RECORD_GLYPH_SIZE + advanceOffset);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const PAIR_POS_FORMAT_2_HEADER_SIZE = 16;
|
|
62
|
+
function parsePairPosFormat2(bytes, subtableOffset) {
|
|
63
|
+
if (!hasBytes(bytes, subtableOffset, PAIR_POS_FORMAT_2_HEADER_SIZE)) return;
|
|
64
|
+
const coverage = parseCoverage(bytes, subtableOffset + u16(bytes, subtableOffset + 2));
|
|
65
|
+
const classDef1 = parseClassDef(bytes, subtableOffset + u16(bytes, subtableOffset + 8));
|
|
66
|
+
const classDef2 = parseClassDef(bytes, subtableOffset + u16(bytes, subtableOffset + 10));
|
|
67
|
+
if (coverage === void 0 || classDef1 === void 0 || classDef2 === void 0) return;
|
|
68
|
+
const valueFormat1 = u16(bytes, subtableOffset + 4);
|
|
69
|
+
const valueFormat2 = u16(bytes, subtableOffset + 6);
|
|
70
|
+
const class1Count = u16(bytes, subtableOffset + 12);
|
|
71
|
+
const class2Count = u16(bytes, subtableOffset + 14);
|
|
72
|
+
const class2RecordSize = valueRecordSize(valueFormat1) + valueRecordSize(valueFormat2);
|
|
73
|
+
const class1RecordSize = class2Count * class2RecordSize;
|
|
74
|
+
const matrixOffset = subtableOffset + PAIR_POS_FORMAT_2_HEADER_SIZE;
|
|
75
|
+
if (!hasBytes(bytes, matrixOffset, class1Count * class1RecordSize)) return;
|
|
76
|
+
const advanceOffset = xAdvanceOffset(valueFormat1);
|
|
77
|
+
return (leftGlyphId, rightGlyphId) => {
|
|
78
|
+
if (coverage.coverageIndex(leftGlyphId) === void 0) return;
|
|
79
|
+
const class1 = classDef1(leftGlyphId);
|
|
80
|
+
const class2 = classDef2(rightGlyphId);
|
|
81
|
+
if (class1 >= class1Count || class2 >= class2Count) return;
|
|
82
|
+
if (advanceOffset === void 0) return 0;
|
|
83
|
+
return i16(bytes, matrixOffset + class1 * class1RecordSize + class2 * class2RecordSize + advanceOffset);
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function parseSubtable(bytes, lookupType, subtableOffset) {
|
|
87
|
+
if (lookupType === LOOKUP_TYPE_EXTENSION_POS) {
|
|
88
|
+
if (!hasBytes(bytes, subtableOffset, EXTENSION_POS_HEADER_SIZE) || u16(bytes, subtableOffset) !== 1) return;
|
|
89
|
+
const extensionLookupType = u16(bytes, subtableOffset + 2);
|
|
90
|
+
if (extensionLookupType === LOOKUP_TYPE_EXTENSION_POS) return;
|
|
91
|
+
return parseSubtable(bytes, extensionLookupType, subtableOffset + u32(bytes, subtableOffset + 4));
|
|
92
|
+
}
|
|
93
|
+
if (lookupType !== LOOKUP_TYPE_PAIR_POS) return;
|
|
94
|
+
if (!hasBytes(bytes, subtableOffset, 2)) return;
|
|
95
|
+
const posFormat = u16(bytes, subtableOffset);
|
|
96
|
+
if (posFormat === 1) return parsePairPosFormat1(bytes, subtableOffset);
|
|
97
|
+
if (posFormat === 2) return parsePairPosFormat2(bytes, subtableOffset);
|
|
98
|
+
}
|
|
99
|
+
function parseLookupSubtables(bytes, lookupOffset) {
|
|
100
|
+
if (!hasBytes(bytes, lookupOffset, LOOKUP_HEADER_SIZE)) return [];
|
|
101
|
+
const lookupType = u16(bytes, lookupOffset);
|
|
102
|
+
const subTableCount = u16(bytes, lookupOffset + 4);
|
|
103
|
+
const offsetsOffset = lookupOffset + LOOKUP_HEADER_SIZE;
|
|
104
|
+
if (!hasBytes(bytes, offsetsOffset, subTableCount * 2)) return [];
|
|
105
|
+
const subtables = [];
|
|
106
|
+
for (let i = 0; i < subTableCount; i++) {
|
|
107
|
+
const subtable = parseSubtable(bytes, lookupType, lookupOffset + u16(bytes, offsetsOffset + i * 2));
|
|
108
|
+
if (subtable !== void 0) subtables.push(subtable);
|
|
109
|
+
}
|
|
110
|
+
return subtables;
|
|
111
|
+
}
|
|
112
|
+
function parseDefaultLangSysFeatureIndices(bytes, scriptOffset) {
|
|
113
|
+
if (!hasBytes(bytes, scriptOffset, 2)) return [];
|
|
114
|
+
const defaultLangSysOffset = u16(bytes, scriptOffset);
|
|
115
|
+
if (defaultLangSysOffset === 0) return [];
|
|
116
|
+
const langSysOffset = scriptOffset + defaultLangSysOffset;
|
|
117
|
+
if (!hasBytes(bytes, langSysOffset, LANG_SYS_HEADER_SIZE)) return [];
|
|
118
|
+
const featureIndexCount = u16(bytes, langSysOffset + 4);
|
|
119
|
+
const indicesOffset = langSysOffset + LANG_SYS_HEADER_SIZE;
|
|
120
|
+
if (!hasBytes(bytes, indicesOffset, featureIndexCount * 2)) return [];
|
|
121
|
+
const indices = [];
|
|
122
|
+
for (let i = 0; i < featureIndexCount; i++) indices.push(u16(bytes, indicesOffset + i * 2));
|
|
123
|
+
return indices;
|
|
124
|
+
}
|
|
125
|
+
function findScriptOffset(bytes, scriptListOffset) {
|
|
126
|
+
if (!hasBytes(bytes, scriptListOffset, 2)) return;
|
|
127
|
+
const scriptCount = u16(bytes, scriptListOffset);
|
|
128
|
+
const recordsOffset = scriptListOffset + 2;
|
|
129
|
+
if (!hasBytes(bytes, recordsOffset, scriptCount * SCRIPT_RECORD_SIZE) || scriptCount === 0) return;
|
|
130
|
+
for (const wanted of PREFERRED_SCRIPT_TAGS) for (let i = 0; i < scriptCount; i++) {
|
|
131
|
+
const recordOffset = recordsOffset + i * SCRIPT_RECORD_SIZE;
|
|
132
|
+
if (readTag(bytes, recordOffset) === wanted) return scriptListOffset + u16(bytes, recordOffset + 4);
|
|
133
|
+
}
|
|
134
|
+
return scriptListOffset + u16(bytes, recordsOffset + 4);
|
|
135
|
+
}
|
|
136
|
+
function collectKernLookupIndices(bytes, featureListOffset, featureIndices) {
|
|
137
|
+
if (!hasBytes(bytes, featureListOffset, 2)) return [];
|
|
138
|
+
const featureCount = u16(bytes, featureListOffset);
|
|
139
|
+
const recordsOffset = featureListOffset + 2;
|
|
140
|
+
if (!hasBytes(bytes, recordsOffset, featureCount * FEATURE_RECORD_SIZE)) return [];
|
|
141
|
+
const lookupIndices = [];
|
|
142
|
+
const seen = /* @__PURE__ */ new Set();
|
|
143
|
+
for (const featureIndex of featureIndices) {
|
|
144
|
+
if (featureIndex >= featureCount) continue;
|
|
145
|
+
const recordOffset = recordsOffset + featureIndex * FEATURE_RECORD_SIZE;
|
|
146
|
+
if (readTag(bytes, recordOffset) !== KERN_FEATURE_TAG) continue;
|
|
147
|
+
const featureOffset = featureListOffset + u16(bytes, recordOffset + 4);
|
|
148
|
+
if (!hasBytes(bytes, featureOffset, FEATURE_HEADER_SIZE)) continue;
|
|
149
|
+
const lookupIndexCount = u16(bytes, featureOffset + 2);
|
|
150
|
+
const indicesOffset = featureOffset + FEATURE_HEADER_SIZE;
|
|
151
|
+
if (!hasBytes(bytes, indicesOffset, lookupIndexCount * 2)) continue;
|
|
152
|
+
for (let i = 0; i < lookupIndexCount; i++) {
|
|
153
|
+
const lookupIndex = u16(bytes, indicesOffset + i * 2);
|
|
154
|
+
if (!seen.has(lookupIndex)) {
|
|
155
|
+
seen.add(lookupIndex);
|
|
156
|
+
lookupIndices.push(lookupIndex);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return lookupIndices;
|
|
161
|
+
}
|
|
162
|
+
function buildGposKernLookup(font) {
|
|
163
|
+
const bytes = sfntTableBytes(font, "GPOS");
|
|
164
|
+
if (bytes === void 0 || !hasBytes(bytes, 0, GPOS_HEADER_SIZE) || u16(bytes, 0) !== 1) return;
|
|
165
|
+
const scriptOffset = findScriptOffset(bytes, u16(bytes, 4));
|
|
166
|
+
if (scriptOffset === void 0) return;
|
|
167
|
+
const lookupIndices = collectKernLookupIndices(bytes, u16(bytes, 6), parseDefaultLangSysFeatureIndices(bytes, scriptOffset));
|
|
168
|
+
if (lookupIndices.length === 0) return;
|
|
169
|
+
const lookupListOffset = u16(bytes, 8);
|
|
170
|
+
if (!hasBytes(bytes, lookupListOffset, 2)) return;
|
|
171
|
+
const lookupCount = u16(bytes, lookupListOffset);
|
|
172
|
+
const lookupOffsetsOffset = lookupListOffset + 2;
|
|
173
|
+
if (!hasBytes(bytes, lookupOffsetsOffset, lookupCount * 2)) return;
|
|
174
|
+
const subtables = [];
|
|
175
|
+
for (const lookupIndex of lookupIndices) {
|
|
176
|
+
if (lookupIndex >= lookupCount) continue;
|
|
177
|
+
subtables.push(...parseLookupSubtables(bytes, lookupListOffset + u16(bytes, lookupOffsetsOffset + lookupIndex * 2)));
|
|
178
|
+
}
|
|
179
|
+
if (subtables.length === 0) return;
|
|
180
|
+
return (leftGlyphId, rightGlyphId) => {
|
|
181
|
+
for (const subtable of subtables) {
|
|
182
|
+
const adjustment = subtable(leftGlyphId, rightGlyphId);
|
|
183
|
+
if (adjustment !== void 0) return adjustment;
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
//#endregion
|
|
188
|
+
export { buildGposKernLookup };
|
package/dist/index.d.cts
CHANGED
|
@@ -6,8 +6,8 @@ import { ByteWriter, concatBytes } from "./bytes/writer.cjs";
|
|
|
6
6
|
import { t as GlyphInkBounds } from "./glyph-bounds-BV_Z40KS.cjs";
|
|
7
7
|
import { NOOP_DIAGNOSTIC_SINK, PdfDiagnostic, PdfDiagnosticSeverity, PdfDiagnosticSink, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError } from "./diagnostics.cjs";
|
|
8
8
|
import { PdfBytesSchema, pdfCodec } from "./codec.cjs";
|
|
9
|
-
import { n as EmbeddedFaceMetrics, r as EmbeddedFaceSubstitution, t as EmbeddedFace } from "./embedded-font-
|
|
10
|
-
import { a as ResolvedFace, i as ProvidedFont, n as FontRegistryOptions, o as createFontRegistry, r as FontSubstitution, s as resolveFaceWithRegistry, t as FontRegistry } from "./font-registry-
|
|
9
|
+
import { n as EmbeddedFaceMetrics, r as EmbeddedFaceSubstitution, t as EmbeddedFace } from "./embedded-font-BU6Jgcof.cjs";
|
|
10
|
+
import { a as ResolvedFace, i as ProvidedFont, n as FontRegistryOptions, o as createFontRegistry, r as FontSubstitution, s as resolveFaceWithRegistry, t as FontRegistry } from "./font-registry-B5qL0Vi0.cjs";
|
|
11
11
|
import { DEFAULT_VERTICAL_METRIC_POLICY, FontMeasurerOptions, StandardFontMeasurerOptions, TextMeasurer, UnderlineMetrics, VerticalMetricPolicy, createFontMeasurer, createStandardFontMeasurer } from "./measure.cjs";
|
|
12
12
|
import { WinAnsiSubstitution } from "./winansi.cjs";
|
|
13
13
|
import { i as Point, u as rotatePointAboutCenter } from "./matrix-BHzJESll.cjs";
|
package/dist/index.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ import { ByteWriter, concatBytes } from "./bytes/writer.js";
|
|
|
6
6
|
import { t as GlyphInkBounds } from "./glyph-bounds-BV_Z40KS.js";
|
|
7
7
|
import { NOOP_DIAGNOSTIC_SINK, PdfDiagnostic, PdfDiagnosticSeverity, PdfDiagnosticSink, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError } from "./diagnostics.js";
|
|
8
8
|
import { PdfBytesSchema, pdfCodec } from "./codec.js";
|
|
9
|
-
import { n as EmbeddedFaceMetrics, r as EmbeddedFaceSubstitution, t as EmbeddedFace } from "./embedded-font-
|
|
10
|
-
import { a as ResolvedFace, i as ProvidedFont, n as FontRegistryOptions, o as createFontRegistry, r as FontSubstitution, s as resolveFaceWithRegistry, t as FontRegistry } from "./font-registry-
|
|
9
|
+
import { n as EmbeddedFaceMetrics, r as EmbeddedFaceSubstitution, t as EmbeddedFace } from "./embedded-font-fREdbxnr.js";
|
|
10
|
+
import { a as ResolvedFace, i as ProvidedFont, n as FontRegistryOptions, o as createFontRegistry, r as FontSubstitution, s as resolveFaceWithRegistry, t as FontRegistry } from "./font-registry-mgdbNP8_.js";
|
|
11
11
|
import { DEFAULT_VERTICAL_METRIC_POLICY, FontMeasurerOptions, StandardFontMeasurerOptions, TextMeasurer, UnderlineMetrics, VerticalMetricPolicy, createFontMeasurer, createStandardFontMeasurer } from "./measure.js";
|
|
12
12
|
import { WinAnsiSubstitution } from "./winansi.js";
|
|
13
13
|
import { i as Point, u as rotatePointAboutCenter } from "./matrix-BHzJESll.js";
|
package/dist/math-table.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_sfnt = require("./sfnt.cjs");
|
|
3
|
+
const require_ot_layout_common = require("./ot-layout-common.cjs");
|
|
3
4
|
//#region src/math-table.ts
|
|
4
5
|
const MATH_VALUE_RECORD_INDEX = {
|
|
5
6
|
axisHeight: 1,
|
|
@@ -72,28 +73,11 @@ function parseMathConstants(bytes, mathTableOffset) {
|
|
|
72
73
|
radicalDegreeBottomRaisePercent: require_sfnt.i16(bytes, constantsOffset + RADICAL_DEGREE_BOTTOM_RAISE_PERCENT_OFFSET)
|
|
73
74
|
};
|
|
74
75
|
}
|
|
75
|
-
function parseCoverageIndex(bytes, coverageOffset) {
|
|
76
|
-
const format = require_sfnt.u16(bytes, coverageOffset);
|
|
77
|
-
const index = /* @__PURE__ */ new Map();
|
|
78
|
-
if (format === 1) {
|
|
79
|
-
const glyphCount = require_sfnt.u16(bytes, coverageOffset + 2);
|
|
80
|
-
for (let i = 0; i < glyphCount; i++) index.set(require_sfnt.u16(bytes, coverageOffset + 4 + i * 2), i);
|
|
81
|
-
} else if (format === 2) {
|
|
82
|
-
const rangeCount = require_sfnt.u16(bytes, coverageOffset + 2);
|
|
83
|
-
for (let i = 0; i < rangeCount; i++) {
|
|
84
|
-
const recordOffset = coverageOffset + 4 + i * 6;
|
|
85
|
-
const startGlyphId = require_sfnt.u16(bytes, recordOffset);
|
|
86
|
-
const endGlyphId = require_sfnt.u16(bytes, recordOffset + 2);
|
|
87
|
-
const startCoverageIndex = require_sfnt.u16(bytes, recordOffset + 4);
|
|
88
|
-
for (let glyphId = startGlyphId; glyphId <= endGlyphId; glyphId++) index.set(glyphId, startCoverageIndex + (glyphId - startGlyphId));
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return index;
|
|
92
|
-
}
|
|
93
76
|
function parseGlyphValueTable(bytes, tableOffset) {
|
|
94
|
-
const coverage =
|
|
77
|
+
const coverage = require_ot_layout_common.parseCoverage(bytes, tableOffset + require_sfnt.u16(bytes, tableOffset));
|
|
95
78
|
const values = /* @__PURE__ */ new Map();
|
|
96
|
-
|
|
79
|
+
if (coverage === void 0) return values;
|
|
80
|
+
for (const [glyphId, coverageIndex] of coverage.entries()) values.set(glyphId, require_sfnt.i16(bytes, tableOffset + 4 + coverageIndex * 4));
|
|
97
81
|
return values;
|
|
98
82
|
}
|
|
99
83
|
function parseMathGlyphInfo(bytes, mathTableOffset) {
|
|
@@ -146,7 +130,9 @@ function parseGlyphConstruction(bytes, constructionOffset) {
|
|
|
146
130
|
function parseConstructionsForAxis(bytes, variantsOffset, coverageOffset, count, constructionArrayOffset) {
|
|
147
131
|
const constructions = /* @__PURE__ */ new Map();
|
|
148
132
|
if (coverageOffset === 0) return constructions;
|
|
149
|
-
|
|
133
|
+
const coverage = require_ot_layout_common.parseCoverage(bytes, variantsOffset + coverageOffset);
|
|
134
|
+
if (coverage === void 0) return constructions;
|
|
135
|
+
for (const [glyphId, coverageIndex] of coverage.entries()) {
|
|
150
136
|
if (coverageIndex >= count) continue;
|
|
151
137
|
constructions.set(glyphId, parseGlyphConstruction(bytes, variantsOffset + require_sfnt.u16(bytes, constructionArrayOffset + coverageIndex * 2)));
|
|
152
138
|
}
|
package/dist/math-table.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { i16, sfntTableBytes, u16 } from "./sfnt.js";
|
|
2
|
+
import { parseCoverage } from "./ot-layout-common.js";
|
|
2
3
|
//#region src/math-table.ts
|
|
3
4
|
const MATH_VALUE_RECORD_INDEX = {
|
|
4
5
|
axisHeight: 1,
|
|
@@ -71,28 +72,11 @@ function parseMathConstants(bytes, mathTableOffset) {
|
|
|
71
72
|
radicalDegreeBottomRaisePercent: i16(bytes, constantsOffset + RADICAL_DEGREE_BOTTOM_RAISE_PERCENT_OFFSET)
|
|
72
73
|
};
|
|
73
74
|
}
|
|
74
|
-
function parseCoverageIndex(bytes, coverageOffset) {
|
|
75
|
-
const format = u16(bytes, coverageOffset);
|
|
76
|
-
const index = /* @__PURE__ */ new Map();
|
|
77
|
-
if (format === 1) {
|
|
78
|
-
const glyphCount = u16(bytes, coverageOffset + 2);
|
|
79
|
-
for (let i = 0; i < glyphCount; i++) index.set(u16(bytes, coverageOffset + 4 + i * 2), i);
|
|
80
|
-
} else if (format === 2) {
|
|
81
|
-
const rangeCount = u16(bytes, coverageOffset + 2);
|
|
82
|
-
for (let i = 0; i < rangeCount; i++) {
|
|
83
|
-
const recordOffset = coverageOffset + 4 + i * 6;
|
|
84
|
-
const startGlyphId = u16(bytes, recordOffset);
|
|
85
|
-
const endGlyphId = u16(bytes, recordOffset + 2);
|
|
86
|
-
const startCoverageIndex = u16(bytes, recordOffset + 4);
|
|
87
|
-
for (let glyphId = startGlyphId; glyphId <= endGlyphId; glyphId++) index.set(glyphId, startCoverageIndex + (glyphId - startGlyphId));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return index;
|
|
91
|
-
}
|
|
92
75
|
function parseGlyphValueTable(bytes, tableOffset) {
|
|
93
|
-
const coverage =
|
|
76
|
+
const coverage = parseCoverage(bytes, tableOffset + u16(bytes, tableOffset));
|
|
94
77
|
const values = /* @__PURE__ */ new Map();
|
|
95
|
-
|
|
78
|
+
if (coverage === void 0) return values;
|
|
79
|
+
for (const [glyphId, coverageIndex] of coverage.entries()) values.set(glyphId, i16(bytes, tableOffset + 4 + coverageIndex * 4));
|
|
96
80
|
return values;
|
|
97
81
|
}
|
|
98
82
|
function parseMathGlyphInfo(bytes, mathTableOffset) {
|
|
@@ -145,7 +129,9 @@ function parseGlyphConstruction(bytes, constructionOffset) {
|
|
|
145
129
|
function parseConstructionsForAxis(bytes, variantsOffset, coverageOffset, count, constructionArrayOffset) {
|
|
146
130
|
const constructions = /* @__PURE__ */ new Map();
|
|
147
131
|
if (coverageOffset === 0) return constructions;
|
|
148
|
-
|
|
132
|
+
const coverage = parseCoverage(bytes, variantsOffset + coverageOffset);
|
|
133
|
+
if (coverage === void 0) return constructions;
|
|
134
|
+
for (const [glyphId, coverageIndex] of coverage.entries()) {
|
|
149
135
|
if (coverageIndex >= count) continue;
|
|
150
136
|
constructions.set(glyphId, parseGlyphConstruction(bytes, variantsOffset + u16(bytes, constructionArrayOffset + coverageIndex * 2)));
|
|
151
137
|
}
|
package/dist/measure.d.cts
CHANGED
package/dist/measure.d.ts
CHANGED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_sfnt = require("./sfnt.cjs");
|
|
3
|
+
//#region src/ot-layout-common.ts
|
|
4
|
+
function findRange(ranges, glyphId) {
|
|
5
|
+
let low = 0;
|
|
6
|
+
let high = ranges.length - 1;
|
|
7
|
+
while (low <= high) {
|
|
8
|
+
const mid = low + high >> 1;
|
|
9
|
+
const range = ranges[mid];
|
|
10
|
+
if (glyphId < range.startGlyphId) high = mid - 1;
|
|
11
|
+
else if (glyphId > range.endGlyphId) low = mid + 1;
|
|
12
|
+
else return range;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function pushGlyph(ranges, glyphId, value, valueStep) {
|
|
16
|
+
const previous = ranges[ranges.length - 1];
|
|
17
|
+
if (previous !== void 0 && glyphId === previous.endGlyphId + 1 && value === previous.value + (previous.endGlyphId - previous.startGlyphId + 1) * valueStep) {
|
|
18
|
+
ranges[ranges.length - 1] = {
|
|
19
|
+
startGlyphId: previous.startGlyphId,
|
|
20
|
+
endGlyphId: glyphId,
|
|
21
|
+
value: previous.value
|
|
22
|
+
};
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
ranges.push({
|
|
26
|
+
startGlyphId: glyphId,
|
|
27
|
+
endGlyphId: glyphId,
|
|
28
|
+
value
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const RANGE_RECORD_SIZE = 6;
|
|
32
|
+
function parseRangeRecords(bytes, recordsOffset, recordCount) {
|
|
33
|
+
if (!require_sfnt.hasBytes(bytes, recordsOffset, recordCount * RANGE_RECORD_SIZE)) return;
|
|
34
|
+
const ranges = [];
|
|
35
|
+
for (let i = 0; i < recordCount; i++) {
|
|
36
|
+
const recordOffset = recordsOffset + i * RANGE_RECORD_SIZE;
|
|
37
|
+
const startGlyphId = require_sfnt.u16(bytes, recordOffset);
|
|
38
|
+
const endGlyphId = require_sfnt.u16(bytes, recordOffset + 2);
|
|
39
|
+
if (endGlyphId < startGlyphId) continue;
|
|
40
|
+
ranges.push({
|
|
41
|
+
startGlyphId,
|
|
42
|
+
endGlyphId,
|
|
43
|
+
value: require_sfnt.u16(bytes, recordOffset + 4)
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
ranges.sort((a, b) => a.startGlyphId - b.startGlyphId);
|
|
47
|
+
return ranges;
|
|
48
|
+
}
|
|
49
|
+
const COVERAGE_HEADER_SIZE = 4;
|
|
50
|
+
function parseCoverage(bytes, coverageOffset) {
|
|
51
|
+
if (!require_sfnt.hasBytes(bytes, coverageOffset, COVERAGE_HEADER_SIZE)) return;
|
|
52
|
+
const format = require_sfnt.u16(bytes, coverageOffset);
|
|
53
|
+
const count = require_sfnt.u16(bytes, coverageOffset + 2);
|
|
54
|
+
let ranges;
|
|
55
|
+
if (format === 1) {
|
|
56
|
+
const glyphArrayOffset = coverageOffset + COVERAGE_HEADER_SIZE;
|
|
57
|
+
if (!require_sfnt.hasBytes(bytes, glyphArrayOffset, count * 2)) return;
|
|
58
|
+
ranges = [];
|
|
59
|
+
for (let i = 0; i < count; i++) pushGlyph(ranges, require_sfnt.u16(bytes, glyphArrayOffset + i * 2), i, 1);
|
|
60
|
+
ranges.sort((a, b) => a.startGlyphId - b.startGlyphId);
|
|
61
|
+
} else if (format === 2) ranges = parseRangeRecords(bytes, coverageOffset + COVERAGE_HEADER_SIZE, count);
|
|
62
|
+
if (ranges === void 0) return;
|
|
63
|
+
const resolved = ranges;
|
|
64
|
+
return {
|
|
65
|
+
coverageIndex(glyphId) {
|
|
66
|
+
const range = findRange(resolved, glyphId);
|
|
67
|
+
return range === void 0 ? void 0 : range.value + (glyphId - range.startGlyphId);
|
|
68
|
+
},
|
|
69
|
+
*entries() {
|
|
70
|
+
for (const range of resolved) for (let glyphId = range.startGlyphId; glyphId <= range.endGlyphId; glyphId++) yield [glyphId, range.value + (glyphId - range.startGlyphId)];
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const CLASS_DEF_FORMAT_1_HEADER_SIZE = 6;
|
|
75
|
+
const CLASS_DEF_FORMAT_2_HEADER_SIZE = 4;
|
|
76
|
+
function parseClassDef(bytes, classDefOffset) {
|
|
77
|
+
if (!require_sfnt.hasBytes(bytes, classDefOffset, CLASS_DEF_FORMAT_2_HEADER_SIZE)) return;
|
|
78
|
+
const format = require_sfnt.u16(bytes, classDefOffset);
|
|
79
|
+
let ranges;
|
|
80
|
+
if (format === 1) {
|
|
81
|
+
if (!require_sfnt.hasBytes(bytes, classDefOffset, CLASS_DEF_FORMAT_1_HEADER_SIZE)) return;
|
|
82
|
+
const startGlyphId = require_sfnt.u16(bytes, classDefOffset + 2);
|
|
83
|
+
const glyphCount = require_sfnt.u16(bytes, classDefOffset + 4);
|
|
84
|
+
const classArrayOffset = classDefOffset + CLASS_DEF_FORMAT_1_HEADER_SIZE;
|
|
85
|
+
if (!require_sfnt.hasBytes(bytes, classArrayOffset, glyphCount * 2)) return;
|
|
86
|
+
ranges = [];
|
|
87
|
+
for (let i = 0; i < glyphCount; i++) pushGlyph(ranges, startGlyphId + i, require_sfnt.u16(bytes, classArrayOffset + i * 2), 0);
|
|
88
|
+
} else if (format === 2) ranges = parseRangeRecords(bytes, classDefOffset + CLASS_DEF_FORMAT_2_HEADER_SIZE, require_sfnt.u16(bytes, classDefOffset + 2));
|
|
89
|
+
if (ranges === void 0) return;
|
|
90
|
+
const resolved = ranges;
|
|
91
|
+
return (glyphId) => findRange(resolved, glyphId)?.value ?? 0;
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
exports.parseClassDef = parseClassDef;
|
|
95
|
+
exports.parseCoverage = parseCoverage;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/ot-layout-common.d.ts
|
|
2
|
+
interface CoverageTable {
|
|
3
|
+
coverageIndex(glyphId: number): number | undefined;
|
|
4
|
+
entries(): IterableIterator<readonly [number, number]>;
|
|
5
|
+
}
|
|
6
|
+
declare function parseCoverage(bytes: Uint8Array<ArrayBuffer>, coverageOffset: number): CoverageTable | undefined;
|
|
7
|
+
type ClassDefTable = (glyphId: number) => number;
|
|
8
|
+
declare function parseClassDef(bytes: Uint8Array<ArrayBuffer>, classDefOffset: number): ClassDefTable | undefined;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { ClassDefTable, CoverageTable, parseClassDef, parseCoverage };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/ot-layout-common.d.ts
|
|
2
|
+
interface CoverageTable {
|
|
3
|
+
coverageIndex(glyphId: number): number | undefined;
|
|
4
|
+
entries(): IterableIterator<readonly [number, number]>;
|
|
5
|
+
}
|
|
6
|
+
declare function parseCoverage(bytes: Uint8Array<ArrayBuffer>, coverageOffset: number): CoverageTable | undefined;
|
|
7
|
+
type ClassDefTable = (glyphId: number) => number;
|
|
8
|
+
declare function parseClassDef(bytes: Uint8Array<ArrayBuffer>, classDefOffset: number): ClassDefTable | undefined;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { ClassDefTable, CoverageTable, parseClassDef, parseCoverage };
|