postext-pdf 1.4.2 → 1.5.1

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 (208) hide show
  1. package/README.md +3 -3
  2. package/dist/__tests__/accessibility.test.js +66 -0
  3. package/dist/__tests__/accessibility.test.js.map +1 -1
  4. package/dist/__tests__/alpha.test.d.ts +2 -0
  5. package/dist/__tests__/alpha.test.d.ts.map +1 -0
  6. package/dist/__tests__/alpha.test.js +164 -0
  7. package/dist/__tests__/alpha.test.js.map +1 -0
  8. package/dist/__tests__/bleedClip.test.d.ts +2 -0
  9. package/dist/__tests__/bleedClip.test.d.ts.map +1 -0
  10. package/dist/__tests__/bleedClip.test.js +83 -0
  11. package/dist/__tests__/bleedClip.test.js.map +1 -0
  12. package/dist/__tests__/boxBorderInside.test.d.ts +2 -0
  13. package/dist/__tests__/boxBorderInside.test.d.ts.map +1 -0
  14. package/dist/__tests__/boxBorderInside.test.js +63 -0
  15. package/dist/__tests__/boxBorderInside.test.js.map +1 -0
  16. package/dist/__tests__/calloutRuntTracking.test.d.ts +2 -0
  17. package/dist/__tests__/calloutRuntTracking.test.d.ts.map +1 -0
  18. package/dist/__tests__/calloutRuntTracking.test.js +72 -0
  19. package/dist/__tests__/calloutRuntTracking.test.js.map +1 -0
  20. package/dist/__tests__/calloutStripeRadius.test.d.ts +2 -0
  21. package/dist/__tests__/calloutStripeRadius.test.d.ts.map +1 -0
  22. package/dist/__tests__/calloutStripeRadius.test.js +90 -0
  23. package/dist/__tests__/calloutStripeRadius.test.js.map +1 -0
  24. package/dist/__tests__/chipVerticalPadding.test.d.ts +2 -0
  25. package/dist/__tests__/chipVerticalPadding.test.d.ts.map +1 -0
  26. package/dist/__tests__/chipVerticalPadding.test.js +71 -0
  27. package/dist/__tests__/chipVerticalPadding.test.js.map +1 -0
  28. package/dist/__tests__/chips.test.js +20 -3
  29. package/dist/__tests__/chips.test.js.map +1 -1
  30. package/dist/__tests__/documentLanguage.test.d.ts +2 -0
  31. package/dist/__tests__/documentLanguage.test.d.ts.map +1 -0
  32. package/dist/__tests__/documentLanguage.test.js +44 -0
  33. package/dist/__tests__/documentLanguage.test.js.map +1 -0
  34. package/dist/__tests__/fallbackSpaces.test.d.ts +2 -0
  35. package/dist/__tests__/fallbackSpaces.test.d.ts.map +1 -0
  36. package/dist/__tests__/fallbackSpaces.test.js +156 -0
  37. package/dist/__tests__/fallbackSpaces.test.js.map +1 -0
  38. package/dist/__tests__/floatReadingOrder.test.d.ts +2 -0
  39. package/dist/__tests__/floatReadingOrder.test.d.ts.map +1 -0
  40. package/dist/__tests__/floatReadingOrder.test.js +208 -0
  41. package/dist/__tests__/floatReadingOrder.test.js.map +1 -0
  42. package/dist/__tests__/fontEmbedding.test.d.ts +2 -0
  43. package/dist/__tests__/fontEmbedding.test.d.ts.map +1 -0
  44. package/dist/__tests__/fontEmbedding.test.js +118 -0
  45. package/dist/__tests__/fontEmbedding.test.js.map +1 -0
  46. package/dist/__tests__/fontFaces.test.d.ts +2 -0
  47. package/dist/__tests__/fontFaces.test.d.ts.map +1 -0
  48. package/dist/__tests__/fontFaces.test.js +193 -0
  49. package/dist/__tests__/fontFaces.test.js.map +1 -0
  50. package/dist/__tests__/fontStack.test.d.ts +2 -0
  51. package/dist/__tests__/fontStack.test.d.ts.map +1 -0
  52. package/dist/__tests__/fontStack.test.js +48 -0
  53. package/dist/__tests__/fontStack.test.js.map +1 -0
  54. package/dist/__tests__/headerFooter.test.js +83 -1
  55. package/dist/__tests__/headerFooter.test.js.map +1 -1
  56. package/dist/__tests__/headingAlign.test.d.ts +2 -0
  57. package/dist/__tests__/headingAlign.test.d.ts.map +1 -0
  58. package/dist/__tests__/headingAlign.test.js +66 -0
  59. package/dist/__tests__/headingAlign.test.js.map +1 -0
  60. package/dist/__tests__/hiddenHeadings.test.d.ts +2 -0
  61. package/dist/__tests__/hiddenHeadings.test.d.ts.map +1 -0
  62. package/dist/__tests__/hiddenHeadings.test.js +96 -0
  63. package/dist/__tests__/hiddenHeadings.test.js.map +1 -0
  64. package/dist/__tests__/lineTracking.test.d.ts +2 -0
  65. package/dist/__tests__/lineTracking.test.d.ts.map +1 -0
  66. package/dist/__tests__/lineTracking.test.js +80 -0
  67. package/dist/__tests__/lineTracking.test.js.map +1 -0
  68. package/dist/__tests__/measuredLines.test.d.ts +2 -0
  69. package/dist/__tests__/measuredLines.test.d.ts.map +1 -0
  70. package/dist/__tests__/measuredLines.test.js +255 -0
  71. package/dist/__tests__/measuredLines.test.js.map +1 -0
  72. package/dist/__tests__/metadata.test.d.ts +2 -0
  73. package/dist/__tests__/metadata.test.d.ts.map +1 -0
  74. package/dist/__tests__/metadata.test.js +51 -0
  75. package/dist/__tests__/metadata.test.js.map +1 -0
  76. package/dist/__tests__/outlineTitles.test.d.ts +2 -0
  77. package/dist/__tests__/outlineTitles.test.d.ts.map +1 -0
  78. package/dist/__tests__/outlineTitles.test.js +59 -0
  79. package/dist/__tests__/outlineTitles.test.js.map +1 -0
  80. package/dist/__tests__/pdfGenerationConfig.test.d.ts +2 -0
  81. package/dist/__tests__/pdfGenerationConfig.test.d.ts.map +1 -0
  82. package/dist/__tests__/pdfGenerationConfig.test.js +76 -0
  83. package/dist/__tests__/pdfGenerationConfig.test.js.map +1 -0
  84. package/dist/__tests__/pdfWorker.test.d.ts +2 -0
  85. package/dist/__tests__/pdfWorker.test.d.ts.map +1 -0
  86. package/dist/__tests__/pdfWorker.test.js +123 -0
  87. package/dist/__tests__/pdfWorker.test.js.map +1 -0
  88. package/dist/__tests__/printMarks.test.d.ts +2 -0
  89. package/dist/__tests__/printMarks.test.d.ts.map +1 -0
  90. package/dist/__tests__/printMarks.test.js +170 -0
  91. package/dist/__tests__/printMarks.test.js.map +1 -0
  92. package/dist/__tests__/printMaster.test.d.ts +2 -0
  93. package/dist/__tests__/printMaster.test.d.ts.map +1 -0
  94. package/dist/__tests__/printMaster.test.js +161 -0
  95. package/dist/__tests__/printMaster.test.js.map +1 -0
  96. package/dist/__tests__/renderWarnings.test.d.ts +2 -0
  97. package/dist/__tests__/renderWarnings.test.d.ts.map +1 -0
  98. package/dist/__tests__/renderWarnings.test.js +89 -0
  99. package/dist/__tests__/renderWarnings.test.js.map +1 -0
  100. package/dist/__tests__/repeatedHyphen.test.d.ts +2 -0
  101. package/dist/__tests__/repeatedHyphen.test.d.ts.map +1 -0
  102. package/dist/__tests__/repeatedHyphen.test.js +125 -0
  103. package/dist/__tests__/repeatedHyphen.test.js.map +1 -0
  104. package/dist/__tests__/scriptStacking.test.d.ts +2 -0
  105. package/dist/__tests__/scriptStacking.test.d.ts.map +1 -0
  106. package/dist/__tests__/scriptStacking.test.js +66 -0
  107. package/dist/__tests__/scriptStacking.test.js.map +1 -0
  108. package/dist/__tests__/sectionColumnRule.test.d.ts +2 -0
  109. package/dist/__tests__/sectionColumnRule.test.d.ts.map +1 -0
  110. package/dist/__tests__/sectionColumnRule.test.js +144 -0
  111. package/dist/__tests__/sectionColumnRule.test.js.map +1 -0
  112. package/dist/__tests__/svgFormReuse.test.d.ts +2 -0
  113. package/dist/__tests__/svgFormReuse.test.d.ts.map +1 -0
  114. package/dist/__tests__/svgFormReuse.test.js +102 -0
  115. package/dist/__tests__/svgFormReuse.test.js.map +1 -0
  116. package/dist/__tests__/svgVector.test.js +85 -11
  117. package/dist/__tests__/svgVector.test.js.map +1 -1
  118. package/dist/__tests__/tableFillSeams.test.d.ts +2 -0
  119. package/dist/__tests__/tableFillSeams.test.d.ts.map +1 -0
  120. package/dist/__tests__/tableFillSeams.test.js +72 -0
  121. package/dist/__tests__/tableFillSeams.test.js.map +1 -0
  122. package/dist/__tests__/tocLeaderKerning.test.d.ts +2 -0
  123. package/dist/__tests__/tocLeaderKerning.test.d.ts.map +1 -0
  124. package/dist/__tests__/tocLeaderKerning.test.js +84 -0
  125. package/dist/__tests__/tocLeaderKerning.test.js.map +1 -0
  126. package/dist/__tests__/tocNumberBaseline.test.d.ts +2 -0
  127. package/dist/__tests__/tocNumberBaseline.test.d.ts.map +1 -0
  128. package/dist/__tests__/tocNumberBaseline.test.js +72 -0
  129. package/dist/__tests__/tocNumberBaseline.test.js.map +1 -0
  130. package/dist/__tests__/tocTagging.test.d.ts +2 -0
  131. package/dist/__tests__/tocTagging.test.d.ts.map +1 -0
  132. package/dist/__tests__/tocTagging.test.js +120 -0
  133. package/dist/__tests__/tocTagging.test.js.map +1 -0
  134. package/dist/__tests__/trackedLineAlign.test.d.ts +2 -0
  135. package/dist/__tests__/trackedLineAlign.test.d.ts.map +1 -0
  136. package/dist/__tests__/trackedLineAlign.test.js +73 -0
  137. package/dist/__tests__/trackedLineAlign.test.js.map +1 -0
  138. package/dist/__tests__/uriLinks.test.d.ts +2 -0
  139. package/dist/__tests__/uriLinks.test.d.ts.map +1 -0
  140. package/dist/__tests__/uriLinks.test.js +103 -0
  141. package/dist/__tests__/uriLinks.test.js.map +1 -0
  142. package/dist/colors.d.ts +18 -3
  143. package/dist/colors.d.ts.map +1 -1
  144. package/dist/colors.js +77 -25
  145. package/dist/colors.js.map +1 -1
  146. package/dist/fontCache.d.ts +67 -4
  147. package/dist/fontCache.d.ts.map +1 -1
  148. package/dist/fontCache.js +200 -23
  149. package/dist/fontCache.js.map +1 -1
  150. package/dist/index.d.ts +1 -1
  151. package/dist/index.d.ts.map +1 -1
  152. package/dist/pdf-backend/blockRender.d.ts.map +1 -1
  153. package/dist/pdf-backend/blockRender.js +127 -28
  154. package/dist/pdf-backend/blockRender.js.map +1 -1
  155. package/dist/pdf-backend/fallbackSpaces.d.ts +37 -0
  156. package/dist/pdf-backend/fallbackSpaces.d.ts.map +1 -0
  157. package/dist/pdf-backend/fallbackSpaces.js +119 -0
  158. package/dist/pdf-backend/fallbackSpaces.js.map +1 -0
  159. package/dist/pdf-backend/fontHelpers.d.ts +10 -1
  160. package/dist/pdf-backend/fontHelpers.d.ts.map +1 -1
  161. package/dist/pdf-backend/fontHelpers.js +111 -65
  162. package/dist/pdf-backend/fontHelpers.js.map +1 -1
  163. package/dist/pdf-backend/headerFooter.d.ts +4 -2
  164. package/dist/pdf-backend/headerFooter.d.ts.map +1 -1
  165. package/dist/pdf-backend/headerFooter.js +105 -48
  166. package/dist/pdf-backend/headerFooter.js.map +1 -1
  167. package/dist/pdf-backend/index.d.ts +55 -6
  168. package/dist/pdf-backend/index.d.ts.map +1 -1
  169. package/dist/pdf-backend/index.js +135 -35
  170. package/dist/pdf-backend/index.js.map +1 -1
  171. package/dist/pdf-backend/links.d.ts +82 -1
  172. package/dist/pdf-backend/links.d.ts.map +1 -1
  173. package/dist/pdf-backend/links.js +141 -3
  174. package/dist/pdf-backend/links.js.map +1 -1
  175. package/dist/pdf-backend/outlines.d.ts.map +1 -1
  176. package/dist/pdf-backend/outlines.js +7 -0
  177. package/dist/pdf-backend/outlines.js.map +1 -1
  178. package/dist/pdf-backend/pageDecorations.d.ts.map +1 -1
  179. package/dist/pdf-backend/pageDecorations.js +42 -26
  180. package/dist/pdf-backend/pageDecorations.js.map +1 -1
  181. package/dist/pdf-backend/primitives.d.ts +61 -1
  182. package/dist/pdf-backend/primitives.d.ts.map +1 -1
  183. package/dist/pdf-backend/primitives.js +318 -18
  184. package/dist/pdf-backend/primitives.js.map +1 -1
  185. package/dist/pdf-backend/renderResourceBlock.d.ts +3 -1
  186. package/dist/pdf-backend/renderResourceBlock.d.ts.map +1 -1
  187. package/dist/pdf-backend/renderResourceBlock.js +97 -19
  188. package/dist/pdf-backend/renderResourceBlock.js.map +1 -1
  189. package/dist/pdf-backend/structureFlow.d.ts +70 -3
  190. package/dist/pdf-backend/structureFlow.d.ts.map +1 -1
  191. package/dist/pdf-backend/structureFlow.js +209 -27
  192. package/dist/pdf-backend/structureFlow.js.map +1 -1
  193. package/dist/pdf-backend/svgVector.d.ts +7 -2
  194. package/dist/pdf-backend/svgVector.d.ts.map +1 -1
  195. package/dist/pdf-backend/svgVector.js +157 -72
  196. package/dist/pdf-backend/svgVector.js.map +1 -1
  197. package/dist/pdf-backend/tagging.d.ts +1 -1
  198. package/dist/pdf-backend/tagging.d.ts.map +1 -1
  199. package/dist/pdf-backend/tagging.js.map +1 -1
  200. package/dist/worker/client.d.ts +1 -1
  201. package/dist/worker/client.d.ts.map +1 -1
  202. package/dist/worker/client.js +8 -0
  203. package/dist/worker/client.js.map +1 -1
  204. package/dist/worker/pdf.worker.js +1 -0
  205. package/dist/worker/pdf.worker.js.map +1 -1
  206. package/dist/worker/protocol.d.ts +8 -1
  207. package/dist/worker/protocol.d.ts.map +1 -1
  208. package/package.json +3 -3
