pdf-codec 1.8.0 → 1.10.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 (36) hide show
  1. package/README.md +10 -6
  2. package/dist/codec.d.cts +12 -0
  3. package/dist/codec.d.ts +12 -0
  4. package/dist/content-write.cjs +177 -5
  5. package/dist/content-write.d.cts +1 -1
  6. package/dist/content-write.d.ts +1 -1
  7. package/dist/content-write.js +178 -6
  8. package/dist/{embedded-font-CLedn-mT.d.cts → embedded-font-BU6Jgcof.d.cts} +7 -1
  9. package/dist/{embedded-font-CbqkKgBl.d.ts → embedded-font-fREdbxnr.d.ts} +7 -1
  10. package/dist/embedded-font-write.d.cts +1 -1
  11. package/dist/embedded-font-write.d.ts +1 -1
  12. package/dist/embedded-font.cjs +22 -5
  13. package/dist/embedded-font.d.cts +2 -2
  14. package/dist/embedded-font.d.ts +2 -2
  15. package/dist/embedded-font.js +22 -5
  16. package/dist/{font-registry-yby02snZ.d.cts → font-registry-B5qL0Vi0.d.cts} +1 -1
  17. package/dist/{font-registry-Cn7P9lAh.d.ts → font-registry-mgdbNP8_.d.ts} +1 -1
  18. package/dist/font-registry.d.cts +1 -1
  19. package/dist/font-registry.d.ts +1 -1
  20. package/dist/gpos-table.cjs +189 -0
  21. package/dist/gpos-table.d.cts +6 -0
  22. package/dist/gpos-table.d.ts +6 -0
  23. package/dist/gpos-table.js +188 -0
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/math-table.cjs +7 -21
  27. package/dist/math-table.js +7 -21
  28. package/dist/measure.d.cts +1 -1
  29. package/dist/measure.d.ts +1 -1
  30. package/dist/ot-layout-common.cjs +95 -0
  31. package/dist/ot-layout-common.d.cts +10 -0
  32. package/dist/ot-layout-common.d.ts +10 -0
  33. package/dist/ot-layout-common.js +93 -0
  34. package/dist/write.d.cts +2 -2
  35. package/dist/write.d.ts +2 -2
  36. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  import { o as encodeForShow } from "./afm-widths-Dxucrg7D.js";
2
2
  import { ByteWriter } from "./bytes/writer.js";
3
- import { pdfHexString } from "./objects.js";
3
+ import { pdfArray, pdfHexString, pdfNum } from "./objects.js";
4
4
  import { BEZIER_KAPPA, multiplyMatrices, rotationMatrix, scaleMatrix, translationMatrix } from "./matrix.js";
5
5
  import { encodeForShowEmbedded } from "./embedded-font.js";
6
6
  import { formatNumber, writeObject } from "./serialize.js";
@@ -32,27 +32,48 @@ function writeUnderline(writer, item, widthPt, underline) {
32
32
  writer.writeAscii("f\n");
33
33
  writer.writeAscii("Q\n");
34
34
  }
