pdf-parser.js 4.5.6 → 4.7.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.
Files changed (50) hide show
  1. package/README.md +5 -5
  2. package/dist/codec.d.cts +8 -0
  3. package/dist/codec.d.ts +8 -0
  4. package/dist/content-write.d.cts +1 -1
  5. package/dist/content-write.d.ts +1 -1
  6. package/dist/{embedded-font-B4p9a3O3.d.ts → embedded-font-BRhZfEN2.d.ts} +1 -1
  7. package/dist/{embedded-font-oc65VGlr.d.cts → embedded-font-DJUn9kMH.d.cts} +1 -1
  8. package/dist/embedded-font-write.d.cts +1 -1
  9. package/dist/embedded-font-write.d.ts +1 -1
  10. package/dist/embedded-font.cjs +1 -1
  11. package/dist/embedded-font.d.cts +1 -1
  12. package/dist/embedded-font.d.ts +1 -1
  13. package/dist/embedded-font.js +1 -1
  14. package/dist/filters.cjs +14 -3
  15. package/dist/filters.d.cts +4 -0
  16. package/dist/filters.d.ts +4 -0
  17. package/dist/filters.js +14 -3
  18. package/dist/font-registry.d.cts +1 -1
  19. package/dist/font-registry.d.ts +1 -1
  20. package/dist/gdef-table.cjs +48 -0
  21. package/dist/gdef-table.d.cts +15 -0
  22. package/dist/gdef-table.d.ts +15 -0
  23. package/dist/gdef-table.js +42 -0
  24. package/dist/gsub-table-Bm9kSMzk.d.cts +16 -0
  25. package/dist/gsub-table-CdfESH2-.d.ts +16 -0
  26. package/dist/gsub-table.cjs +404 -87
  27. package/dist/gsub-table.d.cts +2 -2
  28. package/dist/gsub-table.d.ts +2 -2
  29. package/dist/gsub-table.js +404 -89
  30. package/dist/images-read.cjs +12 -2
  31. package/dist/images-read.d.cts +5 -0
  32. package/dist/images-read.d.ts +5 -0
  33. package/dist/images-read.js +12 -2
  34. package/dist/index.d.cts +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/layout.cjs +6 -1
  37. package/dist/layout.d.cts +16 -0
  38. package/dist/layout.d.ts +16 -0
  39. package/dist/layout.js +6 -1
  40. package/dist/read.cjs +9 -4
  41. package/dist/read.js +9 -4
  42. package/dist/tounicode.cjs +1 -1
  43. package/dist/tounicode.js +1 -1
  44. package/dist/write.cjs +50 -5
  45. package/dist/write.d.cts +1 -1
  46. package/dist/write.d.ts +1 -1
  47. package/dist/write.js +50 -5
  48. package/package.json +3 -3
  49. package/dist/gsub-table-BRTQ8EUW.d.ts +0 -10
  50. package/dist/gsub-table-URczLd85.d.cts +0 -10
@@ -1,8 +1,15 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_sfnt = require("./sfnt.cjs");
3
3
  const require_ot_layout_common = require("./ot-layout-common.cjs");
4
+ const require_gdef_table = require("./gdef-table.cjs");
4
5
  //#region src/gsub-table.ts
5
- const LIGATURE_FEATURE_TAGS = ["liga", "rlig"];
6
+ const DEFAULT_GSUB_FEATURE_TAGS = [
7
+ "liga",
8
+ "rlig",
9
+ "calt",
10
+ "clig"
11
+ ];
12
+ const GSUB_OPT_IN_FEATURE_TAGS = ["smcp", "dlig"];
6
13
  const GSUB_HEADER_SIZE = 10;
7
14
  const SCRIPT_RECORD_SIZE = 6;
8
15
  const FEATURE_RECORD_SIZE = 6;
@@ -11,105 +18,411 @@ const FEATURE_HEADER_SIZE = 4;
11
18
  const LOOKUP_HEADER_SIZE = 6;
12
19
  const LOOKUP_TYPE_SINGLE_SUBST = 1;
13
20
  const LOOKUP_TYPE_LIGATURE_SUBST = 4;
21
+ const LOOKUP_TYPE_CONTEXT_SUBST = 5;
22
+ const LOOKUP_TYPE_CHAIN_CONTEXT_SUBST = 6;
14
23
  const LOOKUP_TYPE_EXTENSION_SUBST = 7;
15
24
  const EXTENSION_SUBST_HEADER_SIZE = 8;
25
+ const LOOKUP_FLAG_IGNORE_BASE_GLYPHS = 2;
26
+ const LOOKUP_FLAG_IGNORE_LIGATURES = 4;
27
+ const LOOKUP_FLAG_IGNORE_MARKS = 8;
28
+ const LOOKUP_FLAG_USE_MARK_FILTERING_SET = 16;
29
+ const LOOKUP_FLAG_MARK_ATTACHMENT_TYPE = 65280;
30
+ const MAX_LOOKUP_NESTING_DEPTH = 6;
16
31
  const PREFERRED_SCRIPT_TAGS = ["latn", "DFLT"];
17
32
  function readTag(bytes, offset) {
18
33
  return String.fromCharCode(require_sfnt.u16(bytes, offset) >> 8, require_sfnt.u16(bytes, offset) & 255, require_sfnt.u16(bytes, offset + 2) >> 8, require_sfnt.u16(bytes, offset + 2) & 255);
19
34
  }