@@ -0,0 +1,72 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import { PDFArray, PDFDocument, PDFRawStream, decodePDFRawStream } from 'pdf-lib';
4
+ import { buildDocument } from 'postext';
5
+ import { renderToPdf } from '../pdf-backend';
6
+ // EF-111: a box paragraph set one line shorter with negative tracking (the
7
+ // runt fix, `bodyText.maxRuntTracking`) is painted with that tracking, as a
8
+ // paragraph of the running text is.
9
+ const fontBytes = fs.readFileSync(new URL('../../../../apps/web/public/fonts/Lora-Regular.ttf', import.meta.url));
10
+ const fontProvider = async () => new Uint8Array(fontBytes);
11
+ // Widths that vary by character, so the breaks fall in many places.
12
+ const W = (ch) => {
13
+ if (ch === ' ')
14
+ return 0.25;
15
+ if ('il.,;:!|\'()'.includes(ch))
16
+ return 0.28;
17
+ if ('mwMW'.includes(ch))
18
+ return 0.8;
19
+ if (/[A-Z]/.test(ch))
20
+ return 0.66;
21
+ return 0.5;
22
+ };
23
+ class StubCtx {
24
+ font = '';
25
+ measureText(s) {
26
+ const size = parseFloat(/(\d*\.?\d+)px/.exec(this.font)?.[1] ?? '10');
27
+ let w = 0;
28
+ for (const ch of s)
29
+ w += W(ch) * size;
30
+ return { width: w };
31
+ }
32
+ }
33
+ globalThis.OffscreenCanvas = class {
34
+ getContext() {
35
+ return new StubCtx();
36
+ }
37
+ };
38
+ const pt = (value) => ({ value, unit: 'pt' });
39
+ const CONFIG = {
40
+ page: { width: pt(160), height: pt(300), dpi: 72, margins: { top: pt(10), bottom: pt(10), left: pt(10), right: pt(10) } },
41
+ layout: { layoutType: 'single' },
42
+ header: { elements: [] },
43
+ footer: { elements: [] },
44
+ bodyText: { fontFamily: 'Lora', fontSize: pt(10), lineHeight: pt(14), firstLineIndent: pt(0), hyphenation: { enabled: false } },
45
+ calloutStyles: [{ id: 'n', padding: { top: pt(0), bottom: pt(0), left: pt(0), right: pt(0) } }],
46
+ };
47
+ const TEXT = 'and within a is its within lets left its osmosis a left and within a is its within lets left its.';
48
+ async function contentOf(doc) {
49
+ const pdf = await PDFDocument.load(await renderToPdf(doc, { fontProvider, accessible: false }));
50
+ const contents = pdf.getPage(0).node.Contents();
51
+ const refs = contents instanceof PDFArray ? contents.asArray() : [contents];
52
+ return refs
53
+ .map((ref) => {
54
+ const s = pdf.context.lookup(ref);
55
+ return s instanceof PDFRawStream ? new TextDecoder('latin1').decode(decodePDFRawStream(s).decode()) : '';
56
+ })
57
+ .join('\n');
58
+ }
59
+ const spacings = (content) => [...content.matchAll(/(-?[\d.]+) Tc/g)].map((m) => Number(m[1]));
60
+ describe('runt tracking inside a box in the PDF (EF-111)', () => {
61
+ it('sets the character spacing of every line of the box paragraph', async () => {
62
+ const doc = buildDocument({ markdown: `:::callout{type="n"}\n${TEXT}\n:::` }, CONFIG);
63
+ const boxed = doc.blocks.find((b) => b.type === 'paragraph');
64
+ expect(boxed.containerId).toBeDefined();
65
+ expect(boxed.letterSpacing).toBeCloseTo(-0.1, 5);
66
+ const set = spacings(await contentOf(doc)).filter((v) => v !== 0);
67
+ expect(set).toHaveLength(boxed.lines.length);
68
+ for (const v of set)
69
+ expect(v).toBeCloseTo(-0.1, 5);
70
+ }, 60_000);
71
+ });
72
+ //# sourceMappingURL=calloutRuntTracking.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calloutRuntTracking.test.js","sourceRoot":"","sources":["../../src/__tests__/calloutRuntTracking.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=calloutStripeRadius.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calloutStripeRadius.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/calloutStripeRadius.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,90 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import { PDFArray, PDFDocument, PDFRawStream, decodePDFRawStream } from 'pdf-lib';
4
+ import fontkit from '@pdf-lib/fontkit';
5
+ import { buildDocument } from 'postext';
6
+ import { renderToPdf } from '../pdf-backend';
7
+ import { parseFontString } from '../fontString';
8
+ // EF-99: the stripe of a rounded callout is clipped to the frame's rounded
9
+ // rectangle in the PDF, as on canvas and in HTML.
10
+ const fontBytes = fs.readFileSync(new URL('../../../../apps/web/public/fonts/Lora-Regular.ttf', import.meta.url));
11
+ const fontProvider = async () => new Uint8Array(fontBytes);
12
+ const face = fontkit.create(fontBytes);
13
+ class StubCtx {
14
+ font = '';
15
+ measureText(s) {
16
+ const sizePx = parseFontString(this.font)?.sizePx ?? 16;
17
+ const run = face.layout(s);
18
+ return { width: (run.advanceWidth / face.unitsPerEm) * sizePx };
19
+ }
20
+ }
21
+ globalThis.OffscreenCanvas = class {
22
+ getContext() {
23
+ return new StubCtx();
24
+ }
25
+ };
26
+ const pt = (value) => ({ value, unit: 'pt' });
27
+ const mm = (value) => ({ value, unit: 'mm' });
28
+ const hex = (h) => ({ hex: h, model: 'hex' });
29
+ const config = (extra) => ({
30
+ page: { width: pt(300), height: pt(300), margins: { top: pt(20), bottom: pt(20), left: pt(20), right: pt(20) } },
31
+ headings: { balancing: { enabled: false } },
32
+ layout: { layoutType: 'single' },
33
+ calloutStyles: [{
34
+ id: 'note',
35
+ background: hex('#eef2f7'),
36
+ stripe: { enabled: true, side: 'left', width: mm(3), color: hex('#2d5a8a') },
37
+ ...extra,
38
+ }],
39
+ });
40
+ async function pageOps(cfg) {
41
+ const doc = buildDocument({ markdown: ':::callout{type="note"}\nSome text.\n:::' }, cfg);
42
+ const bytes = await renderToPdf(doc, { fontProvider });
43
+ const pdf = await PDFDocument.load(bytes);
44
+ const contents = pdf.getPage(0).node.Contents();
45
+ const streams = contents instanceof PDFArray ? contents.asArray().map((r) => pdf.context.lookup(r)) : [contents];
46
+ return streams
47
+ .map((s) => (s instanceof PDFRawStream ? Buffer.from(decodePDFRawStream(s).decode()).toString('latin1') : ''))
48
+ .join('\n');
49
+ }
50
+ /** The operators between the last clip before the stripe's fill colour and
51
+ * that fill, plus the path the clip was built from. */
52
+ function clipBeforeStripe(ops) {
53
+ // #2d5a8a → 0.17647 0.35294 0.54118 rg (pdf-lib prints up to 5 decimals).
54
+ const fill = /0\.176\d* 0\.352\d* 0\.541\d* rg/.exec(ops);
55
+ if (!fill)
56
+ throw new Error('no stripe fill');
57
+ const before = ops.slice(0, fill.index);
58
+ const clipAt = before.search(/W\s+n\s*(?![\s\S]*W\s+n)/);
59
+ if (clipAt < 0)
60
+ return null;
61
+ const pathStart = before.lastIndexOf('q', clipAt);
62
+ return { path: before.slice(pathStart, clipAt), between: before.slice(clipAt) };
63
+ }
64
+ describe('EF-99: a rounded callout clips its stripe in the PDF', () => {
65
+ it('clips the stripe to a curved outline that is still in force when it is filled', async () => {
66
+ const ops = await pageOps(config({ borderRadius: mm(3) }));
67
+ const clip = clipBeforeStripe(ops);
68
+ expect(clip).not.toBeNull();
69
+ // Bézier corners in the clip path.
70
+ expect(/ c\n/.test(clip.path)).toBe(true);
71
+ // The clip's graphics state has not been popped before the fill.
72
+ const opens = (clip.between.match(/\bq\b/g) ?? []).length;
73
+ const closes = (clip.between.match(/\bQ\b/g) ?? []).length;
74
+ expect(closes).toBeLessThanOrEqual(opens);
75
+ // Balanced graphics state over the page.
76
+ expect((ops.match(/\bq\b/g) ?? []).length).toBe((ops.match(/\bQ\b/g) ?? []).length);
77
+ // Tagged output: the stripe is decoration, marked as an artifact inside
78
+ // the clip's graphics state (marked content nests within q … Q).
79
+ const artifactAt = clip.between.lastIndexOf('/Artifact');
80
+ expect(artifactAt).toBeGreaterThan(-1);
81
+ expect(clip.between.slice(artifactAt)).not.toMatch(/\bEMC\b/);
82
+ });
83
+ it('draws a square frame\'s stripe without a clip of its own (unchanged output)', async () => {
84
+ const ops = await pageOps(config({ borderRadius: mm(0) }));
85
+ // Only the column's rectangular clip encloses it.
86
+ const clip = clipBeforeStripe(ops);
87
+ expect(clip === null || !/ c\n/.test(clip.path)).toBe(true);
88
+ });
89
+ });
90
+ //# sourceMappingURL=calloutStripeRadius.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calloutStripeRadius.test.js","sourceRoot":"","sources":["../../src/__tests__/calloutStripeRadius.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chipVerticalPadding.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chipVerticalPadding.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/chipVerticalPadding.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,71 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import { PDFArray, PDFDocument, PDFRawStream, decodePDFRawStream } from 'pdf-lib';
4
+ import fontkit from '@pdf-lib/fontkit';
5
+ import { buildDocument } from 'postext';
6
+ import { renderToPdf } from '../pdf-backend';
7
+ import { parseFontString } from '../fontString';
8
+ const fontBytes = fs.readFileSync(new URL('../../../../apps/web/public/fonts/Lora-Regular.ttf', import.meta.url));
9
+ const fontProvider = async () => new Uint8Array(fontBytes);
10
+ const face = fontkit.create(fontBytes);
11
+ class StubCtx {
12
+ font = '';
13
+ measureText(s) {
14
+ const sizePx = parseFontString(this.font)?.sizePx ?? 16;
15
+ const run = face.layout(s);
16
+ return { width: (run.advanceWidth / face.unitsPerEm) * sizePx };
17
+ }
18
+ }
19
+ globalThis.OffscreenCanvas = class {
20
+ getContext() {
21
+ return new StubCtx();
22
+ }
23
+ };
24
+ // EF-172: a chip padded apart at the top and the bottom. At 72 dpi a
25
+ // pixel is a point, so the PDF box is the VDT box.
26
+ const pt = (value) => ({ value, unit: 'pt' });
27
+ const em = (value) => ({ value, unit: 'em' });
28
+ const config = (chip) => ({
29
+ page: { width: pt(220), height: pt(200), dpi: 72, margins: { top: pt(20), bottom: pt(20), left: pt(20), right: pt(20) } },
30
+ layout: { layoutType: 'single' },
31
+ headings: { balancing: { enabled: false } },
32
+ bodyText: { fontSize: pt(10), lineHeight: pt(14), textAlign: 'left' },
33
+ // A square box in a colour of its own, with no outline.
34
+ chipStyles: [{ id: 'b', background: { hex: '#336699', model: 'hex' }, borderWidth: pt(0), borderRadius: pt(0), ...chip }],
35
+ });
36
+ function pageContent(doc) {
37
+ const contents = doc.getPage(0).node.Contents();
38
+ const refs = contents instanceof PDFArray ? contents.asArray() : [contents];
39
+ return refs
40
+ .map((ref) => {
41
+ const s = doc.context.lookup(ref);
42
+ return s instanceof PDFRawStream ? new TextDecoder('latin1').decode(decodePDFRawStream(s).decode()) : '';
43
+ })
44
+ .join('\n');
45
+ }
46
+ /** The top and bottom (PDF y) of the first path filled in #336699. */
47
+ function boxYs(content) {
48
+ const at = content.indexOf('0.2 0.4 0.6 rg');
49
+ expect(at).toBeGreaterThanOrEqual(0);
50
+ const path = content.slice(at, content.indexOf('\nf\n', at));
51
+ const ys = [...path.matchAll(/(-?[\d.]+) (-?[\d.]+) [ml]\n/g)].map((m) => Number(m[2]));
52
+ return { top: Math.max(...ys), bottom: Math.min(...ys) };
53
+ }
54
+ const chipOf = (doc) => doc.blocks.flatMap((b) => b.lines.flatMap((l) => (l.segments ?? []).map((s) => ({ s, l })))).find(({ s }) => s.kind === 'chip');
55
+ describe('chip paddingTop / paddingBottom in the PDF (EF-172)', () => {
56
+ it('paints the box the layout gives it, taller above the baseline than below', async () => {
57
+ const doc = buildDocument({ markdown: 'Answer :chip[A]{style="b"} here.' }, config({ paddingTop: em(0.2), paddingBottom: em(0.02) }));
58
+ const { s, l } = chipOf(doc);
59
+ const pdf = await PDFDocument.load(await renderToPdf(doc, { fontProvider }));
60
+ const { top, bottom } = boxYs(pageContent(pdf));
61
+ const pageH = 200;
62
+ // PDF y grows upwards: the baseline sits at pageH − baseline.
63
+ const baseline = pageH - l.baseline;
64
+ expect(top - baseline).toBeCloseTo(s.chip.ascent, 2);
65
+ expect(baseline - bottom).toBeCloseTo(s.chip.descent, 2);
66
+ // 1 em of text: 0.8 + 0.2 above, 0.25 + 0.02 below.
67
+ expect(top - baseline).toBeCloseTo(10, 2);
68
+ expect(baseline - bottom).toBeCloseTo(2.7, 2);
69
+ });
70
+ });
71
+ //# sourceMappingURL=chipVerticalPadding.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chipVerticalPadding.test.js","sourceRoot":"","sources":["../../src/__tests__/chipVerticalPadding.test.ts"],"names":[],"mappings":"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"}
@@ -61,12 +61,12 @@ const markdown = [
61
61
  ].join('\n');