35
- function writeShowTextBlock(writer, item, resourceName, scalePercent, codes) {
35
+ function writeShowTextBlock(writer, item, resourceName, scalePercent, show) {
36
36
  writer.writeAscii("BT\n");
37
37
  writer.writeAscii(`/${resourceName} ${formatNumber(item.sizePt)} Tf\n`);
38
38
  writer.writeAscii(`${formatNumber(scalePercent)} Tz\n`);
39
39
  writeRgbOperator(writer, item.color, "rg");
40
40
  writeMatrixOperator(writer, anchorMatrix(item.xPt, item.yPt, item.rotationDeg), "Tm");
41
- writeObject(writer, pdfHexString(codes));
42
- writer.writeAscii(" Tj\n");
41
+ writeObject(writer, show.operand);
42
+ writer.writeAscii(` ${show.operator}\n`);
43
43
  writer.writeAscii("ET\n");
44
44
  }
45
45
  function writeStandardText(writer, item, standardName, resourceName, measurer, substitutions) {
46
46
  const encoded = encodeForShow(item.text, standardName);
47
47
  substitutions.push(...encoded.substitutions);
48
48
  const scale = measurer.horizontalScaleFor(item.font);
49
- writeShowTextBlock(writer, item, resourceName, scale * 100, encoded.codes);
49
+ writeShowTextBlock(writer, item, resourceName, scale * 100, {
50
+ operand: pdfHexString(encoded.codes),
51
+ operator: "Tj"
52
+ });
50
53
  if (item.underline === true) writeUnderline(writer, item, item.widthPt ?? encoded.width1000 / GLYPH_SPACE_UNITS_PER_EM * item.sizePt * scale, measurer.underlineAtSize(item.font, item.sizePt));
51
54
  }
55
+ function embeddedShowOperand(encoded) {
56
+ if (encoded.kerns.length === 0) return {
57
+ operand: pdfHexString(encoded.codes),
58
+ operator: "Tj"
59
+ };
60
+ const items = [];
61
+ let runStart = 0;
62
+ for (const kern of encoded.kerns) {
63
+ items.push(pdfHexString(encoded.codes.subarray(runStart, kern.codeOffset)));
64
+ items.push(pdfNum(-kern.adjustment1000));
65
+ runStart = kern.codeOffset;
66
+ }
67
+ items.push(pdfHexString(encoded.codes.subarray(runStart)));
68
+ return {
69
+ operand: pdfArray(items),
70
+ operator: "TJ"
71
+ };
72
+ }
52
73
  function writeEmbeddedText(writer, item, face, resourceName, missingGlyphs) {
53
74
  const encoded = encodeForShowEmbedded(item.text, face);
54
75
  missingGlyphs.push(...encoded.substitutions);
55
- writeShowTextBlock(writer, item, resourceName, EMBEDDED_HORIZONTAL_SCALE_PERCENT, encoded.codes);
76
+ writeShowTextBlock(writer, item, resourceName, EMBEDDED_HORIZONTAL_SCALE_PERCENT, embeddedShowOperand(encoded));
56
77
  if (item.underline === true) writeUnderline(writer, item, item.widthPt ?? encoded.width1000 / GLYPH_SPACE_UNITS_PER_EM * item.sizePt, {
57
78
  offsetPt: face.metrics.underlinePositionGlyphSpace / GLYPH_SPACE_UNITS_PER_EM * item.sizePt,
58
79
  thicknessPt: face.metrics.underlineThicknessGlyphSpace / GLYPH_SPACE_UNITS_PER_EM * item.sizePt
@@ -75,6 +96,105 @@ function paintOperatorFor(fill, stroke, fillRule) {
75
96
  function formatPoint(x, y) {
76
97
  return `${formatNumber(x)} ${formatNumber(y)}`;
77
98
  }
99
+ const DASHED_ON_WIDTH_MULTIPLE = 3;
100
+ const DASHED_GAP_WIDTH_MULTIPLE = 3;
101
+ const DOTTED_ON_LENGTH_PT = 0;
102
+ const DOTTED_GAP_WIDTH_MULTIPLE = 2;
103
+ const DASH_PHASE_PT = 0;
104
+ const LINE_CAP_BUTT = 0;
105
+ const LINE_CAP_ROUND = 1;
106
+ const DOUBLE_RULE_BANDS = 3;
107
+ const DOUBLE_RULE_SIGNS = [1, -1];
108
+ function writeStrokeStyleState(writer, style, strokeWidthPt) {
109
+ if (style === "dashed") {
110
+ writer.writeAscii(`[${formatNumber(strokeWidthPt * DASHED_ON_WIDTH_MULTIPLE)} ${formatNumber(strokeWidthPt * DASHED_GAP_WIDTH_MULTIPLE)}] ${formatNumber(DASH_PHASE_PT)} d\n`);
111
+ return true;
112
+ }
113
+ if (style === "dotted") {
114
+ writer.writeAscii(`[${formatNumber(DOTTED_ON_LENGTH_PT)} ${formatNumber(strokeWidthPt * DOTTED_GAP_WIDTH_MULTIPLE)}] ${formatNumber(DASH_PHASE_PT)} d\n`);
115
+ writer.writeAscii(`${formatNumber(LINE_CAP_ROUND)} J\n`);
116
+ return true;
117
+ }
118
+ return false;
119
+ }
120
+ function resetStrokeStyleState(writer, style) {
121
+ writer.writeAscii(`[] ${formatNumber(DASH_PHASE_PT)} d\n`);
122
+ if (style === "dotted") writer.writeAscii(`${formatNumber(LINE_CAP_BUTT)} J\n`);
123
+ }
124
+ function chordNormal(fromX, fromY, toX, toY) {
125
+ const dx = toX - fromX;
126
+ const dy = toY - fromY;
127
+ const length = Math.hypot(dx, dy);
128
+ if (length === 0) return;
129
+ return {
130
+ x: -dy / length,
131
+ y: dx / length
132
+ };
133
+ }
134
+ function averageNormal(a, b) {
135
+ if (a === void 0) return b;
136
+ if (b === void 0) return a;
137
+ const x = a.x + b.x;
138
+ const y = a.y + b.y;
139
+ const length = Math.hypot(x, y);
140
+ if (length === 0) return;
141
+ return {
142
+ x: x / length,
143
+ y: y / length
144
+ };
145
+ }
146
+ function offsetX(x, normal, offsetPt) {
147
+ return normal === void 0 ? x : x + normal.x * offsetPt;
148
+ }
149
+ function offsetY(y, normal, offsetPt) {
150
+ return normal === void 0 ? y : y + normal.y * offsetPt;
151
+ }
152
+ function offsetSubpath(subpath, offsetPt) {
153
+ const points = [{
154
+ x: subpath.startXPt,
155
+ y: subpath.startYPt
156
+ }, ...subpath.segments.map((segment) => ({
157
+ x: segment.xPt,
158
+ y: segment.yPt
159
+ }))];
160
+ const chords = [];
161
+ for (let i = 0; i + 1 < points.length; i += 1) {
162
+ const from = points[i];
163
+ const to = points[i + 1];
164
+ chords.push(chordNormal(from.x, from.y, to.x, to.y));
165
+ }
166
+ if (subpath.closed && points.length > 1) {
167
+ const from = points[points.length - 1];
168
+ const to = points[0];
169
+ chords.push(chordNormal(from.x, from.y, to.x, to.y));
170
+ }
171
+ const vertexNormals = points.map((_point, i) => {
172
+ return averageNormal(i === 0 ? subpath.closed ? chords[chords.length - 1] : void 0 : chords[i - 1], chords[i]);
173
+ });
174
+ return {
175
+ startXPt: offsetX(subpath.startXPt, vertexNormals[0], offsetPt),
176
+ startYPt: offsetY(subpath.startYPt, vertexNormals[0], offsetPt),
177
+ closed: subpath.closed,
178
+ segments: subpath.segments.map((segment, i) => {
179
+ const endNormal = vertexNormals[i + 1];
180
+ if (segment.kind === "line") return {
181
+ kind: "line",
182
+ xPt: offsetX(segment.xPt, endNormal, offsetPt),
183
+ yPt: offsetY(segment.yPt, endNormal, offsetPt)
184
+ };
185
+ const controlNormal = chords[i] ?? vertexNormals[i];
186
+ return {
187
+ kind: "cubic",
188
+ c1xPt: offsetX(segment.c1xPt, controlNormal, offsetPt),
189
+ c1yPt: offsetY(segment.c1yPt, controlNormal, offsetPt),
190
+ c2xPt: offsetX(segment.c2xPt, controlNormal, offsetPt),
191
+ c2yPt: offsetY(segment.c2yPt, controlNormal, offsetPt),
192
+ xPt: offsetX(segment.xPt, endNormal, offsetPt),
193
+ yPt: offsetY(segment.yPt, endNormal, offsetPt)
194
+ };
195
+ })
196
+ };
197
+ }
78
198
  function writeFillAndStroke(writer, fill, stroke) {
79
199
  if (fill !== void 0) writeRgbOperator(writer, fill, "rg");
80
200
  if (stroke !== void 0) {
@@ -89,11 +209,36 @@ function writeRect(writer, item) {
89
209
  writer.writeAscii(`${formatNumber(item.xPt)} ${formatNumber(item.yPt)} ${formatNumber(item.widthPt)} ${formatNumber(item.heightPt)} re\n`);
90
210
  writer.writeAscii(`${paint}\n`);
91
211
  }
212
+ function writeDoubleLine(writer, item) {
213
+ writeRgbOperator(writer, item.color, "RG");
214
+ const normal = chordNormal(item.x1Pt, item.y1Pt, item.x2Pt, item.y2Pt);
215
+ if (normal === void 0) {
216
+ writer.writeAscii(`${formatNumber(item.widthPt)} w\n`);
217
+ writer.writeAscii(`${formatNumber(item.x1Pt)} ${formatNumber(item.y1Pt)} m ${formatNumber(item.x2Pt)} ${formatNumber(item.y2Pt)} l\n`);
218
+ writer.writeAscii("S\n");
219
+ return;
220
+ }
221
+ const ruleWidthPt = item.widthPt / DOUBLE_RULE_BANDS;
222
+ const ruleOffsetPt = item.widthPt / DOUBLE_RULE_BANDS;
223
+ writer.writeAscii(`${formatNumber(ruleWidthPt)} w\n`);
224
+ for (const sign of DOUBLE_RULE_SIGNS) {
225
+ const dx = normal.x * ruleOffsetPt * sign;
226
+ const dy = normal.y * ruleOffsetPt * sign;
227
+ writer.writeAscii(`${formatPoint(item.x1Pt + dx, item.y1Pt + dy)} m ${formatPoint(item.x2Pt + dx, item.y2Pt + dy)} l\n`);
228
+ writer.writeAscii("S\n");
229
+ }
230
+ }
92
231
  function writeLine(writer, item) {
232
+ if (item.style === "double") {
233
+ writeDoubleLine(writer, item);
234
+ return;
235
+ }
93
236
  writeRgbOperator(writer, item.color, "RG");
94
237
  writer.writeAscii(`${formatNumber(item.widthPt)} w\n`);
238
+ const styled = writeStrokeStyleState(writer, item.style, item.widthPt);
95
239
  writer.writeAscii(`${formatNumber(item.x1Pt)} ${formatNumber(item.y1Pt)} m ${formatNumber(item.x2Pt)} ${formatNumber(item.y2Pt)} l\n`);
96
240
  writer.writeAscii("S\n");
241
+ if (styled) resetStrokeStyleState(writer, item.style);
97
242
  }
98
243
  function writeEllipse(writer, item) {
99
244
  const paint = paintOperatorFor(item.fill, item.stroke);
@@ -119,12 +264,39 @@ function writeSubpath(writer, subpath) {
119
264
  else writer.writeAscii(`${formatPoint(segment.c1xPt, segment.c1yPt)} ${formatPoint(segment.c2xPt, segment.c2yPt)} ${formatPoint(segment.xPt, segment.yPt)} c\n`);
120
265
  if (subpath.closed) writer.writeAscii("h\n");
121
266
  }
267
+ function writeDoublePath(writer, item, stroke) {
268
+ if (item.fill !== void 0) {
269
+ writeRgbOperator(writer, item.fill, "rg");
270
+ for (const subpath of item.subpaths) writeSubpath(writer, subpath);
271
+ writer.writeAscii(`${item.fillRule === "evenodd" ? "f*" : "f"}\n`);
272
+ }
273
+ const ruleWidthPt = stroke.widthPt / DOUBLE_RULE_BANDS;
274
+ const ruleOffsetPt = stroke.widthPt / DOUBLE_RULE_BANDS;
275
+ writeRgbOperator(writer, stroke.color, "RG");
276
+ writer.writeAscii(`${formatNumber(ruleWidthPt)} w\n`);
277
+ for (const sign of DOUBLE_RULE_SIGNS) {
278
+ for (const subpath of item.subpaths) writeSubpath(writer, offsetSubpath(subpath, ruleOffsetPt * sign));
279
+ writer.writeAscii("S\n");
280
+ }
281
+ }
122
282
  function writePath(writer, item) {
123
283
  const paint = paintOperatorFor(item.fill, item.stroke, item.fillRule);
124
284
  if (paint === void 0) return;
285
+ if (item.stroke === void 0) {
286
+ writeFillAndStroke(writer, item.fill, void 0);
287
+ for (const subpath of item.subpaths) writeSubpath(writer, subpath);
288
+ writer.writeAscii(`${paint}\n`);
289
+ return;
290
+ }
291
+ if (item.style === "double") {
292
+ writeDoublePath(writer, item, item.stroke);
293
+ return;
294
+ }
125
295
  writeFillAndStroke(writer, item.fill, item.stroke);
296
+ const styled = writeStrokeStyleState(writer, item.style, item.stroke.widthPt);
126
297
  for (const subpath of item.subpaths) writeSubpath(writer, subpath);
127
298
  writer.writeAscii(`${paint}\n`);
299
+ if (styled) resetStrokeStyleState(writer, item.style);
128
300
  }
129
301
  function writeImage(writer, item, context) {
130
302
  const image = context.resolveImage(item.imageId);
@@ -26,17 +26,23 @@ interface EmbeddedFace {
26
26
  readonly metrics: EmbeddedFaceMetrics;
27
27
  glyphId(codePoint: number): number | undefined;
28
28
  glyphSpaceWidth(glyphId: number): number;
29
+ kernGlyphSpace(leftGlyphId: number, rightGlyphId: number): number;
29
30
  }
30
31
  declare function loadEmbeddedFace(font: SfntFont): EmbeddedFace | undefined;
31
32
  interface EmbeddedFaceSubstitution {
32
33
  readonly from: string;
33
34
  }
35
+ interface EmbeddedKern {
36
+ readonly codeOffset: number;
37
+ readonly adjustment1000: number;
38
+ }
34
39
  interface EmbeddedShow {
35
40
  readonly codes: Uint8Array<ArrayBuffer>;
36
41
  readonly width1000: number;
37
42
  readonly substitutions: readonly EmbeddedFaceSubstitution[];
43
+ readonly kerns: readonly EmbeddedKern[];
38
44
  }
39
45
  declare function encodeForShowEmbedded(text: string, face: EmbeddedFace): EmbeddedShow;
40
46
  declare function collectEmbeddedGlyphs(texts: Iterable<string>, face: EmbeddedFace): ReadonlyMap<number, number>;
41
47
  //#endregion
42
- export { NOTDEF_GLYPH_ID as a, loadEmbeddedFace as c, EmbeddedShow as i, EmbeddedFaceMetrics as n, collectEmbeddedGlyphs as o, EmbeddedFaceSubstitution as r, encodeForShowEmbedded as s, EmbeddedFace as t };
48
+ export { EmbeddedShow as a, encodeForShowEmbedded as c, EmbeddedKern as i, loadEmbeddedFace as l, EmbeddedFaceMetrics as n, NOTDEF_GLYPH_ID as o, EmbeddedFaceSubstitution as r, collectEmbeddedGlyphs as s, EmbeddedFace as t };
@@ -26,17 +26,23 @@ interface EmbeddedFace {
26
26
  readonly metrics: EmbeddedFaceMetrics;
27
27
  glyphId(codePoint: number): number | undefined;
28
28
  glyphSpaceWidth(glyphId: number): number;
29
+ kernGlyphSpace(leftGlyphId: number, rightGlyphId: number): number;
29
30
  }
30
31
  declare function loadEmbeddedFace(font: SfntFont): EmbeddedFace | undefined;
31
32
  interface EmbeddedFaceSubstitution {
32
33
  readonly from: string;
33
34
  }
35
+ interface EmbeddedKern {
36
+ readonly codeOffset: number;
37
+ readonly adjustment1000: number;
38
+ }
34
39
  interface EmbeddedShow {
35
40
  readonly codes: Uint8Array<ArrayBuffer>;
36
41
  readonly width1000: number;
37
42
  readonly substitutions: readonly EmbeddedFaceSubstitution[];
43
+ readonly kerns: readonly EmbeddedKern[];
38
44
  }
39
45
  declare function encodeForShowEmbedded(text: string, face: EmbeddedFace): EmbeddedShow;
40
46
  declare function collectEmbeddedGlyphs(texts: Iterable<string>, face: EmbeddedFace): ReadonlyMap<number, number>;
41
47
  //#endregion
42
- export { NOTDEF_GLYPH_ID as a, loadEmbeddedFace as c, EmbeddedShow as i, EmbeddedFaceMetrics as n, collectEmbeddedGlyphs as o, EmbeddedFaceSubstitution as r, encodeForShowEmbedded as s, EmbeddedFace as t };
48
+ export { EmbeddedShow as a, encodeForShowEmbedded as c, EmbeddedKern as i, loadEmbeddedFace as l, EmbeddedFaceMetrics as n, NOTDEF_GLYPH_ID as o, EmbeddedFaceSubstitution as r, collectEmbeddedGlyphs as s, EmbeddedFace as t };
@@ -1,5 +1,5 @@
1
1
  import { PdfDict, PdfObject } from "./objects.cjs";
2
- import { t as EmbeddedFace } from "./embedded-font-CLedn-mT.cjs";
2
+ import { t as EmbeddedFace } from "./embedded-font-BU6Jgcof.cjs";
3
3
  import { SfntSubsetResult } from "./sfnt-subset.cjs";
4
4
  //#region src/embedded-font-write.d.ts
5
5
  declare function embeddedSubsetTag(postScriptName: string, glyphIds: readonly number[]): string;
@@ -1,5 +1,5 @@
1
1
  import { PdfDict, PdfObject } from "./objects.js";
2
- import { t as EmbeddedFace } from "./embedded-font-CbqkKgBl.js";
2
+ import { t as EmbeddedFace } from "./embedded-font-fREdbxnr.js";
3
3
  import { SfntSubsetResult } from "./sfnt-subset.js";
4
4
  //#region src/embedded-font-write.d.ts
5
5
  declare function embeddedSubsetTag(postScriptName: string, glyphIds: readonly number[]): string;
@@ -3,6 +3,7 @@ const require_sfnt = require("./sfnt.cjs");
3
3
  const require_cmap_table = require("./cmap-table.cjs");
4
4
  const require_font_tables = require("./font-tables.cjs");
5
5
  const require_glyf = require("./glyf.cjs");
6
+ const require_gpos_table = require("./gpos-table.cjs");
6
7
  const require_hmtx_table = require("./hmtx-table.cjs");
7
8
  //#region src/embedded-font.ts
8
9
  const GLYPH_SPACE_UNITS_PER_EM = 1e3;
@@ -55,6 +56,7 @@ function readEmbeddedFace(font) {
55
56
  const { unitsPerEm } = head;
56
57
  const scale = (designUnits) => scaleToGlyphSpace(designUnits, unitsPerEm);
57
58
  const capHeight = resolveCapHeight(font, cmap, os2?.sCapHeight, hhea.ascent);
59
+ const kern = require_gpos_table.buildGposKernLookup(font);
58
60
  return {
59
61
  font,
60
62
  postScriptName: name.postScriptName,
@@ -83,7 +85,8 @@ function readEmbeddedFace(font) {
83
85
  serif: isSerifByPanose(os2?.panose)
84
86
  },
85
87
  glyphId: (codePoint) => cmap(codePoint),
86
- glyphSpaceWidth: (glyphId) => scale(hmtx.advanceWidth(glyphId))
88
+ glyphSpaceWidth: (glyphId) => scale(hmtx.advanceWidth(glyphId)),
89
+ kernGlyphSpace: kern === void 0 ? () => 0 : (leftGlyphId, rightGlyphId) => scale(kern(leftGlyphId, rightGlyphId) ?? 0)
87
90
  };
88
91
  }
89
92
  const HHEA_TABLE_SIZE = 36;
@@ -104,26 +107,40 @@ function parseHhea(font) {
104
107
  numberOfHMetrics
105
108
  };
106
109
  }
110
+ const CID_BYTE_LENGTH = 2;
107
111
  function encodeForShowEmbedded(text, face) {
108
112
  const glyphIds = [];
109
113
  const substitutions = [];
114
+ const kerns = [];
110
115
  let width1000 = 0;
111
116
  for (const character of text) {
112
117
  const glyphId = face.glyphId(character.codePointAt(0));
113
118
  if (glyphId === void 0) substitutions.push({ from: character });
114
119
  const shown = glyphId ?? 0;
120
+ const previous = glyphIds[glyphIds.length - 1];
121
+ if (previous !== void 0) {
122
+ const adjustment1000 = face.kernGlyphSpace(previous, shown);
123
+ if (adjustment1000 !== 0) {
124
+ kerns.push({
125
+ codeOffset: glyphIds.length * CID_BYTE_LENGTH,
126
+ adjustment1000
127
+ });
128
+ width1000 += adjustment1000;
129
+ }
130
+ }
115
131
  glyphIds.push(shown);
116
132
  width1000 += face.glyphSpaceWidth(shown);
117
133
  }
118
- const codes = new Uint8Array(glyphIds.length * 2);
134
+ const codes = new Uint8Array(glyphIds.length * CID_BYTE_LENGTH);
119
135
  glyphIds.forEach((glyphId, index) => {
120
- codes[index * 2] = glyphId >> 8 & 255;
121
- codes[index * 2 + 1] = glyphId & 255;
136
+ codes[index * CID_BYTE_LENGTH] = glyphId >> 8 & 255;
137
+ codes[index * CID_BYTE_LENGTH + 1] = glyphId & 255;
122
138
  });
123
139
  return {
124
140
  codes,
125
141
  width1000,
126
- substitutions
142
+ substitutions,
143
+ kerns
127
144
  };
128
145
  }
129
146
  function collectEmbeddedGlyphs(texts, face) {
@@ -1,2 +1,2 @@
1
- import { a as NOTDEF_GLYPH_ID, c as loadEmbeddedFace, i as EmbeddedShow, n as EmbeddedFaceMetrics, o as collectEmbeddedGlyphs, r as EmbeddedFaceSubstitution, s as encodeForShowEmbedded, t as EmbeddedFace } from "./embedded-font-CLedn-mT.cjs";
2
- export { EmbeddedFace, EmbeddedFaceMetrics, EmbeddedFaceSubstitution, EmbeddedShow, NOTDEF_GLYPH_ID, collectEmbeddedGlyphs, encodeForShowEmbedded, loadEmbeddedFace };
1
+ import { a as EmbeddedShow, c as encodeForShowEmbedded, i as EmbeddedKern, l as loadEmbeddedFace, n as EmbeddedFaceMetrics, o as NOTDEF_GLYPH_ID, r as EmbeddedFaceSubstitution, s as collectEmbeddedGlyphs, t as EmbeddedFace } from "./embedded-font-BU6Jgcof.cjs";
2
+ export { EmbeddedFace, EmbeddedFaceMetrics, EmbeddedFaceSubstitution, EmbeddedKern, EmbeddedShow, NOTDEF_GLYPH_ID, collectEmbeddedGlyphs, encodeForShowEmbedded, loadEmbeddedFace };
@@ -1,2 +1,2 @@
1
- import { a as NOTDEF_GLYPH_ID, c as loadEmbeddedFace, i as EmbeddedShow, n as EmbeddedFaceMetrics, o as collectEmbeddedGlyphs, r as EmbeddedFaceSubstitution, s as encodeForShowEmbedded, t as EmbeddedFace } from "./embedded-font-CbqkKgBl.js";
2
- export { EmbeddedFace, EmbeddedFaceMetrics, EmbeddedFaceSubstitution, EmbeddedShow, NOTDEF_GLYPH_ID, collectEmbeddedGlyphs, encodeForShowEmbedded, loadEmbeddedFace };
1
+ import { a as EmbeddedShow, c as encodeForShowEmbedded, i as EmbeddedKern, l as loadEmbeddedFace, n as EmbeddedFaceMetrics, o as NOTDEF_GLYPH_ID, r as EmbeddedFaceSubstitution, s as collectEmbeddedGlyphs, t as EmbeddedFace } from "./embedded-font-fREdbxnr.js";
2
+ export { EmbeddedFace, EmbeddedFaceMetrics, EmbeddedFaceSubstitution, EmbeddedKern, EmbeddedShow, NOTDEF_GLYPH_ID, collectEmbeddedGlyphs, encodeForShowEmbedded, loadEmbeddedFace };
@@ -2,6 +2,7 @@ import { hasBytes, i16, sfntTableBytes, u16 } from "./sfnt.js";
2
2
  import { buildCmapLookup } from "./cmap-table.js";
3
3
  import { parseHead, parseMaxp, parseName, parseOs2, parsePost } from "./font-tables.js";
4
4
  import { parseGlyf } from "./glyf.js";
5
+ import { buildGposKernLookup } from "./gpos-table.js";
5
6
  import { parseHmtx } from "./hmtx-table.js";
6
7
  //#region src/embedded-font.ts
7
8
  const GLYPH_SPACE_UNITS_PER_EM = 1e3;
@@ -54,6 +55,7 @@ function readEmbeddedFace(font) {
54
55
  const { unitsPerEm } = head;
55
56
  const scale = (designUnits) => scaleToGlyphSpace(designUnits, unitsPerEm);
56
57
  const capHeight = resolveCapHeight(font, cmap, os2?.sCapHeight, hhea.ascent);
58
+ const kern = buildGposKernLookup(font);
57
59
  return {
58
60
  font,
59
61
  postScriptName: name.postScriptName,
@@ -82,7 +84,8 @@ function readEmbeddedFace(font) {
82
84
  serif: isSerifByPanose(os2?.panose)
83
85
  },
84
86
  glyphId: (codePoint) => cmap(codePoint),
85
- glyphSpaceWidth: (glyphId) => scale(hmtx.advanceWidth(glyphId))
87
+ glyphSpaceWidth: (glyphId) => scale(hmtx.advanceWidth(glyphId)),
88
+ kernGlyphSpace: kern === void 0 ? () => 0 : (leftGlyphId, rightGlyphId) => scale(kern(leftGlyphId, rightGlyphId) ?? 0)
86
89
  };
87
90
  }
88
91
  const HHEA_TABLE_SIZE = 36;
@@ -103,26 +106,40 @@ function parseHhea(font) {
103
106
  numberOfHMetrics
104
107
  };
105
108
  }
109
+ const CID_BYTE_LENGTH = 2;
106
110
  function encodeForShowEmbedded(text, face) {
107
111
  const glyphIds = [];
108
112
  const substitutions = [];
113
+ const kerns = [];
109
114
  let width1000 = 0;
110
115
  for (const character of text) {
111
116
  const glyphId = face.glyphId(character.codePointAt(0));
112
117
  if (glyphId === void 0) substitutions.push({ from: character });
113
118
  const shown = glyphId ?? 0;
119
+ const previous = glyphIds[glyphIds.length - 1];
120
+ if (previous !== void 0) {
121
+ const adjustment1000 = face.kernGlyphSpace(previous, shown);
122
+ if (adjustment1000 !== 0) {
123
+ kerns.push({
124
+ codeOffset: glyphIds.length * CID_BYTE_LENGTH,
125
+ adjustment1000
126
+ });
127
+ width1000 += adjustment1000;
128
+ }
129
+ }
114
130
  glyphIds.push(shown);
115
131
  width1000 += face.glyphSpaceWidth(shown);
116
132
  }
117
- const codes = new Uint8Array(glyphIds.length * 2);
133
+ const codes = new Uint8Array(glyphIds.length * CID_BYTE_LENGTH);
118
134
  glyphIds.forEach((glyphId, index) => {
119
- codes[index * 2] = glyphId >> 8 & 255;
120
- codes[index * 2 + 1] = glyphId & 255;
135
+ codes[index * CID_BYTE_LENGTH] = glyphId >> 8 & 255;
136
+ codes[index * CID_BYTE_LENGTH + 1] = glyphId & 255;
121
137
  });
122
138
  return {
123
139
  codes,
124
140
  width1000,
125
- substitutions
141
+ substitutions,
142
+ kerns
126
143
  };
127
144
  }
128
145
  function collectEmbeddedGlyphs(texts, face) {
@@ -1,5 +1,5 @@
1
1
  import { r as StandardFontName } from "./afm-widths-DyDq56Ph.cjs";
2
- import { t as EmbeddedFace } from "./embedded-font-CLedn-mT.cjs";
2
+ import { t as EmbeddedFace } from "./embedded-font-BU6Jgcof.cjs";
3
3
  import { LayoutFont } from "document-schema.js";
4
4
  //#region src/font-registry.d.ts
5
5
  interface ProvidedFont {
@@ -1,5 +1,5 @@
1
1
  import { r as StandardFontName } from "./afm-widths-DyDq56Ph.js";
2
- import { t as EmbeddedFace } from "./embedded-font-CbqkKgBl.js";
2
+ import { t as EmbeddedFace } from "./embedded-font-fREdbxnr.js";
3
3
  import { LayoutFont } from "document-schema.js";
4
4
  //#region src/font-registry.d.ts
5
5
  interface ProvidedFont {
@@ -1,2 +1,2 @@
1
- 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-yby02snZ.cjs";
1
+ 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";
2
2
  export { FontRegistry, FontRegistryOptions, FontSubstitution, ProvidedFont, ResolvedFace, createFontRegistry, resolveFaceWithRegistry };
@@ -1,2 +1,2 @@
1
- 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-Cn7P9lAh.js";
1
+ 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";
2
2
  export { FontRegistry, FontRegistryOptions, FontSubstitution, ProvidedFont, ResolvedFace, createFontRegistry, resolveFaceWithRegistry };