35
+ function glyphSkipper(lookupFlag, markFilteringSet, gdef) {
36
+ if (gdef === void 0 || lookupFlag === 0) return () => false;
37
+ const ignoreBase = (lookupFlag & LOOKUP_FLAG_IGNORE_BASE_GLYPHS) !== 0;
38
+ const ignoreLigatures = (lookupFlag & LOOKUP_FLAG_IGNORE_LIGATURES) !== 0;
39
+ const ignoreMarks = (lookupFlag & LOOKUP_FLAG_IGNORE_MARKS) !== 0;
40
+ const markAttachmentType = (lookupFlag & LOOKUP_FLAG_MARK_ATTACHMENT_TYPE) >> 8;
41
+ const useMarkFilteringSet = (lookupFlag & LOOKUP_FLAG_USE_MARK_FILTERING_SET) !== 0;
42
+ return (glyphId) => {
43
+ const glyphClass = gdef.glyphClass(glyphId);
44
+ if (ignoreBase && glyphClass === 1) return true;
45
+ if (ignoreLigatures && glyphClass === 2) return true;
46
+ if (glyphClass !== 3) return false;
47
+ if (ignoreMarks) return true;
48
+ if (markAttachmentType !== 0 && gdef.markAttachClass(glyphId) !== markAttachmentType) return true;
49
+ return useMarkFilteringSet && !gdef.markFilteringSetCovers(markFilteringSet, glyphId);
50
+ };
51
+ }
52
+ function nextVisibleSlot(slots, from, skip) {
53
+ for (let i = Math.max(from, 0); i < slots.length; i++) if (!skip(slots[i].glyphId)) return i;
54
+ }
55
+ function prevVisibleSlot(slots, before, skip) {
56
+ for (let i = Math.min(before, slots.length) - 1; i >= 0; i--) if (!skip(slots[i].glyphId)) return i;
57
+ }
20
58
  const SINGLE_SUBST_FORMAT_1_SIZE = 6;