62
62
  let pdf;
63
63
  let bytes;
64
- function pageContent(index) {
65
- const contents = pdf.getPage(index).node.Contents();
64
+ function pageContent(index, doc = pdf) {
65
+ const contents = doc.getPage(index).node.Contents();
66
66
  const refs = contents instanceof PDFArray ? contents.asArray() : [contents];
67
67
  return refs
68
68
  .map((ref) => {
69
- const s = pdf.context.lookup(ref);
69
+ const s = doc.context.lookup(ref);
70
70
  return s instanceof PDFRawStream ? new TextDecoder('latin1').decode(decodePDFRawStream(s).decode()) : '';
71
71
  })
72
72
  .join('\n');
@@ -110,5 +110,22 @@ describe('inline chips in the PDF', () => {
110
110
  }
111
111
  expect(text).toMatch(/pila cable interruptor/);
112
112
  });
113
+ // EF-02: a chip of spaces is an empty box (an answer blank), not markup.
114
+ it('paints an empty chip as a box with no text', async () => {
115
+ const doc = buildDocument({ markdown: 'Respuesta: :chip[ ]{style="key"} y fin.' }, config);
116
+ const out = await PDFDocument.load(await renderToPdf(doc, { fontProvider }));
117
+ const content = pageContent(0, out);
118
+ expect(content).toMatch(/\/Artifact <<\n\/Type \/Layout\n>> BDC/);
119
+ expect(/\bf\n/.test(content)).toBe(true);
120
+ expect((content.match(/\b(BDC|BMC)\n/g) ?? []).length).toBe((content.match(/\bEMC\n/g) ?? []).length);
121
+ if (hasPdftotext) {
122
+ const file = path.join(os.tmpdir(), `postext-empty-chip-${process.pid}.pdf`);
123
+ fs.writeFileSync(file, await out.save());
124
+ const text = execFileSync('pdftotext', ['-raw', file, '-'], { encoding: 'utf8' }).replace(/\s+/g, ' ');
125
+ fs.unlinkSync(file);
126
+ expect(text).toMatch(/Respuesta: y fin\./);
127
+ expect(text).not.toContain(':chip');
128
+ }
129
+ });
113
130
  });
