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.
- package/README.md +3 -3
- package/dist/__tests__/accessibility.test.js +66 -0
- package/dist/__tests__/accessibility.test.js.map +1 -1
- package/dist/__tests__/alpha.test.d.ts +2 -0
- package/dist/__tests__/alpha.test.d.ts.map +1 -0
- package/dist/__tests__/alpha.test.js +164 -0
- package/dist/__tests__/alpha.test.js.map +1 -0
- package/dist/__tests__/bleedClip.test.d.ts +2 -0
- package/dist/__tests__/bleedClip.test.d.ts.map +1 -0
- package/dist/__tests__/bleedClip.test.js +83 -0
- package/dist/__tests__/bleedClip.test.js.map +1 -0
- package/dist/__tests__/boxBorderInside.test.d.ts +2 -0
- package/dist/__tests__/boxBorderInside.test.d.ts.map +1 -0
- package/dist/__tests__/boxBorderInside.test.js +63 -0
- package/dist/__tests__/boxBorderInside.test.js.map +1 -0
- package/dist/__tests__/calloutRuntTracking.test.d.ts +2 -0
- package/dist/__tests__/calloutRuntTracking.test.d.ts.map +1 -0
- package/dist/__tests__/calloutRuntTracking.test.js +72 -0
- package/dist/__tests__/calloutRuntTracking.test.js.map +1 -0
- package/dist/__tests__/calloutStripeRadius.test.d.ts +2 -0
- package/dist/__tests__/calloutStripeRadius.test.d.ts.map +1 -0
- package/dist/__tests__/calloutStripeRadius.test.js +90 -0
- package/dist/__tests__/calloutStripeRadius.test.js.map +1 -0
- package/dist/__tests__/chipVerticalPadding.test.d.ts +2 -0
- package/dist/__tests__/chipVerticalPadding.test.d.ts.map +1 -0
- package/dist/__tests__/chipVerticalPadding.test.js +71 -0
- package/dist/__tests__/chipVerticalPadding.test.js.map +1 -0
- package/dist/__tests__/chips.test.js +20 -3
- package/dist/__tests__/chips.test.js.map +1 -1
- package/dist/__tests__/documentLanguage.test.d.ts +2 -0
- package/dist/__tests__/documentLanguage.test.d.ts.map +1 -0
- package/dist/__tests__/documentLanguage.test.js +44 -0
- package/dist/__tests__/documentLanguage.test.js.map +1 -0
- package/dist/__tests__/fallbackSpaces.test.d.ts +2 -0
- package/dist/__tests__/fallbackSpaces.test.d.ts.map +1 -0
- package/dist/__tests__/fallbackSpaces.test.js +156 -0
- package/dist/__tests__/fallbackSpaces.test.js.map +1 -0
- package/dist/__tests__/floatReadingOrder.test.d.ts +2 -0
- package/dist/__tests__/floatReadingOrder.test.d.ts.map +1 -0
- package/dist/__tests__/floatReadingOrder.test.js +208 -0
- package/dist/__tests__/floatReadingOrder.test.js.map +1 -0
- package/dist/__tests__/fontEmbedding.test.d.ts +2 -0
- package/dist/__tests__/fontEmbedding.test.d.ts.map +1 -0
- package/dist/__tests__/fontEmbedding.test.js +118 -0
- package/dist/__tests__/fontEmbedding.test.js.map +1 -0
- package/dist/__tests__/fontFaces.test.d.ts +2 -0
- package/dist/__tests__/fontFaces.test.d.ts.map +1 -0
- package/dist/__tests__/fontFaces.test.js +193 -0
- package/dist/__tests__/fontFaces.test.js.map +1 -0
- package/dist/__tests__/fontStack.test.d.ts +2 -0
- package/dist/__tests__/fontStack.test.d.ts.map +1 -0
- package/dist/__tests__/fontStack.test.js +48 -0
- package/dist/__tests__/fontStack.test.js.map +1 -0
- package/dist/__tests__/headerFooter.test.js +83 -1
- package/dist/__tests__/headerFooter.test.js.map +1 -1
- package/dist/__tests__/headingAlign.test.d.ts +2 -0
- package/dist/__tests__/headingAlign.test.d.ts.map +1 -0
- package/dist/__tests__/headingAlign.test.js +66 -0
- package/dist/__tests__/headingAlign.test.js.map +1 -0
- package/dist/__tests__/hiddenHeadings.test.d.ts +2 -0
- package/dist/__tests__/hiddenHeadings.test.d.ts.map +1 -0
- package/dist/__tests__/hiddenHeadings.test.js +96 -0
- package/dist/__tests__/hiddenHeadings.test.js.map +1 -0
- package/dist/__tests__/lineTracking.test.d.ts +2 -0
- package/dist/__tests__/lineTracking.test.d.ts.map +1 -0
- package/dist/__tests__/lineTracking.test.js +80 -0
- package/dist/__tests__/lineTracking.test.js.map +1 -0
- package/dist/__tests__/measuredLines.test.d.ts +2 -0
- package/dist/__tests__/measuredLines.test.d.ts.map +1 -0
- package/dist/__tests__/measuredLines.test.js +255 -0
- package/dist/__tests__/measuredLines.test.js.map +1 -0
- package/dist/__tests__/metadata.test.d.ts +2 -0
- package/dist/__tests__/metadata.test.d.ts.map +1 -0
- package/dist/__tests__/metadata.test.js +51 -0
- package/dist/__tests__/metadata.test.js.map +1 -0
- package/dist/__tests__/outlineTitles.test.d.ts +2 -0
- package/dist/__tests__/outlineTitles.test.d.ts.map +1 -0
- package/dist/__tests__/outlineTitles.test.js +59 -0
- package/dist/__tests__/outlineTitles.test.js.map +1 -0
- package/dist/__tests__/pdfGenerationConfig.test.d.ts +2 -0
- package/dist/__tests__/pdfGenerationConfig.test.d.ts.map +1 -0
- package/dist/__tests__/pdfGenerationConfig.test.js +76 -0
- package/dist/__tests__/pdfGenerationConfig.test.js.map +1 -0
- package/dist/__tests__/pdfWorker.test.d.ts +2 -0
- package/dist/__tests__/pdfWorker.test.d.ts.map +1 -0
- package/dist/__tests__/pdfWorker.test.js +123 -0
- package/dist/__tests__/pdfWorker.test.js.map +1 -0
- package/dist/__tests__/printMarks.test.d.ts +2 -0
- package/dist/__tests__/printMarks.test.d.ts.map +1 -0
- package/dist/__tests__/printMarks.test.js +170 -0
- package/dist/__tests__/printMarks.test.js.map +1 -0
- package/dist/__tests__/printMaster.test.d.ts +2 -0
- package/dist/__tests__/printMaster.test.d.ts.map +1 -0
- package/dist/__tests__/printMaster.test.js +161 -0
- package/dist/__tests__/printMaster.test.js.map +1 -0
- package/dist/__tests__/renderWarnings.test.d.ts +2 -0
- package/dist/__tests__/renderWarnings.test.d.ts.map +1 -0
- package/dist/__tests__/renderWarnings.test.js +89 -0
- package/dist/__tests__/renderWarnings.test.js.map +1 -0
- package/dist/__tests__/repeatedHyphen.test.d.ts +2 -0
- package/dist/__tests__/repeatedHyphen.test.d.ts.map +1 -0
- package/dist/__tests__/repeatedHyphen.test.js +125 -0
- package/dist/__tests__/repeatedHyphen.test.js.map +1 -0
- package/dist/__tests__/scriptStacking.test.d.ts +2 -0
- package/dist/__tests__/scriptStacking.test.d.ts.map +1 -0
- package/dist/__tests__/scriptStacking.test.js +66 -0
- package/dist/__tests__/scriptStacking.test.js.map +1 -0
- package/dist/__tests__/sectionColumnRule.test.d.ts +2 -0
- package/dist/__tests__/sectionColumnRule.test.d.ts.map +1 -0
- package/dist/__tests__/sectionColumnRule.test.js +144 -0
- package/dist/__tests__/sectionColumnRule.test.js.map +1 -0
- package/dist/__tests__/svgFormReuse.test.d.ts +2 -0
- package/dist/__tests__/svgFormReuse.test.d.ts.map +1 -0
- package/dist/__tests__/svgFormReuse.test.js +102 -0
- package/dist/__tests__/svgFormReuse.test.js.map +1 -0
- package/dist/__tests__/svgVector.test.js +85 -11
- package/dist/__tests__/svgVector.test.js.map +1 -1
- package/dist/__tests__/tableFillSeams.test.d.ts +2 -0
- package/dist/__tests__/tableFillSeams.test.d.ts.map +1 -0
- package/dist/__tests__/tableFillSeams.test.js +72 -0
- package/dist/__tests__/tableFillSeams.test.js.map +1 -0
- package/dist/__tests__/tocLeaderKerning.test.d.ts +2 -0
- package/dist/__tests__/tocLeaderKerning.test.d.ts.map +1 -0
- package/dist/__tests__/tocLeaderKerning.test.js +84 -0
- package/dist/__tests__/tocLeaderKerning.test.js.map +1 -0
- package/dist/__tests__/tocNumberBaseline.test.d.ts +2 -0
- package/dist/__tests__/tocNumberBaseline.test.d.ts.map +1 -0
- package/dist/__tests__/tocNumberBaseline.test.js +72 -0
- package/dist/__tests__/tocNumberBaseline.test.js.map +1 -0
- package/dist/__tests__/tocTagging.test.d.ts +2 -0
- package/dist/__tests__/tocTagging.test.d.ts.map +1 -0
- package/dist/__tests__/tocTagging.test.js +120 -0
- package/dist/__tests__/tocTagging.test.js.map +1 -0
- package/dist/__tests__/trackedLineAlign.test.d.ts +2 -0
- package/dist/__tests__/trackedLineAlign.test.d.ts.map +1 -0
- package/dist/__tests__/trackedLineAlign.test.js +73 -0
- package/dist/__tests__/trackedLineAlign.test.js.map +1 -0
- package/dist/__tests__/uriLinks.test.d.ts +2 -0
- package/dist/__tests__/uriLinks.test.d.ts.map +1 -0
- package/dist/__tests__/uriLinks.test.js +103 -0
- package/dist/__tests__/uriLinks.test.js.map +1 -0
- package/dist/colors.d.ts +18 -3
- package/dist/colors.d.ts.map +1 -1
- package/dist/colors.js +77 -25
- package/dist/colors.js.map +1 -1
- package/dist/fontCache.d.ts +67 -4
- package/dist/fontCache.d.ts.map +1 -1
- package/dist/fontCache.js +200 -23
- package/dist/fontCache.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/pdf-backend/blockRender.d.ts.map +1 -1
- package/dist/pdf-backend/blockRender.js +127 -28
- package/dist/pdf-backend/blockRender.js.map +1 -1
- package/dist/pdf-backend/fallbackSpaces.d.ts +37 -0
- package/dist/pdf-backend/fallbackSpaces.d.ts.map +1 -0
- package/dist/pdf-backend/fallbackSpaces.js +119 -0
- package/dist/pdf-backend/fallbackSpaces.js.map +1 -0
- package/dist/pdf-backend/fontHelpers.d.ts +10 -1
- package/dist/pdf-backend/fontHelpers.d.ts.map +1 -1
- package/dist/pdf-backend/fontHelpers.js +111 -65
- package/dist/pdf-backend/fontHelpers.js.map +1 -1
- package/dist/pdf-backend/headerFooter.d.ts +4 -2
- package/dist/pdf-backend/headerFooter.d.ts.map +1 -1
- package/dist/pdf-backend/headerFooter.js +105 -48
- package/dist/pdf-backend/headerFooter.js.map +1 -1
- package/dist/pdf-backend/index.d.ts +55 -6
- package/dist/pdf-backend/index.d.ts.map +1 -1
- package/dist/pdf-backend/index.js +135 -35
- package/dist/pdf-backend/index.js.map +1 -1
- package/dist/pdf-backend/links.d.ts +82 -1
- package/dist/pdf-backend/links.d.ts.map +1 -1
- package/dist/pdf-backend/links.js +141 -3
- package/dist/pdf-backend/links.js.map +1 -1
- package/dist/pdf-backend/outlines.d.ts.map +1 -1
- package/dist/pdf-backend/outlines.js +7 -0
- package/dist/pdf-backend/outlines.js.map +1 -1
- package/dist/pdf-backend/pageDecorations.d.ts.map +1 -1
- package/dist/pdf-backend/pageDecorations.js +42 -26
- package/dist/pdf-backend/pageDecorations.js.map +1 -1
- package/dist/pdf-backend/primitives.d.ts +61 -1
- package/dist/pdf-backend/primitives.d.ts.map +1 -1
- package/dist/pdf-backend/primitives.js +318 -18
- package/dist/pdf-backend/primitives.js.map +1 -1
- package/dist/pdf-backend/renderResourceBlock.d.ts +3 -1
- package/dist/pdf-backend/renderResourceBlock.d.ts.map +1 -1
- package/dist/pdf-backend/renderResourceBlock.js +97 -19
- package/dist/pdf-backend/renderResourceBlock.js.map +1 -1
- package/dist/pdf-backend/structureFlow.d.ts +70 -3
- package/dist/pdf-backend/structureFlow.d.ts.map +1 -1
- package/dist/pdf-backend/structureFlow.js +209 -27
- package/dist/pdf-backend/structureFlow.js.map +1 -1
- package/dist/pdf-backend/svgVector.d.ts +7 -2
- package/dist/pdf-backend/svgVector.d.ts.map +1 -1
- package/dist/pdf-backend/svgVector.js +157 -72
- package/dist/pdf-backend/svgVector.js.map +1 -1
- package/dist/pdf-backend/tagging.d.ts +1 -1
- package/dist/pdf-backend/tagging.d.ts.map +1 -1
- package/dist/pdf-backend/tagging.js.map +1 -1
- package/dist/worker/client.d.ts +1 -1
- package/dist/worker/client.d.ts.map +1 -1
- package/dist/worker/client.js +8 -0
- package/dist/worker/client.js.map +1 -1
- package/dist/worker/pdf.worker.js +1 -0
- package/dist/worker/pdf.worker.js.map +1 -1
- package/dist/worker/protocol.d.ts +8 -1
- package/dist/worker/protocol.d.ts.map +1 -1
- 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 @@
|
|
|
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 @@
|
|
|
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 =
|
|
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 =
|
|
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":"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"}
|
|
@@ -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 @@
|
|
|
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', 'xy', ' ', '', '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, 'xy')).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, 'xy')).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 @@
|
|
|
1
|
+
{"version":3,"file":"floatReadingOrder.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/floatReadingOrder.test.ts"],"names":[],"mappings":""}
|