21
- function parseSingleSubstFormat1(bytes, subtableOffset) {
59
+ function parseSingleSubstFormat1(bytes, subtableOffset, skip) {
22
60
  if (!require_sfnt.hasBytes(bytes, subtableOffset, SINGLE_SUBST_FORMAT_1_SIZE)) return;
23
61
  const coverage = require_ot_layout_common.parseCoverage(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 2));
24
62
  if (coverage === void 0) return;
25
63
  const delta = require_sfnt.i16(bytes, subtableOffset + 4);
26
- return {
27
- kind: "single",
28
- lookup: (glyphId) => {
29
- if (coverage.coverageIndex(glyphId) === void 0) return;
30
- return glyphId + delta;
31
- }
64
+ return (slots, index) => {
65
+ const slot = slots[index];
66
+ if (skip(slot.glyphId)) return;
67
+ if (coverage.coverageIndex(slot.glyphId) === void 0) return;
68
+ return {
69
+ consumed: 1,
70
+ replacement: [{
71
+ glyphId: slot.glyphId + delta,
72
+ span: slot.span
73
+ }]
74
+ };
32
75
  };
33
76
  }
34
77
  const SINGLE_SUBST_FORMAT_2_HEADER_SIZE = 6;
35
- function parseSingleSubstFormat2(bytes, subtableOffset) {
78
+ function parseSingleSubstFormat2(bytes, subtableOffset, skip) {
36
79
  if (!require_sfnt.hasBytes(bytes, subtableOffset, SINGLE_SUBST_FORMAT_2_HEADER_SIZE)) return;
37
80
  const coverage = require_ot_layout_common.parseCoverage(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 2));
38
81
  if (coverage === void 0) return;
39
82
  const glyphCount = require_sfnt.u16(bytes, subtableOffset + 4);
40
83
  const substitutesOffset = subtableOffset + SINGLE_SUBST_FORMAT_2_HEADER_SIZE;
41
84
  if (!require_sfnt.hasBytes(bytes, substitutesOffset, glyphCount * 2)) return;
42
- return {
43
- kind: "single",
44
- lookup: (glyphId) => {
45
- const coverageIndex = coverage.coverageIndex(glyphId);
46
- if (coverageIndex === void 0 || coverageIndex >= glyphCount) return;
47
- return require_sfnt.u16(bytes, substitutesOffset + coverageIndex * 2);
48
- }
85
+ return (slots, index) => {
86
+ const slot = slots[index];
87
+ if (skip(slot.glyphId)) return;
88
+ const coverageIndex = coverage.coverageIndex(slot.glyphId);
89
+ if (coverageIndex === void 0 || coverageIndex >= glyphCount) return;
90
+ return {
91
+ consumed: 1,
92
+ replacement: [{
93
+ glyphId: require_sfnt.u16(bytes, substitutesOffset + coverageIndex * 2),
94
+ span: slot.span
95
+ }]
96
+ };
49
97
  };
50
98
  }
51
99
  const LIGATURE_SUBST_FORMAT_1_HEADER_SIZE = 6;
52
100
  const LIGATURE_SET_HEADER_SIZE = 2;
53
101
  const LIGATURE_HEADER_PREFIX_SIZE = 4;
54
- function parseLigatureSubstFormat1(bytes, subtableOffset) {
102
+ function parseLigatureSubstFormat1(bytes, subtableOffset, skip) {
55
103
  if (!require_sfnt.hasBytes(bytes, subtableOffset, LIGATURE_SUBST_FORMAT_1_HEADER_SIZE)) return;
56
104
  const coverage = require_ot_layout_common.parseCoverage(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 2));
57
105
  if (coverage === void 0) return;
58
106
  const ligSetCount = require_sfnt.u16(bytes, subtableOffset + 4);
59
107
  const ligSetOffsetsOffset = subtableOffset + LIGATURE_SUBST_FORMAT_1_HEADER_SIZE;
60
108
  if (!require_sfnt.hasBytes(bytes, ligSetOffsetsOffset, ligSetCount * 2)) return;
61
- return {
62
- kind: "ligature",
63
- match: (glyphIds, index) => {
64
- const coverageIndex = coverage.coverageIndex(glyphIds[index]);
65
- if (coverageIndex === void 0 || coverageIndex >= ligSetCount) return;
66
- const ligSetOffset = subtableOffset + require_sfnt.u16(bytes, ligSetOffsetsOffset + coverageIndex * 2);
67
- if (!require_sfnt.hasBytes(bytes, ligSetOffset, LIGATURE_SET_HEADER_SIZE)) return;
68
- const ligatureCount = require_sfnt.u16(bytes, ligSetOffset);
69
- const ligatureOffsetsOffset = ligSetOffset + LIGATURE_SET_HEADER_SIZE;
70
- if (!require_sfnt.hasBytes(bytes, ligatureOffsetsOffset, ligatureCount * 2)) return;
71
- for (let i = 0; i < ligatureCount; i++) {
72
- const ligatureOffset = ligSetOffset + require_sfnt.u16(bytes, ligatureOffsetsOffset + i * 2);
73
- if (!require_sfnt.hasBytes(bytes, ligatureOffset, LIGATURE_HEADER_PREFIX_SIZE)) continue;
74
- const ligatureGlyph = require_sfnt.u16(bytes, ligatureOffset);
75
- const componentCount = require_sfnt.u16(bytes, ligatureOffset + 2);
76
- if (componentCount === 0) continue;
77
- const componentsOffset = ligatureOffset + LIGATURE_HEADER_PREFIX_SIZE;
78
- if (!require_sfnt.hasBytes(bytes, componentsOffset, (componentCount - 1) * 2)) continue;
79
- if (index + componentCount > glyphIds.length) continue;
80
- let matches = true;
81
- for (let c = 1; c < componentCount; c++) if (glyphIds[index + c] !== require_sfnt.u16(bytes, componentsOffset + (c - 1) * 2)) {
109
+ return (slots, index) => {
110
+ const first = slots[index];
111
+ if (skip(first.glyphId)) return;
112
+ const coverageIndex = coverage.coverageIndex(first.glyphId);
113
+ if (coverageIndex === void 0 || coverageIndex >= ligSetCount) return;
114
+ const ligSetOffset = subtableOffset + require_sfnt.u16(bytes, ligSetOffsetsOffset + coverageIndex * 2);
115
+ if (!require_sfnt.hasBytes(bytes, ligSetOffset, LIGATURE_SET_HEADER_SIZE)) return;
116
+ const ligatureCount = require_sfnt.u16(bytes, ligSetOffset);
117
+ const ligatureOffsetsOffset = ligSetOffset + LIGATURE_SET_HEADER_SIZE;
118
+ if (!require_sfnt.hasBytes(bytes, ligatureOffsetsOffset, ligatureCount * 2)) return;
119
+ for (let i = 0; i < ligatureCount; i++) {
120
+ const ligatureOffset = ligSetOffset + require_sfnt.u16(bytes, ligatureOffsetsOffset + i * 2);
121
+ if (!require_sfnt.hasBytes(bytes, ligatureOffset, LIGATURE_HEADER_PREFIX_SIZE)) continue;
122
+ const ligatureGlyph = require_sfnt.u16(bytes, ligatureOffset);
123
+ const componentCount = require_sfnt.u16(bytes, ligatureOffset + 2);
124
+ if (componentCount === 0) continue;
125
+ const componentsOffset = ligatureOffset + LIGATURE_HEADER_PREFIX_SIZE;
126
+ if (!require_sfnt.hasBytes(bytes, componentsOffset, (componentCount - 1) * 2)) continue;
127
+ const matchedSlots = [index];
128
+ let cursor = index;
129
+ let matches = true;
130
+ for (let c = 1; c < componentCount; c++) {
131
+ const next = nextVisibleSlot(slots, cursor + 1, skip);
132
+ if (next === void 0 || slots[next].glyphId !== require_sfnt.u16(bytes, componentsOffset + (c - 1) * 2)) {
82
133
  matches = false;
83
134
  break;
84
135
  }
85
- if (matches) return {
86
- ligatureGlyph,
87
- componentCount
88
- };
136
+ matchedSlots.push(next);
137
+ cursor = next;
138
+ }
139
+ if (!matches) continue;
140
+ const lastSlot = matchedSlots[matchedSlots.length - 1];
141
+ let windowSpan = 0;
142
+ const retained = [];
143
+ for (let s = index; s <= lastSlot; s++) {
144
+ windowSpan += slots[s].span;
145
+ if (skip(slots[s].glyphId)) retained.push({
146
+ glyphId: slots[s].glyphId,
147
+ span: 0
148
+ });
89
149
  }
150
+ return {
151
+ consumed: lastSlot - index + 1,
152
+ replacement: [{
153
+ glyphId: ligatureGlyph,
154
+ span: windowSpan
155
+ }, ...retained]
156
+ };
90
157
  }
91
158
  };
92
159
  }
93
- function parseSubtable(bytes, lookupType, subtableOffset) {
160
+ function matchContextualRule(slots, index, skip, backtrack, inputTests, lookahead) {
161
+ const inputSlots = [index];
162
+ let cursor = index;
163
+ for (const test of inputTests) {
164
+ const next = nextVisibleSlot(slots, cursor + 1, skip);
165
+ if (next === void 0 || !test(slots[next].glyphId)) return;
166
+ inputSlots.push(next);
167
+ cursor = next;
168
+ }
169
+ let back = index;
170
+ for (let b = backtrack.length - 1; b >= 0; b--) {
171
+ const previous = prevVisibleSlot(slots, back, skip);
172
+ if (previous === void 0 || !backtrack[b](slots[previous].glyphId)) return;
173
+ back = previous;
174
+ }
175
+ let ahead = inputSlots[inputSlots.length - 1];
176
+ for (const test of lookahead) {
177
+ const next = nextVisibleSlot(slots, ahead + 1, skip);
178
+ if (next === void 0 || !test(slots[next].glyphId)) return;
179
+ ahead = next;
180
+ }
181
+ return inputSlots;
182
+ }
183
+ function applyContextualRule(slots, inputSlots, records, lookupOf, skip, depth) {
184
+ const first = inputSlots[0];
185
+ const last = inputSlots[inputSlots.length - 1];
186
+ const window = [];
187
+ for (let s = first; s <= last; s++) window.push({
188
+ glyphId: slots[s].glyphId,
189
+ span: slots[s].span
190
+ });
191
+ for (const record of records) {
192
+ const lookup = lookupOf(record.lookupIndex);
193
+ if (lookup === void 0 || record.sequenceIndex >= inputSlots.length || depth >= MAX_LOOKUP_NESTING_DEPTH) return;
194
+ const target = visibleInputSlot(window, record.sequenceIndex, skip);
195
+ if (target !== void 0) applyLookupAtSlot(window, target, lookup, depth + 1);
196
+ }
197
+ return {
198
+ consumed: last - first + 1,
199
+ replacement: window
200
+ };
201
+ }
202
+ function visibleInputSlot(window, position, skip) {
203
+ let seen = 0;
204
+ for (let i = 0; i < window.length; i++) {
205
+ if (skip(window[i].glyphId)) continue;
206
+ if (seen === position) return i;
207
+ seen += 1;
208
+ }
209
+ }
210
+ function applyLookupAtSlot(slots, index, lookup, depth) {
211
+ for (const subtable of lookup.subtables) {
212
+ const application = subtable(slots, index, depth);
213
+ if (application !== void 0) {
214
+ slots.splice(index, application.consumed, ...application.replacement);
215
+ return application.replacement.length;
216
+ }
217
+ }
218
+ return 0;
219
+ }
220
+ const SUBST_LOOKUP_RECORD_SIZE = 4;
221
+ function readSubstLookupRecords(bytes, offset, count) {
222
+ if (!require_sfnt.hasBytes(bytes, offset, count * SUBST_LOOKUP_RECORD_SIZE)) return;
223
+ const records = [];
224
+ for (let i = 0; i < count; i++) {
225
+ const recordOffset = offset + i * SUBST_LOOKUP_RECORD_SIZE;
226
+ records.push({
227
+ sequenceIndex: require_sfnt.u16(bytes, recordOffset),
228
+ lookupIndex: require_sfnt.u16(bytes, recordOffset + 2)
229
+ });
230
+ }
231
+ return records;
232
+ }
233
+ function parseFormat3Rule(bytes, subtableOffset, chained) {
234
+ let offset = subtableOffset + 2;
235
+ const backtrack = [];
236
+ const input = [];
237
+ const lookahead = [];
238
+ const readCoverageArray = () => {
239
+ if (!require_sfnt.hasBytes(bytes, offset, 2)) return;
240
+ const count = require_sfnt.u16(bytes, offset);
241
+ offset += 2;
242
+ if (!require_sfnt.hasBytes(bytes, offset, count * 2)) return;
243
+ const coverages = [];
244
+ for (let i = 0; i < count; i++) {
245
+ const coverageOffset = require_sfnt.u16(bytes, offset + i * 2);
246
+ if (coverageOffset === 0) return;
247
+ const coverage = require_ot_layout_common.parseCoverage(bytes, subtableOffset + coverageOffset);
248
+ if (coverage === void 0) return;
249
+ coverages.push(coverage);
250
+ }
251
+ offset += count * 2;
252
+ return coverages;
253
+ };
254
+ if (chained) {
255
+ const backtracks = readCoverageArray();
256
+ if (backtracks === void 0) return;
257
+ backtrack.push(...backtracks);
258
+ }
259
+ {
260
+ const inputs = readCoverageArray();
261
+ if (inputs === void 0 || inputs.length === 0) return;
262
+ input.push(...inputs);
263
+ }
264
+ if (chained) {
265
+ const lookaheads = readCoverageArray();
266
+ if (lookaheads === void 0) return;
267
+ lookahead.push(...lookaheads);
268
+ }
269
+ if (!require_sfnt.hasBytes(bytes, offset, 2)) return;
270
+ const substCount = require_sfnt.u16(bytes, offset);
271
+ const records = readSubstLookupRecords(bytes, offset + 2, substCount);
272
+ if (records === void 0) return;
273
+ return {
274
+ backtrack,
275
+ input,
276
+ lookahead,
277
+ records
278
+ };
279
+ }
280
+ function format3Subtable(rule, skip, lookupOf) {
281
+ const inputRest = [];
282
+ for (let i = 1; i < rule.input.length; i++) {
283
+ const coverage = rule.input[i];
284
+ inputRest.push((glyphId) => coverage.coverageIndex(glyphId) !== void 0);
285
+ }
286
+ const backtrack = rule.backtrack.map((coverage) => (glyphId) => coverage.coverageIndex(glyphId) !== void 0);
287
+ const lookahead = rule.lookahead.map((coverage) => (glyphId) => coverage.coverageIndex(glyphId) !== void 0);
288
+ return (slots, index, depth) => {
289
+ const slot = slots[index];
290
+ if (skip(slot.glyphId)) return;
291
+ if (rule.input[0].coverageIndex(slot.glyphId) === void 0) return;
292
+ const inputSlots = matchContextualRule(slots, index, skip, backtrack, inputRest, lookahead);
293
+ if (inputSlots === void 0) return;
294
+ return applyContextualRule(slots, inputSlots, rule.records, lookupOf, skip, depth);
295
+ };
296
+ }
297
+ function readSequenceRule(bytes, ruleOffset, chained) {
298
+ let offset = ruleOffset;
299
+ const readU16 = () => {
300
+ if (!require_sfnt.hasBytes(bytes, offset, 2)) return;
301
+ const value = require_sfnt.u16(bytes, offset);
302
+ offset += 2;
303
+ return value;
304
+ };
305
+ const readArray = () => {
306
+ const count = readU16();
307
+ if (count === void 0 || !require_sfnt.hasBytes(bytes, offset, count * 2)) return;
308
+ const values = [];
309
+ for (let i = 0; i < count; i++) values.push(require_sfnt.u16(bytes, offset + i * 2));
310
+ offset += count * 2;
311
+ return values;
312
+ };
313
+ const backtrack = chained ? readArray() : [];
314
+ const glyphCount = readU16();
315
+ if (backtrack === void 0 || glyphCount === void 0 || glyphCount === 0 || !require_sfnt.hasBytes(bytes, offset, (glyphCount - 1) * 2)) return;
316
+ const input = [];
317
+ for (let i = 0; i < glyphCount - 1; i++) input.push(require_sfnt.u16(bytes, offset + i * 2));
318
+ offset += (glyphCount - 1) * 2;
319
+ const lookahead = chained ? readArray() : [];
320
+ const substCount = readU16();
321
+ if (lookahead === void 0 || substCount === void 0) return;
322
+ const records = readSubstLookupRecords(bytes, offset, substCount);
323
+ if (records === void 0) return;
324
+ return {
325
+ backtrack,
326
+ input,
327
+ lookahead,
328
+ records
329
+ };
330
+ }
331
+ function sequenceSubtable(bytes, subtableOffset, coverage, setCount, setOffsetsOffset, chained, access, skip, lookupOf) {
332
+ const readSet = (entryGlyphId) => {
333
+ const setIndex = access.setIndexOf(entryGlyphId);
334
+ if (setIndex === void 0 || setIndex >= setCount) return [];
335
+ const setOffset = require_sfnt.u16(bytes, setOffsetsOffset + setIndex * 2);
336
+ if (setOffset === 0) return [];
337
+ const ruleSetOffset = subtableOffset + setOffset;
338
+ if (!require_sfnt.hasBytes(bytes, ruleSetOffset, 2)) return [];
339
+ const ruleCount = require_sfnt.u16(bytes, ruleSetOffset);
340
+ if (!require_sfnt.hasBytes(bytes, ruleSetOffset + 2, ruleCount * 2)) return [];
341
+ const rules = [];
342
+ for (let i = 0; i < ruleCount; i++) {
343
+ const rule = readSequenceRule(bytes, ruleSetOffset + require_sfnt.u16(bytes, ruleSetOffset + 2 + i * 2), chained);
344
+ if (rule !== void 0) rules.push(rule);
345
+ }
346
+ return rules;
347
+ };
348
+ return (slots, index, depth) => {
349
+ const slot = slots[index];
350
+ if (skip(slot.glyphId)) return;
351
+ if (coverage.coverageIndex(slot.glyphId) === void 0) return;
352
+ for (const rule of readSet(slot.glyphId)) {
353
+ const inputSlots = matchContextualRule(slots, index, skip, rule.backtrack.map(access.backtrackTest), rule.input.map(access.inputTest), rule.lookahead.map(access.lookaheadTest));
354
+ if (inputSlots !== void 0) return applyContextualRule(slots, inputSlots, rule.records, lookupOf, skip, depth);
355
+ }
356
+ };
357
+ }
358
+ function parseSubtable(bytes, lookupType, subtableOffset, skip, lookupOf) {
94
359
  if (lookupType === LOOKUP_TYPE_EXTENSION_SUBST) {
95
360
  if (!require_sfnt.hasBytes(bytes, subtableOffset, EXTENSION_SUBST_HEADER_SIZE) || require_sfnt.u16(bytes, subtableOffset) !== 1) return;
96
361
  const extensionLookupType = require_sfnt.u16(bytes, subtableOffset + 2);
97
362
  if (extensionLookupType === LOOKUP_TYPE_EXTENSION_SUBST) return;
98
- return parseSubtable(bytes, extensionLookupType, subtableOffset + require_sfnt.u32(bytes, subtableOffset + 4));
363
+ return parseSubtable(bytes, extensionLookupType, subtableOffset + require_sfnt.u32(bytes, subtableOffset + 4), skip, lookupOf);
99
364
  }
100
365
  if (lookupType === LOOKUP_TYPE_SINGLE_SUBST) {
101
366
  if (!require_sfnt.hasBytes(bytes, subtableOffset, 2)) return;
102
367
  const substFormat = require_sfnt.u16(bytes, subtableOffset);
103
- if (substFormat === 1) return parseSingleSubstFormat1(bytes, subtableOffset);
104
- if (substFormat === 2) return parseSingleSubstFormat2(bytes, subtableOffset);
368
+ if (substFormat === 1) return parseSingleSubstFormat1(bytes, subtableOffset, skip);
369
+ if (substFormat === 2) return parseSingleSubstFormat2(bytes, subtableOffset, skip);
105
370
  return;
106
371
  }
107
372
  if (lookupType === LOOKUP_TYPE_LIGATURE_SUBST) {
108
373
  if (!require_sfnt.hasBytes(bytes, subtableOffset, 2)) return;
109
374
  if (require_sfnt.u16(bytes, subtableOffset) !== 1) return;
110
- return parseLigatureSubstFormat1(bytes, subtableOffset);
375
+ return parseLigatureSubstFormat1(bytes, subtableOffset, skip);
376
+ }
377
+ if (lookupType === LOOKUP_TYPE_CONTEXT_SUBST || lookupType === LOOKUP_TYPE_CHAIN_CONTEXT_SUBST) return parseContextualSubtable(bytes, lookupType === LOOKUP_TYPE_CHAIN_CONTEXT_SUBST, subtableOffset, skip, lookupOf);
378
+ }
379
+ function parseContextualSubtable(bytes, chained, subtableOffset, skip, lookupOf) {
380
+ if (!require_sfnt.hasBytes(bytes, subtableOffset, 2)) return;
381
+ const substFormat = require_sfnt.u16(bytes, subtableOffset);
382
+ if (substFormat === 3) {
383
+ const rule = parseFormat3Rule(bytes, subtableOffset, chained);
384
+ return rule === void 0 ? void 0 : format3Subtable(rule, skip, lookupOf);
385
+ }
386
+ if (substFormat === 1) {
387
+ const prefixSize = 6;
388
+ if (!require_sfnt.hasBytes(bytes, subtableOffset, prefixSize)) return;
389
+ const coverage = require_ot_layout_common.parseCoverage(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 2));
390
+ if (coverage === void 0) return;
391
+ const setCount = require_sfnt.u16(bytes, subtableOffset + 4);
392
+ const setOffsetsOffset = subtableOffset + prefixSize;
393
+ if (!require_sfnt.hasBytes(bytes, setOffsetsOffset, setCount * 2)) return;
394
+ const glyphEquality = (expected) => (glyphId) => glyphId === expected;
395
+ return sequenceSubtable(bytes, subtableOffset, coverage, setCount, setOffsetsOffset, chained, {
396
+ setIndexOf: (entryGlyphId) => coverage.coverageIndex(entryGlyphId),
397
+ backtrackTest: glyphEquality,
398
+ inputTest: glyphEquality,
399
+ lookaheadTest: glyphEquality
400
+ }, skip, lookupOf);
401
+ }
402
+ if (substFormat === 2) {
403
+ const prefixSize = chained ? 12 : 8;
404
+ if (!require_sfnt.hasBytes(bytes, subtableOffset, prefixSize)) return;
405
+ const coverage = require_ot_layout_common.parseCoverage(bytes, subtableOffset + require_sfnt.u16(bytes, subtableOffset + 2));
406
+ if (coverage === void 0) return;
407
+ const inputClassDefOffset = chained ? require_sfnt.u16(bytes, subtableOffset + 6) : require_sfnt.u16(bytes, subtableOffset + 4);
408
+ const inputClassDef = inputClassDefOffset === 0 ? constantZeroClassDef : require_ot_layout_common.parseClassDef(bytes, subtableOffset + inputClassDefOffset);
409
+ const readAuxClassDef = (offset) => offset === 0 ? constantZeroClassDef : require_ot_layout_common.parseClassDef(bytes, subtableOffset + offset);
410
+ const backtrackClassDef = chained ? readAuxClassDef(require_sfnt.u16(bytes, subtableOffset + 4)) : constantZeroClassDef;
411
+ const lookaheadClassDef = chained ? readAuxClassDef(require_sfnt.u16(bytes, subtableOffset + 8)) : constantZeroClassDef;
412
+ if (inputClassDef === void 0 || backtrackClassDef === void 0 || lookaheadClassDef === void 0) return;
413
+ const setCount = require_sfnt.u16(bytes, subtableOffset + prefixSize - 2);
414
+ const setOffsetsOffset = subtableOffset + prefixSize;
415
+ if (!require_sfnt.hasBytes(bytes, setOffsetsOffset, setCount * 2)) return;
416
+ const classEquality = (classDef, expected) => (glyphId) => classDef(glyphId) === expected;
417
+ return sequenceSubtable(bytes, subtableOffset, coverage, setCount, setOffsetsOffset, chained, {
418
+ setIndexOf: (entryGlyphId) => inputClassDef(entryGlyphId),
419
+ backtrackTest: (expected) => classEquality(backtrackClassDef, expected),
420
+ inputTest: (expected) => classEquality(inputClassDef, expected),
421
+ lookaheadTest: (expected) => classEquality(lookaheadClassDef, expected)
422
+ }, skip, lookupOf);
111
423
  }
112
424
  }
425
+ const constantZeroClassDef = () => 0;
113
426
  function findScriptOffset(bytes, scriptListOffset) {
114
427
  if (!require_sfnt.hasBytes(bytes, scriptListOffset, 2)) return;
115
428
  const scriptCount = require_sfnt.u16(bytes, scriptListOffset);
@@ -134,7 +447,7 @@ function parseDefaultLangSysFeatureIndices(bytes, scriptOffset) {
134
447
  for (let i = 0; i < featureIndexCount; i++) indices.push(require_sfnt.u16(bytes, indicesOffset + i * 2));
135
448
  return indices;
136
449
  }
137
- function collectLigatureLookupIndices(bytes, featureListOffset, featureIndices) {
450
+ function collectLookupIndices(bytes, featureListOffset, featureIndices, featureTags) {
138
451
  if (!require_sfnt.hasBytes(bytes, featureListOffset, 2)) return [];
139
452
  const featureCount = require_sfnt.u16(bytes, featureListOffset);
140
453
  const recordsOffset = featureListOffset + 2;
@@ -144,8 +457,7 @@ function collectLigatureLookupIndices(bytes, featureListOffset, featureIndices)
144
457
  for (const featureIndex of featureIndices) {
145
458
  if (featureIndex >= featureCount) continue;
146
459
  const recordOffset = recordsOffset + featureIndex * FEATURE_RECORD_SIZE;
147
- const tag = readTag(bytes, recordOffset);
148
- if (!LIGATURE_FEATURE_TAGS.includes(tag)) continue;
460
+ if (!featureTags.includes(readTag(bytes, recordOffset))) continue;
149
461
  const featureOffset = featureListOffset + require_sfnt.u16(bytes, recordOffset + 4);
150
462
  if (!require_sfnt.hasBytes(bytes, featureOffset, FEATURE_HEADER_SIZE)) continue;
151
463
  const lookupIndexCount = require_sfnt.u16(bytes, featureOffset + 2);
@@ -161,65 +473,70 @@ function collectLigatureLookupIndices(bytes, featureListOffset, featureIndices)
161
473
  }
162
474
  return lookupIndices;
163
475
  }
164
- function buildGsubShaper(font) {
476
+ function buildGsubShaper(font, options = {}) {
165
477
  const bytes = require_sfnt.sfntTableBytes(font, "GSUB");
166
478
  if (bytes === void 0 || !require_sfnt.hasBytes(bytes, 0, GSUB_HEADER_SIZE) || require_sfnt.u16(bytes, 0) !== 1) return;
167
479
  const scriptOffset = findScriptOffset(bytes, require_sfnt.u16(bytes, 4));
168
480
  if (scriptOffset === void 0) return;
169
- const lookupIndices = collectLigatureLookupIndices(bytes, require_sfnt.u16(bytes, 6), parseDefaultLangSysFeatureIndices(bytes, scriptOffset));
481
+ const featureTags = [...DEFAULT_GSUB_FEATURE_TAGS, ...options.optInFeatures ?? []];
482
+ const lookupIndices = collectLookupIndices(bytes, require_sfnt.u16(bytes, 6), parseDefaultLangSysFeatureIndices(bytes, scriptOffset), featureTags);
170
483
  if (lookupIndices.length === 0) return;
171
484
  const lookupListOffset = require_sfnt.u16(bytes, 8);
172
485
  if (!require_sfnt.hasBytes(bytes, lookupListOffset, 2)) return;
173
486
  const lookupCount = require_sfnt.u16(bytes, lookupListOffset);
174
487
  const lookupOffsetsOffset = lookupListOffset + 2;
175
488
  if (!require_sfnt.hasBytes(bytes, lookupOffsetsOffset, lookupCount * 2)) return;
176
- const subtables = [];
177
- for (const lookupIndex of lookupIndices) {
178
- if (lookupIndex >= lookupCount) continue;
179
- const lookupOffset = lookupListOffset + require_sfnt.u16(bytes, lookupOffsetsOffset + lookupIndex * 2);
180
- if (!require_sfnt.hasBytes(bytes, lookupOffset, LOOKUP_HEADER_SIZE)) continue;
181
- if (require_sfnt.u16(bytes, lookupOffset + 2) !== 0) continue;
489
+ const gdef = require_gdef_table.parseGdefTable(font);
490
+ const lookups = [];
491
+ const lookupOf = (lookupIndex) => lookups[lookupIndex];
492
+ for (let i = 0; i < lookupCount; i++) {
493
+ const lookupOffset = lookupListOffset + require_sfnt.u16(bytes, lookupOffsetsOffset + i * 2);
494
+ if (!require_sfnt.hasBytes(bytes, lookupOffset, LOOKUP_HEADER_SIZE)) {
495
+ lookups.push(void 0);
496
+ continue;
497
+ }
498
+ const lookupFlag = require_sfnt.u16(bytes, lookupOffset + 2);
182
499
  const lookupType = require_sfnt.u16(bytes, lookupOffset);
183
500
  const subTableCount = require_sfnt.u16(bytes, lookupOffset + 4);
184
501
  const subtableOffsetsOffset = lookupOffset + LOOKUP_HEADER_SIZE;
185
- if (!require_sfnt.hasBytes(bytes, subtableOffsetsOffset, subTableCount * 2)) continue;
186
- for (let i = 0; i < subTableCount; i++) {
187
- const subtable = parseSubtable(bytes, lookupType, lookupOffset + require_sfnt.u16(bytes, subtableOffsetsOffset + i * 2));
502
+ const markFilteringSetWidth = (lookupFlag & LOOKUP_FLAG_USE_MARK_FILTERING_SET) !== 0 ? 2 : 0;
503
+ if (!require_sfnt.hasBytes(bytes, subtableOffsetsOffset, subTableCount * 2 + markFilteringSetWidth)) {
504
+ lookups.push(void 0);
505
+ continue;
506
+ }
507
+ const skip = glyphSkipper(lookupFlag, markFilteringSetWidth === 0 ? 0 : require_sfnt.u16(bytes, subtableOffsetsOffset + subTableCount * 2), gdef);
508
+ const subtables = [];
509
+ for (let s = 0; s < subTableCount; s++) {
510
+ const subtable = parseSubtable(bytes, lookupType, lookupOffset + require_sfnt.u16(bytes, subtableOffsetsOffset + s * 2), skip, lookupOf);
188
511
  if (subtable !== void 0) subtables.push(subtable);
189
512
  }
513
+ lookups.push({ subtables });
190
514
  }
191
- if (subtables.length === 0) return;
515
+ const appliedLookups = [];
516
+ for (const lookupIndex of lookupIndices) {
517
+ const lookup = lookupOf(lookupIndex);
518
+ if (lookup !== void 0) appliedLookups.push(lookup);
519
+ }
520
+ if (appliedLookups.every((lookup) => lookup.subtables.length === 0)) return;
192
521
  return (glyphIds) => {
193
- const shaped = [];
194
- const spans = [];
195
- let index = 0;
196
- outer: while (index < glyphIds.length) {
197
- for (const subtable of subtables) if (subtable.kind === "single") {
198
- const substitute = subtable.lookup(glyphIds[index]);
199
- if (substitute !== void 0) {
200
- shaped.push(substitute);
201
- spans.push(1);
202
- index += 1;
203
- continue outer;
204
- }
205
- } else {
206
- const match = subtable.match(glyphIds, index);
207
- if (match !== void 0) {
208
- shaped.push(match.ligatureGlyph);
209
- spans.push(match.componentCount);
210
- index += match.componentCount;
211
- continue outer;
212
- }
522
+ const slots = glyphIds.map((glyphId) => ({
523
+ glyphId,
524
+ span: 1
525
+ }));
526
+ for (const lookup of appliedLookups) {
527
+ let slotIndex = 0;
528
+ while (slotIndex < slots.length) {
529
+ const advanced = applyLookupAtSlot(slots, slotIndex, lookup, 0);
530
+ slotIndex += advanced !== 0 ? advanced : 1;
213
531
  }
214
- shaped.push(glyphIds[index]);
215
- spans.push(1);
216
- index += 1;
217
532
  }
218
533
  return {
219
- glyphIds: shaped,
220
- spans
534
+ glyphIds: slots.map((slot) => slot.glyphId),
535
+ spans: slots.map((slot) => slot.span)
221
536
  };
222
537
  };
223
538
  }
224
539
  //#endregion
540
+ exports.DEFAULT_GSUB_FEATURE_TAGS = DEFAULT_GSUB_FEATURE_TAGS;
541
+ exports.GSUB_OPT_IN_FEATURE_TAGS = GSUB_OPT_IN_FEATURE_TAGS;
225
542
  exports.buildGsubShaper = buildGsubShaper;
@@ -1,2 +1,2 @@
1
- import { n as GsubShaping, r as buildGsubShaper, t as GsubShaper } from "./gsub-table-URczLd85.cjs";
2
- export { GsubShaper, GsubShaping, buildGsubShaper };
1
+ import { a as GsubShaperOptions, i as GsubShaper, n as GSUB_OPT_IN_FEATURE_TAGS, o as GsubShaping, r as GsubOptInFeatureTag, s as buildGsubShaper, t as DEFAULT_GSUB_FEATURE_TAGS } from "./gsub-table-Bm9kSMzk.cjs";
2
+ export { DEFAULT_GSUB_FEATURE_TAGS, GSUB_OPT_IN_FEATURE_TAGS, GsubOptInFeatureTag, GsubShaper, GsubShaperOptions, GsubShaping, buildGsubShaper };
@@ -1,2 +1,2 @@
1
- import { n as GsubShaping, r as buildGsubShaper, t as GsubShaper } from "./gsub-table-BRTQ8EUW.js";
2
- export { GsubShaper, GsubShaping, buildGsubShaper };
1
+ import { a as GsubShaperOptions, i as GsubShaper, n as GSUB_OPT_IN_FEATURE_TAGS, o as GsubShaping, r as GsubOptInFeatureTag, s as buildGsubShaper, t as DEFAULT_GSUB_FEATURE_TAGS } from "./gsub-table-CdfESH2-.js";
2
+ export { DEFAULT_GSUB_FEATURE_TAGS, GSUB_OPT_IN_FEATURE_TAGS, GsubOptInFeatureTag, GsubShaper, GsubShaperOptions, GsubShaping, buildGsubShaper };