114
131
  //# sourceMappingURL=chips.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chips.test.js","sourceRoot":"","sources":["../../src/__tests__/chips.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chips.test.js","sourceRoot":"","sources":["../../src/__tests__/chips.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClF,OAAO,OAAO,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,oDAAoD,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAClH,MAAM,YAAY,GAAG,KAAK,IAAI,EAAE,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;AAC3D,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAEvC,MAAM,OAAO;IACX,IAAI,GAAG,EAAE,CAAC;IACV,WAAW,CAAC,CAAS;QACnB,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC;QACxD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC3B,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,MAAM,EAAE,CAAC;IAClE,CAAC;CACF;AACA,UAAsD,CAAC,eAAe,GAAG;IACxE,UAAU;QACR,OAAO,IAAI,OAAO,EAAE,CAAC;IACvB,CAAC;CACF,CAAC;AAEF,MAAM,EAAE,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAa,EAAE,CAAC,CAAC;AAC/D,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,KAAc,EAAE,CAAC,CAAC;AAE/D,0EAA0E;AAC1E,oCAAoC;AACpC,MAAM,MAAM,GAAkB;IAC5B,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;IAChH,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE;IACpG,QAAQ,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE;IAClC,UAAU,EAAE;QACV,EAAE,EAAE,EAAE,MAAM,EAAE;QACd,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;KACxG;CACF,CAAC;AAEF,MAAM,SAAS,GAAe,CAAC;QAC7B,EAAE,EAAE,MAAM;QACV,MAAM,EAAE,OAAO;QACf,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,oBAAoB;QAC7B,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,CAAC;QACZ,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAC,CAAC,EAAE,EAAE;QACzI,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;KAChC,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG;IACf,uJAAuJ;IACvJ,EAAE;IACF,yCAAyC;IACzC,EAAE;IACF,YAAY;IACZ,sDAAsD;IACtD,KAAK;IACL,EAAE;IACF,uBAAuB;CACxB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,IAAI,GAAgB,CAAC;AACrB,IAAI,KAAiB,CAAC;AAEtB,SAAS,WAAW,CAAC,KAAa,EAAE,MAAmB,GAAG;IACxD,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IACpD,MAAM,IAAI,GAAG,QAAQ,YAAY,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC5E,OAAO,IAAI;SACR,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACX,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAClC,OAAO,CAAC,YAAY,YAAY,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3G,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,GAAG,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IACzF,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;IACjD,mEAAmE;IACnE,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe;QAAE,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACtF,GAAG,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC,EAAE,MAAM,CAAC,CAAC;AAEX,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE;IACzB,IAAI,CAAC;QACH,YAAY,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC,EAAE,CAAC;AAEL,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;QAClE,oEAAoE;QACpE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QAC5F,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QAC7D,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACzF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iBAAiB,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;QACxE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACvG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACpB,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC;YAC9H,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,yEAAyE;IACzE,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,GAAG,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,yCAAyC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC3F,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,MAAM,WAAW,CAAC,GAAG,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;QAC7E,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACpC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;QAClE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QACtG,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,sBAAsB,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;YAC7E,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACzC,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YACvG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;YAC3C,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=documentLanguage.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documentLanguage.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/documentLanguage.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,44 @@
1
+ import { describe, it, expect, vi, afterEach } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import { PDFDocument, PDFHexString, PDFName, PDFString } from 'pdf-lib';
4
+ import { buildDocument } from 'postext';
5
+ import { renderToPdf } from '../pdf-backend';
6
+ const fontBytes = fs.readFileSync(new URL('../../../../apps/web/public/fonts/Lora-Regular.ttf', import.meta.url));
7
+ const fontProvider = async () => new Uint8Array(fontBytes);
8
+ // Deterministic text measurement stub (no DOM in the node test env).
9
+ class StubCtx {
10
+ font = '';
11
+ measureText(s) {
12
+ return { width: s.length * 7 };
13
+ }
14
+ }
15
+ globalThis.OffscreenCanvas = class {
16
+ getContext() {
17
+ return new StubCtx();
18
+ }
19
+ };
20
+ const textOf = (obj) => obj instanceof PDFString || obj instanceof PDFHexString ? obj.decodeText() : undefined;
21
+ /** The `/Lang` an accessible PDF of a one-line document declares. */
22
+ async function lang(config) {
23
+ const doc = buildDocument({ markdown: '# Title\n\nText.' }, { bodyText: { fontFamily: 'Lora' }, ...config });
24
+ const pdf = await PDFDocument.load(await renderToPdf(doc, { fontProvider }));
25
+ return textOf(pdf.catalog.get(PDFName.of('Lang')));
26
+ }
27
+ afterEach(() => vi.restoreAllMocks());
28
+ describe('document language (/Lang)', () => {
29
+ it('declares a bundled locale in canonical case', async () => {
30
+ expect(await lang({})).toBe('en-US');
31
+ expect(await lang({ locale: 'es' })).toBe('es');
32
+ });
33
+ it('keeps the region of a region-tagged locale that hyphenates with its language', async () => {
34
+ expect(await lang({ locale: 'es-ES' })).toBe('es-ES');
35
+ expect(await lang({ bodyText: { fontFamily: 'Lora', hyphenation: { locale: 'pt_br' } } })).toBe('pt-BR');
36
+ expect(await lang({ locale: 'ca-ES-valencia' })).toBe('ca-ES-valencia');
37
+ });
38
+ it('declares a language without bundled patterns as given, not the en-us fallback', async () => {
39
+ vi.spyOn(console, 'warn').mockImplementation(() => { });
40
+ expect(await lang({ locale: 'sv' })).toBe('sv');
41
+ expect(await lang({ locale: 'zh-Hant-TW' })).toBe('zh-Hant-TW');
42
+ });
43
+ });
44
+ //# sourceMappingURL=documentLanguage.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documentLanguage.test.js","sourceRoot":"","sources":["../../src/__tests__/documentLanguage.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fallbackSpaces.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallbackSpaces.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fallbackSpaces.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,156 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import { PDFArray, PDFDocument, PDFNumber, PDFRawStream, decodePDFRawStream } from 'pdf-lib';
4
+ import fontkit from '@pdf-lib/fontkit';
5
+ import { buildDocument } from 'postext';
6
+ import { showTextShaped } from '../pdf-backend/primitives';
7
+ import { renderToPdf } from '../pdf-backend';
8
+ // EF-66: a no-break space glues its words, and the docs recommend the
9
+ // narrow no-break space (10 %) and the figure space (225 000). Most shipped
10
+ // faces have no glyph for them, nor for the word joiner or U+FEFF. The
11
+ // canvas measured them as the browser's shaper sets them — the face's space
12
+ // glyph at half its width, at a digit's width; invisible characters with no
13
+ // advance — while pdf-lib drew glyph 0, the notdef box (1/2 em in
14
+ // Newsreader), and pushed the rest of the word along. The PDF now paints
15
+ // them as the canvas did.
16
+ const face = (path) => fs.readFileSync(new URL(`../../../../apps/web/public/${path}`, import.meta.url));
17
+ const NEWSREADER = face('presets/deep-sky/fonts/Newsreader-Regular.ttf');
18
+ const SOURCE_SERIF = face('presets/openstax-fisica/fonts/SourceSerif4-Regular.ttf');
19
+ const EB_GARAMOND_BOLD = face('presets/pintura-espanola/fonts/EBGaramond-Bold.ttf');
20
+ async function embed(bytes, subset) {
21
+ const doc = await PDFDocument.create();
22
+ doc.registerFontkit(fontkit);
23
+ const font = await doc.embedFont(bytes, { subset });
24
+ return { font, face: fontkit.create(bytes) };
25
+ }
26
+ /** The glyph ids and adjustments a viewer reads from the operator. */
27
+ function operatorParts(font, text) {
28
+ const op = showTextShaped(font, text);
29
+ const arg = op.args[0];
30
+ const items = arg instanceof PDFArray ? arg.asArray() : [arg];
31
+ return items.map((item) => {
32
+ if (item instanceof PDFNumber)
33
+ return item.asNumber();
34
+ const hex = item.asString();
35
+ return Array.from({ length: hex.length / 4 }, (_, i) => parseInt(hex.slice(i * 4, i * 4 + 4), 16));
36
+ });
37
+ }
38
+ const glyphIds = (font, text) => operatorParts(font, text).flatMap((p) => (typeof p === 'number' ? [] : p));
39
+ /** Advance of the operator (whole-font embedding: glyph ids are the face's),
40
+ * in 1000-unit text space. */
41
+ function paintedWidth(font, f, text) {
42
+ let width = 0;
43
+ for (const part of operatorParts(font, text)) {
44
+ if (typeof part === 'number')
45
+ width -= part;
46
+ else
47
+ for (const id of part)
48
+ width += (f.getGlyph(id).advanceWidth * 1000) / f.unitsPerEm;
49
+ }
50
+ return width;
51
+ }
52
+ const shaped = (f, text) => (f.layout(text).positions.reduce((s, p) => s + p.xAdvance, 0) * 1000) / f.unitsPerEm;
53
+ const advance = (f, cp) => (f.glyphForCodePoint(cp).advanceWidth * 1000) / f.unitsPerEm;
54
+ describe('spaces and invisible characters the face has no glyph for (EF-66)', () => {
55
+ it('Newsreader lacks them (the reason for the fallback)', () => {
56
+ const f = fontkit.create(NEWSREADER);
57
+ for (const cp of [0x202f, 0x2007, 0x2009, 0x2060, 0xfeff])
58
+ expect(f.hasGlyphForCodePoint(cp)).toBe(false);
59
+ expect(f.hasGlyphForCodePoint(0x00a0)).toBe(true);
60
+ });
61
+ for (const subset of [true, false]) {
62
+ it(`never paints the notdef glyph (subset: ${subset})`, async () => {
63
+ const { font } = await embed(NEWSREADER, subset);
64
+ for (const text of ['10 %', '225 000', '1 000', 'ab', 'x⁠y', ' ', '⁠', 'p. 12']) {
65
+ expect(glyphIds(font, text), JSON.stringify(text)).not.toContain(0);
66
+ }
67
+ });
68
+ }
69
+ it('sets each space at the advance the browser gives it, with the face\'s space glyph', async () => {
70
+ const { font, face: f } = await embed(NEWSREADER, false);
71
+ const space = advance(f, 0x20);
72
+ const spaceId = f.glyphForCodePoint(0x20).id;
73
+ // Narrow no-break space: half a word space.
74
+ expect(paintedWidth(font, f, '10 %')).toBeCloseTo(shaped(f, '10') + space / 2 + shaped(f, '%'), 1);
75
+ expect(glyphIds(font, '10 %')).toContain(spaceId);
76
+ // Figure space: a digit.
77
+ expect(paintedWidth(font, f, '225 000')).toBeCloseTo(shaped(f, '225') + advance(f, 0x30) + shaped(f, '000'), 1);
78
+ // Thin space: a fifth of an em.
79
+ expect(paintedWidth(font, f, '1 000')).toBeCloseTo(shaped(f, '1') + 200 + shaped(f, '000'), 1);
80
+ // Word joiner and U+FEFF: nothing, and the letters on either side still
81
+ // kern as one word.
82
+ expect(paintedWidth(font, f, 'ab')).toBeCloseTo(shaped(f, 'ab'), 1);
83
+ expect(paintedWidth(font, f, 'x⁠y')).toBeCloseTo(shaped(f, 'xy'), 1);
84
+ });
85
+ it('keeps the face\'s own glyph when it has one', async () => {
86
+ // Source Serif 4 has a narrow no-break space (1/8 em) of its own.
87
+ const serif = await embed(SOURCE_SERIF, false);
88
+ expect(glyphIds(serif.font, '10 %')).toContain(serif.face.glyphForCodePoint(0x202f).id);
89
+ expect(paintedWidth(serif.font, serif.face, '10 %')).toBeCloseTo(shaped(serif.face, '10 %'), 1);
90
+ // Newsreader's no-break space is its own glyph too: nothing changes.
91
+ const news = await embed(NEWSREADER, false);
92
+ expect(glyphIds(news.font, 'a b')).toContain(news.face.glyphForCodePoint(0xa0).id);
93
+ });
94
+ it('hides U+FEFF and the word joiner even where the face gives them an advance', async () => {
95
+ // EB Garamond Bold maps both to a glyph 0.49 em wide; the browser hides
96
+ // them whatever the face holds.
97
+ const { font, face: f } = await embed(EB_GARAMOND_BOLD, false);
98
+ expect(advance(f, 0xfeff)).toBeGreaterThan(400);
99
+ expect(paintedWidth(font, f, 'ab')).toBeCloseTo(shaped(f, 'ab'), 1);
100
+ expect(paintedWidth(font, f, 'x⁠y')).toBeCloseTo(shaped(f, 'xy'), 1);
101
+ });
102
+ it('leaves text without them as it was', async () => {
103
+ const { font } = await embed(NEWSREADER, false);
104
+ const op = showTextShaped(font, 'plain words');
105
+ expect(['Tj', 'TJ']).toContain(op.name);
106
+ expect(glyphIds(font, 'plain words')).not.toContain(0);
107
+ });
108
+ });
109
+ describe('a whole document in a face without them', () => {
110
+ const fontProvider = async () => new Uint8Array(NEWSREADER);
111
+ class StubCtx {
112
+ font = '';
113
+ measureText(s) {
114
+ return { width: s.length * 7 };
115
+ }
116
+ }
117
+ globalThis.OffscreenCanvas = class {
118
+ getContext() {
119
+ return new StubCtx();
120
+ }
121
+ };
122
+ const pt = (value) => ({ value, unit: 'pt' });
123
+ const config = {
124
+ page: { width: pt(300), height: pt(300), dpi: 72, margins: { top: pt(10), bottom: pt(10), left: pt(10), right: pt(10) } },
125
+ layout: { layoutType: 'single' },
126
+ header: { elements: [] },
127
+ footer: { elements: [] },
128
+ bodyText: { fontFamily: 'Newsreader', fontSize: pt(12), lineHeight: pt(16), firstLineIndent: pt(0), hyphenation: { enabled: false } },
129
+ };
130
+ const markdown = [
131
+ 'Plain: it holds 225 000 stars and 10 per cent of them⁠, see p. 12.',
132
+ '',
133
+ 'Rich: *it* holds 225 000 stars and **10 %** of them⁠.',
134
+ ].join('\n');
135
+ for (const accessible of [false, true]) {
136
+ it(`draws no notdef glyph (${accessible ? 'tagged' : 'untagged'})`, async () => {
137
+ const doc = buildDocument({ markdown }, config);
138
+ const pdf = await PDFDocument.load(await renderToPdf(doc, { fontProvider, accessible }));
139
+ const contents = pdf.getPage(0).node.Contents();
140
+ const refs = contents instanceof PDFArray ? contents.asArray() : [contents];
141
+ const content = refs
142
+ .map((ref) => {
143
+ const s = pdf.context.lookup(ref);
144
+ return s instanceof PDFRawStream ? new TextDecoder('latin1').decode(decodePDFRawStream(s).decode()) : '';
145
+ })
146
+ .join('\n');
147
+ const hexes = [...content.matchAll(/<([0-9A-Fa-f]*)>/g)].map((m) => m[1]);
148
+ expect(hexes.length).toBeGreaterThan(5);
149
+ for (const hex of hexes) {
150
+ for (let i = 0; i < hex.length; i += 4)
151
+ expect(hex.slice(i, i + 4), hex).not.toBe('0000');
152
+ }
153
+ }, 60_000);
154
+ }
155
+ });
156
+ //# sourceMappingURL=fallbackSpaces.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallbackSpaces.test.js","sourceRoot":"","sources":["../../src/__tests__/fallbackSpaces.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=floatReadingOrder.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floatReadingOrder.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/floatReadingOrder.test.ts"],"names":[],"mappings":""}