@jasy/pdf 1.0.0-beta.3 → 1.0.0-beta.5
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/dist/api/color.d.ts +1 -24
- package/dist/api/color.js +2 -278
- package/dist/api/content.d.ts +10 -5
- package/dist/api/content.js +29 -13
- package/dist/api/descriptor.js +30 -3
- package/dist/api/flow.d.ts +55 -0
- package/dist/api/flow.js +71 -0
- package/dist/api/font-url.d.ts +1 -2
- package/dist/api/font-url.js +8 -74
- package/dist/api/forms.d.ts +3 -0
- package/dist/api/forms.js +3 -0
- package/dist/api/gradient.d.ts +1 -53
- package/dist/api/gradient.js +2 -97
- package/dist/api/index.d.ts +4 -0
- package/dist/api/index.js +3 -0
- package/dist/api/layout.d.ts +6 -0
- package/dist/api/layout.js +9 -3
- package/dist/api/page-builder.d.ts +4 -0
- package/dist/api/page-builder.js +4 -0
- package/dist/api/structure.d.ts +10 -2
- package/dist/api/structure.js +9 -6
- package/dist/api/table.d.ts +5 -3
- package/dist/api/table.js +101 -22
- package/dist/api/text.d.ts +8 -8
- package/dist/api/text.js +6 -0
- package/dist/canvas/painter.d.ts +2 -2
- package/dist/canvas/painter.js +2 -2
- package/dist/common/color-input.d.ts +24 -0
- package/dist/common/color-input.js +278 -0
- package/dist/common/diagnostics.d.ts +61 -0
- package/dist/common/diagnostics.js +77 -0
- package/dist/common/gradient.d.ts +53 -0
- package/dist/common/gradient.js +97 -0
- package/dist/edit/acroform-reader.js +7 -7
- package/dist/edit/appearance.js +3 -3
- package/dist/edit/attachments.d.ts +52 -0
- package/dist/edit/attachments.js +178 -0
- package/dist/edit/document.d.ts +38 -8
- package/dist/edit/document.js +208 -51
- package/dist/edit/fill.js +8 -23
- package/dist/edit/filters.d.ts +15 -0
- package/dist/edit/filters.js +157 -0
- package/dist/edit/index.d.ts +4 -1
- package/dist/edit/index.js +3 -1
- package/dist/edit/objects.d.ts +3 -4
- package/dist/edit/objects.js +5 -18
- package/dist/elements/canvas-element.d.ts +3 -0
- package/dist/elements/canvas-element.js +14 -3
- package/dist/elements/container-element.d.ts +8 -1
- package/dist/elements/container-element.js +49 -17
- package/dist/elements/forms/checkbox-element.d.ts +2 -0
- package/dist/elements/forms/checkbox-element.js +12 -3
- package/dist/elements/forms/choice-element.d.ts +6 -1
- package/dist/elements/forms/choice-element.js +17 -6
- package/dist/elements/forms/field-font.d.ts +8 -0
- package/dist/elements/forms/field-font.js +5 -0
- package/dist/elements/forms/push-button-element.d.ts +6 -1
- package/dist/elements/forms/push-button-element.js +16 -4
- package/dist/elements/forms/radio-element.d.ts +2 -0
- package/dist/elements/forms/radio-element.js +12 -3
- package/dist/elements/forms/signature-element.d.ts +6 -1
- package/dist/elements/forms/signature-element.js +16 -4
- package/dist/elements/forms/text-field-element.d.ts +6 -1
- package/dist/elements/forms/text-field-element.js +16 -4
- package/dist/elements/image-element.d.ts +70 -21
- package/dist/elements/image-element.js +173 -52
- package/dist/elements/index.d.ts +3 -0
- package/dist/elements/index.js +3 -0
- package/dist/elements/layout/anchor-element.d.ts +8 -10
- package/dist/elements/layout/anchor-element.js +10 -18
- package/dist/elements/layout/bookmark-element.d.ts +9 -11
- package/dist/elements/layout/bookmark-element.js +11 -20
- package/dist/elements/layout/column-break-element.d.ts +17 -0
- package/dist/elements/layout/column-break-element.js +26 -0
- package/dist/elements/layout/default-text-style-element.d.ts +11 -13
- package/dist/elements/layout/default-text-style-element.js +14 -31
- package/dist/elements/layout/deferred-element.d.ts +20 -4
- package/dist/elements/layout/deferred-element.js +41 -9
- package/dist/elements/layout/expanded-element.d.ts +11 -0
- package/dist/elements/layout/expanded-element.js +53 -18
- package/dist/elements/layout/flow-element.d.ts +109 -0
- package/dist/elements/layout/flow-element.js +317 -0
- package/dist/elements/layout/keep-together-element.d.ts +8 -18
- package/dist/elements/layout/keep-together-element.js +33 -45
- package/dist/elements/layout/link-element.d.ts +8 -13
- package/dist/elements/layout/link-element.js +9 -19
- package/dist/elements/layout/padding-element.d.ts +18 -1
- package/dist/elements/layout/padding-element.js +63 -28
- package/dist/elements/layout/page-break-element.d.ts +4 -1
- package/dist/elements/layout/page-break-element.js +6 -1
- package/dist/elements/layout/page-builder-element.d.ts +5 -0
- package/dist/elements/layout/page-builder-element.js +13 -2
- package/dist/elements/layout/positioned-element.d.ts +23 -4
- package/dist/elements/layout/positioned-element.js +42 -12
- package/dist/elements/layout/proxy-element.d.ts +47 -0
- package/dist/elements/layout/proxy-element.js +106 -0
- package/dist/elements/layout/region-element.d.ts +53 -0
- package/dist/elements/layout/region-element.js +108 -0
- package/dist/elements/layout/repeating-header-element.d.ts +9 -0
- package/dist/elements/layout/repeating-header-element.js +55 -13
- package/dist/elements/layout/rotated-box-element.d.ts +6 -0
- package/dist/elements/layout/rotated-box-element.js +27 -14
- package/dist/elements/layout/rotated-element.d.ts +9 -0
- package/dist/elements/layout/rotated-element.js +33 -2
- package/dist/elements/layout/struct-group.d.ts +9 -17
- package/dist/elements/layout/struct-group.js +10 -35
- package/dist/elements/line-element.d.ts +1 -0
- package/dist/elements/line-element.js +6 -0
- package/dist/elements/page-element.d.ts +10 -3
- package/dist/elements/page-element.js +39 -31
- package/dist/elements/pdf-document-element.d.ts +3 -0
- package/dist/elements/pdf-document-element.js +7 -0
- package/dist/elements/pdf-element.d.ts +105 -16
- package/dist/elements/pdf-element.js +118 -19
- package/dist/elements/rectangle-element.d.ts +22 -2
- package/dist/elements/rectangle-element.js +119 -55
- package/dist/elements/row-element.d.ts +17 -12
- package/dist/elements/row-element.js +89 -9
- package/dist/elements/svg-element.d.ts +30 -6
- package/dist/elements/svg-element.js +91 -26
- package/dist/elements/text-element.d.ts +48 -13
- package/dist/elements/text-element.js +161 -116
- package/dist/forms/acroform.d.ts +9 -1
- package/dist/forms/acroform.js +83 -34
- package/dist/forms/appearance.d.ts +17 -6
- package/dist/forms/appearance.js +18 -16
- package/dist/ir/display-list.d.ts +18 -3
- package/dist/layout/box-constraints.d.ts +17 -0
- package/dist/layout/box-constraints.js +31 -0
- package/dist/layout/collect-images.d.ts +6 -4
- package/dist/layout/collect-images.js +14 -8
- package/dist/layout/flex-item.d.ts +11 -0
- package/dist/layout/flex-item.js +51 -0
- package/dist/layout/fragmentation.d.ts +23 -9
- package/dist/layout/fragmentation.js +62 -19
- package/dist/layout/layout-cache.d.ts +53 -0
- package/dist/layout/layout-cache.js +110 -0
- package/dist/platform/browser-fs.d.ts +1 -2
- package/dist/platform/browser-fs.js +3 -6
- package/dist/platform/node-fs.d.ts +0 -1
- package/dist/platform/node-fs.js +0 -4
- package/dist/renderer/anchor-renderer.d.ts +2 -1
- package/dist/renderer/anchor-renderer.js +5 -4
- package/dist/renderer/bookmark-renderer.d.ts +2 -1
- package/dist/renderer/bookmark-renderer.js +5 -4
- package/dist/renderer/canvas-renderer.d.ts +2 -1
- package/dist/renderer/canvas-renderer.js +5 -2
- package/dist/renderer/column-break-renderer.d.ts +8 -0
- package/dist/renderer/column-break-renderer.js +15 -0
- package/dist/renderer/container-renderer.d.ts +2 -1
- package/dist/renderer/container-renderer.js +6 -5
- package/dist/renderer/default-text-style-renderer.d.ts +2 -1
- package/dist/renderer/default-text-style-renderer.js +2 -3
- package/dist/renderer/deferred-renderer.d.ts +2 -1
- package/dist/renderer/deferred-renderer.js +2 -3
- package/dist/renderer/emoji-image.js +3 -1
- package/dist/renderer/expanded-renderer.d.ts +2 -1
- package/dist/renderer/expanded-renderer.js +2 -3
- package/dist/renderer/flow-renderer.d.ts +16 -0
- package/dist/renderer/flow-renderer.js +21 -0
- package/dist/renderer/form-field-renderer.d.ts +2 -1
- package/dist/renderer/form-field-renderer.js +16 -3
- package/dist/renderer/image-renderer.d.ts +2 -1
- package/dist/renderer/image-renderer.js +33 -53
- package/dist/renderer/index.d.ts +2 -0
- package/dist/renderer/index.js +2 -0
- package/dist/renderer/keep-together-renderer.d.ts +2 -1
- package/dist/renderer/keep-together-renderer.js +2 -3
- package/dist/renderer/line-renderer.d.ts +2 -1
- package/dist/renderer/line-renderer.js +7 -2
- package/dist/renderer/link-renderer.d.ts +2 -1
- package/dist/renderer/link-renderer.js +36 -5
- package/dist/renderer/padding-renderer.d.ts +2 -1
- package/dist/renderer/padding-renderer.js +5 -5
- package/dist/renderer/page-break-renderer.d.ts +6 -5
- package/dist/renderer/page-break-renderer.js +14 -7
- package/dist/renderer/page-builder-renderer.d.ts +2 -1
- package/dist/renderer/page-builder-renderer.js +2 -3
- package/dist/renderer/page-renderer.js +30 -10
- package/dist/renderer/pdf-backend.d.ts +4 -3
- package/dist/renderer/pdf-backend.js +14 -7
- package/dist/renderer/pdf-document-renderer.d.ts +1 -8
- package/dist/renderer/pdf-document-renderer.js +17 -17
- package/dist/renderer/pdf-renderer.js +20 -11
- package/dist/renderer/positioned-renderer.d.ts +18 -1
- package/dist/renderer/positioned-renderer.js +43 -6
- package/dist/renderer/rectangle-renderer.d.ts +2 -1
- package/dist/renderer/rectangle-renderer.js +18 -8
- package/dist/renderer/repeating-header-renderer.d.ts +2 -1
- package/dist/renderer/repeating-header-renderer.js +6 -5
- package/dist/renderer/rotated-renderer.d.ts +2 -1
- package/dist/renderer/rotated-renderer.js +9 -5
- package/dist/renderer/row-renderer.d.ts +2 -1
- package/dist/renderer/row-renderer.js +6 -5
- package/dist/renderer/struct-group-renderer.d.ts +2 -1
- package/dist/renderer/struct-group-renderer.js +2 -3
- package/dist/renderer/svg-renderer.d.ts +2 -1
- package/dist/renderer/svg-renderer.js +8 -2
- package/dist/renderer/text-renderer.d.ts +4 -6
- package/dist/renderer/text-renderer.js +114 -127
- package/dist/svg/gradients.js +5 -0
- package/dist/svg/index.d.ts +1 -1
- package/dist/svg/index.js +36 -6
- package/dist/svg/style.d.ts +2 -0
- package/dist/svg/style.js +12 -1
- package/dist/text/advance.d.ts +4 -0
- package/dist/text/advance.js +17 -4
- package/dist/text/bidi.d.ts +0 -2
- package/dist/text/bidi.js +0 -10
- package/dist/text/glyph-coverage.d.ts +1 -1
- package/dist/text/glyph-coverage.js +7 -3
- package/dist/text/hyphen-breaks.d.ts +17 -0
- package/dist/text/hyphen-breaks.js +54 -0
- package/dist/text/line-breaker.d.ts +55 -29
- package/dist/text/line-breaker.js +453 -188
- package/dist/text/line-metrics.d.ts +8 -3
- package/dist/text/line-metrics.js +11 -2
- package/dist/text/pdf-text-string.d.ts +21 -0
- package/dist/text/pdf-text-string.js +114 -0
- package/dist/text/text-decoration.d.ts +5 -5
- package/dist/text/text-decoration.js +5 -5
- package/dist/text/word-splitting.d.ts +15 -2
- package/dist/text/word-splitting.js +45 -13
- package/dist/utils/afm-parser.d.ts +2 -0
- package/dist/utils/afm-parser.js +10 -1
- package/dist/utils/dest-registry.d.ts +1 -1
- package/dist/utils/dest-registry.js +3 -2
- package/dist/utils/fetch-bytes.d.ts +19 -0
- package/dist/utils/fetch-bytes.js +79 -0
- package/dist/utils/flex-layout.d.ts +16 -14
- package/dist/utils/flex-layout.js +427 -217
- package/dist/utils/font-metrics.d.ts +4 -3
- package/dist/utils/image-helper.d.ts +59 -11
- package/dist/utils/image-helper.js +209 -81
- package/dist/utils/pdf-object-manager.d.ts +17 -6
- package/dist/utils/pdf-object-manager.js +70 -20
- package/dist/utils/renderer-registry.d.ts +49 -2
- package/dist/utils/renderer-registry.js +40 -0
- package/dist/utils/struct-tree.d.ts +24 -0
- package/dist/utils/struct-tree.js +61 -9
- package/dist/utils/ttf-parser.d.ts +4 -0
- package/dist/utils/ttf-parser.js +30 -6
- package/dist/validators/element-validator.js +2 -1
- package/package.json +1 -1
- package/dist/elements/layout/sized-container-element.d.ts +0 -14
- package/dist/elements/layout/sized-container-element.js +0 -32
|
@@ -9,13 +9,15 @@ import { LayoutContext, PDFElement } from "../elements/pdf-element.js";
|
|
|
9
9
|
* rest, so no information flows back UP after a break. This one-way flow is what keeps
|
|
10
10
|
* fragmentation terminating (no overflow-cascade fixpoint).
|
|
11
11
|
*/
|
|
12
|
+
export type ForcedBreak = boolean | "column";
|
|
12
13
|
export interface FragmentResult {
|
|
13
14
|
fitted: PDFElement | null;
|
|
14
15
|
remainder: PDFElement | null;
|
|
15
|
-
/** The split ended at a FORCED
|
|
16
|
-
* remainder
|
|
17
|
-
*
|
|
18
|
-
|
|
16
|
+
/** The split ended at a FORCED break, not because the region filled up: `true` for a page break (the
|
|
17
|
+
* remainder starts a fresh page), `"column"` for a `ColumnBreak` in a Flow's Region (it starts the
|
|
18
|
+
* next Region; the Flow consumes it). An enclosing flow stops packing too - so this bubbles up
|
|
19
|
+
* through nested `fragment()` calls. Absent/false for an ordinary height-driven break. */
|
|
20
|
+
forceBreak?: ForcedBreak;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* An element that knows how to split itself across regions. Width is already finalized
|
|
@@ -33,13 +35,25 @@ export declare function isFragmentable(element: PDFElement): element is PDFEleme
|
|
|
33
35
|
* logs and clips, `"ignore"` clips silently.
|
|
34
36
|
*/
|
|
35
37
|
export type OverflowPolicy = "error" | "warn" | "ignore";
|
|
36
|
-
export declare function reportOverflow(child: PDFElement, childHeight: number, maxHeight: number, policy: OverflowPolicy): void;
|
|
37
38
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
39
|
+
* The context for content inset by `chrome` on every page (a border, padding, a repeated header): a
|
|
40
|
+
* fresh page gives it that much less room. Every element that shrinks the region for its children
|
|
41
|
+
* hands this down with it.
|
|
42
|
+
*/
|
|
43
|
+
export declare function insetContext(ctx: LayoutContext, chrome: number): LayoutContext;
|
|
44
|
+
export declare function reportOverflow(child: PDFElement, childHeight: number, maxHeight: number, ctx: LayoutContext): void;
|
|
45
|
+
/** Content cut off at the bottom, under the author's `onOverflow` policy. */
|
|
46
|
+
export declare function reportClipped(about: PDFElement, detail: string, ctx: LayoutContext): void;
|
|
47
|
+
/**
|
|
48
|
+
* True if packing `children` will hit a forced cut INSIDE them: a child that IS a break, contains one
|
|
49
|
+
* deeper in its subtree, or asks to break before/after itself. A flow container reports this from
|
|
50
|
+
* `hasForcedBreak` so its parent fragments it (runs `packChildren`) instead of placing it whole and
|
|
51
|
+
* swallowing the cut. A break before the FIRST child is not inside: the stack takes it as its own
|
|
52
|
+
* (`breaksBefore`), so it moves whole - which is what a `keepTogether` around it relies on.
|
|
41
53
|
*/
|
|
42
54
|
export declare function childrenForceBreak(children: PDFElement[]): boolean;
|
|
55
|
+
/** The packer kept every child as it was - none came back as a piece of itself (a sized Flow). */
|
|
56
|
+
export declare function packedUnchanged(children: PDFElement[], fitted: PDFElement[]): boolean;
|
|
43
57
|
/**
|
|
44
58
|
* Packs a vertical stack of children into `maxHeight`, in order. Children are measured
|
|
45
59
|
* against `width` (unbounded height) and added until one would overflow; that straddling
|
|
@@ -57,5 +71,5 @@ export declare function childrenForceBreak(children: PDFElement[]): boolean;
|
|
|
57
71
|
export declare function packChildren(children: PDFElement[], maxHeight: number, width: number, ctx: LayoutContext, gap?: number): {
|
|
58
72
|
fitted: PDFElement[];
|
|
59
73
|
remainder: PDFElement[];
|
|
60
|
-
forceBreak:
|
|
74
|
+
forceBreak: ForcedBreak;
|
|
61
75
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BoxConstraints } from "./box-constraints.js";
|
|
2
|
+
import { diagnose, pageOf } from "../common/diagnostics.js";
|
|
2
3
|
export function isFragmentable(element) {
|
|
3
4
|
if (!("fragment" in element) ||
|
|
4
5
|
typeof element.fragment !== "function") {
|
|
@@ -10,24 +11,50 @@ export function isFragmentable(element) {
|
|
|
10
11
|
const canFragment = element.canFragment;
|
|
11
12
|
return typeof canFragment !== "function" || canFragment.call(element);
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The context for content inset by `chrome` on every page (a border, padding, a repeated header): a
|
|
16
|
+
* fresh page gives it that much less room. Every element that shrinks the region for its children
|
|
17
|
+
* hands this down with it.
|
|
18
|
+
*/
|
|
19
|
+
export function insetContext(ctx, chrome) {
|
|
20
|
+
if (ctx.pageBodyHeight === undefined || chrome === 0)
|
|
21
|
+
return ctx;
|
|
22
|
+
return { ...ctx, pageBodyHeight: ctx.pageBodyHeight - chrome };
|
|
23
|
+
}
|
|
24
|
+
export function reportOverflow(child, childHeight, maxHeight, ctx) {
|
|
16
25
|
const name = child.constructor.name.replace(/Element$/, "");
|
|
17
|
-
|
|
26
|
+
reportClipped(child, `${name} is ${Math.round(childHeight)}pt tall but the page region is only ` +
|
|
18
27
|
`${Math.round(maxHeight)}pt and it cannot be broken - reduce its size, give it a bounded ` +
|
|
19
|
-
`height, or let it split across pages
|
|
28
|
+
`height, or let it split across pages.`, ctx);
|
|
29
|
+
}
|
|
30
|
+
/** Content cut off at the bottom, under the author's `onOverflow` policy. */
|
|
31
|
+
export function reportClipped(about, detail, ctx) {
|
|
32
|
+
const policy = ctx.onOverflow ?? "ignore";
|
|
20
33
|
if (policy === "error")
|
|
21
34
|
throw new Error(`Layout overflow: ${detail}`);
|
|
22
|
-
|
|
35
|
+
diagnose(ctx.diagnostics, {
|
|
36
|
+
code: "overflow-clipped",
|
|
37
|
+
severity: "warning",
|
|
38
|
+
message: `Layout overflow (clipped): ${detail}`,
|
|
39
|
+
about,
|
|
40
|
+
page: pageOf(ctx),
|
|
41
|
+
// `ignore` means "no console" - an `onDiagnostic` handler still hears of it.
|
|
42
|
+
fallback: policy === "ignore" ? "silent" : "warn",
|
|
43
|
+
});
|
|
23
44
|
}
|
|
24
45
|
/**
|
|
25
|
-
* True if packing `children` will hit a forced cut: a child that IS a break, contains one
|
|
26
|
-
* subtree, or asks to break before/after itself. A flow container reports this from
|
|
27
|
-
* its parent fragments it (runs `packChildren`) instead of placing it whole and
|
|
46
|
+
* True if packing `children` will hit a forced cut INSIDE them: a child that IS a break, contains one
|
|
47
|
+
* deeper in its subtree, or asks to break before/after itself. A flow container reports this from
|
|
48
|
+
* `hasForcedBreak` so its parent fragments it (runs `packChildren`) instead of placing it whole and
|
|
49
|
+
* swallowing the cut. A break before the FIRST child is not inside: the stack takes it as its own
|
|
50
|
+
* (`breaksBefore`), so it moves whole - which is what a `keepTogether` around it relies on.
|
|
28
51
|
*/
|
|
29
52
|
export function childrenForceBreak(children) {
|
|
30
|
-
return children.some((child) => child.hasForcedBreak() || child.breaksBefore() || child.breaksAfter());
|
|
53
|
+
return children.some((child, i) => child.hasForcedBreak() || (i > 0 && child.breaksBefore()) || child.breaksAfter());
|
|
54
|
+
}
|
|
55
|
+
/** The packer kept every child as it was - none came back as a piece of itself (a sized Flow). */
|
|
56
|
+
export function packedUnchanged(children, fitted) {
|
|
57
|
+
return fitted.length === children.length && fitted.every((child, i) => child === children[i]);
|
|
31
58
|
}
|
|
32
59
|
/**
|
|
33
60
|
* Packs a vertical stack of children into `maxHeight`, in order. Children are measured
|
|
@@ -60,17 +87,26 @@ export function packChildren(children, maxHeight, width, ctx, gap = 0) {
|
|
|
60
87
|
// page, regardless of how much room is left.
|
|
61
88
|
if (child.isPageBreak())
|
|
62
89
|
return spill(i + 1, true);
|
|
90
|
+
// A column break cuts a Flow's Region; anywhere else it stays in place, draws nothing, and warns.
|
|
91
|
+
if (child.isColumnBreak()) {
|
|
92
|
+
if (ctx.inFlowRegion)
|
|
93
|
+
return spill(i + 1, "column");
|
|
94
|
+
fitted.push(child);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
63
97
|
// break-before: this child wants a fresh page. Honour it only if something is already on this region
|
|
64
98
|
// (CSS ignores break-before at the top of a page); that guard also prevents an empty page + a loop.
|
|
65
99
|
if (child.breaksBefore() && fitted.length > 0)
|
|
66
100
|
return spill(i, true);
|
|
67
|
-
const childHeight = child.
|
|
101
|
+
const childHeight = child.measure(BoxConstraints.loose(width, Infinity), ctx).height;
|
|
68
102
|
// A gap precedes every child except the first one placed in this region.
|
|
69
103
|
const lead = fitted.length > 0 ? gap : 0;
|
|
70
104
|
// Place whole only if it fits AND holds no forced break: a child that fits by height but contains
|
|
71
105
|
// a `PageBreak` (or a break-before/after) in its subtree must still be fragmented, or the break
|
|
72
|
-
// would be swallowed.
|
|
73
|
-
if (usedHeight + lead + childHeight <= maxHeight &&
|
|
106
|
+
// would be swallowed. A region-sized child (a Flow) has no height of its own to fit by.
|
|
107
|
+
if (usedHeight + lead + childHeight <= maxHeight &&
|
|
108
|
+
!child.hasForcedBreak() &&
|
|
109
|
+
!child.needsRegion()) {
|
|
74
110
|
fitted.push(child);
|
|
75
111
|
usedHeight += lead + childHeight;
|
|
76
112
|
// break-after: everything after this child starts a fresh page.
|
|
@@ -82,8 +118,10 @@ export function packChildren(children, maxHeight, width, ctx, gap = 0) {
|
|
|
82
118
|
const remaining = maxHeight - usedHeight - lead;
|
|
83
119
|
let placedPart = false;
|
|
84
120
|
let childBroke = false;
|
|
121
|
+
const below = ctx.belowContent || fitted.length > 0;
|
|
85
122
|
if (isFragmentable(child)) {
|
|
86
|
-
const
|
|
123
|
+
const childCtx = below && !ctx.belowContent ? { ...ctx, belowContent: true } : ctx;
|
|
124
|
+
const split = child.fragment(Math.max(0, remaining), width, childCtx);
|
|
87
125
|
childBroke = split.forceBreak ?? false;
|
|
88
126
|
if (split.fitted) {
|
|
89
127
|
fitted.push(split.fitted);
|
|
@@ -92,7 +130,11 @@ export function packChildren(children, maxHeight, width, ctx, gap = 0) {
|
|
|
92
130
|
// break-before at the top of the region, which CSS ignores. Keep packing the siblings after
|
|
93
131
|
// it instead of spilling them, so break-before does not accidentally push later content away.
|
|
94
132
|
if (!split.remainder && !childBroke) {
|
|
95
|
-
|
|
133
|
+
// A region-sized child comes back as a different, sized piece: count what it holds.
|
|
134
|
+
const placed = split.fitted === child
|
|
135
|
+
? childHeight
|
|
136
|
+
: split.fitted.measure(BoxConstraints.loose(width, Infinity), ctx).height;
|
|
137
|
+
usedHeight += lead + placed;
|
|
96
138
|
continue;
|
|
97
139
|
}
|
|
98
140
|
if (split.remainder)
|
|
@@ -101,10 +143,11 @@ export function packChildren(children, maxHeight, width, ctx, gap = 0) {
|
|
|
101
143
|
}
|
|
102
144
|
}
|
|
103
145
|
if (!placedPart) {
|
|
104
|
-
if (
|
|
105
|
-
// Taller than
|
|
106
|
-
// so the next region still advances - and surface it per the overflow policy.
|
|
107
|
-
|
|
146
|
+
if (!below && !childBroke) {
|
|
147
|
+
// Taller than a whole fresh page and unsplittable: force it on (it overflows and is clipped)
|
|
148
|
+
// so the next region still advances - and surface it per the overflow policy. Below other
|
|
149
|
+
// content it simply waits for the next page.
|
|
150
|
+
reportOverflow(child, childHeight, maxHeight, ctx);
|
|
108
151
|
fitted.push(child);
|
|
109
152
|
}
|
|
110
153
|
else {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { BoxConstraints, Size } from "./box-constraints.js";
|
|
2
|
+
import type { LayoutContext } from "../elements/pdf-element.js";
|
|
3
|
+
/**
|
|
4
|
+
* The layout cache - the one place a size is remembered. `PDFElement.measure` asks it before
|
|
5
|
+
* `computeSize` runs, and stores what `computeSize` returned.
|
|
6
|
+
*
|
|
7
|
+
* An element never changes after it is built, so its size is a pure function of its INPUTS: the
|
|
8
|
+
* constraints, plus the context fields listed in `Key` below. The same inputs again are answered from
|
|
9
|
+
* the element's own cache. That is what Flutter's dry-layout cache and Yoga's measure cache do; flex
|
|
10
|
+
* asks the same child the same question several times while it distributes space.
|
|
11
|
+
*
|
|
12
|
+
* What keeps it correct:
|
|
13
|
+
* - `computeSize` reads only the context fields in `Key`. A new field that can change a size is added
|
|
14
|
+
* HERE. `frame`, `belowContent`, `pageBodyHeight` and `onOverflow` steer placement and page breaks,
|
|
15
|
+
* never a size, so they are not part of it.
|
|
16
|
+
* - The page (`pageConfig`, `pageInfo`) is part of the key only for an element that
|
|
17
|
+
* `dependsOnPage()`. Every page and both passes bring new page objects, so keying everything on them
|
|
18
|
+
* would make the cache miss on each page.
|
|
19
|
+
* - Context values compare by IDENTITY. Code that derives one (a merged text style) returns the same
|
|
20
|
+
* object for the same input, or every element below it misses.
|
|
21
|
+
* - `fontEpoch` moves when a font face is added, and kerning can be switched on the same metrics; both
|
|
22
|
+
* change widths.
|
|
23
|
+
*
|
|
24
|
+
* The same key, without the constraints, decides when a subtree built at layout time can be reused
|
|
25
|
+
* (`BuiltFromContext`, below).
|
|
26
|
+
*
|
|
27
|
+
* Below this level sit value memos that are not size caches: glyph advances per font
|
|
28
|
+
* (`text/advance.ts`) and a Text's displayed content (`TextElement.display`).
|
|
29
|
+
*/
|
|
30
|
+
export declare const layoutCache: {
|
|
31
|
+
/** Off only in the test that renders every pinned document both ways and demands the same bytes. */
|
|
32
|
+
enabled: boolean;
|
|
33
|
+
};
|
|
34
|
+
/** One element's remembered sizes, oldest overwritten first. */
|
|
35
|
+
export declare class SizeCache {
|
|
36
|
+
private entries;
|
|
37
|
+
private next;
|
|
38
|
+
get(constraints: BoxConstraints, ctx: LayoutContext, onPage: boolean): Size | undefined;
|
|
39
|
+
set(constraints: BoxConstraints, ctx: LayoutContext, onPage: boolean, size: Size): void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* What an element builds from the context at layout time: a subtree (`Deferred`: a table whose `auto`
|
|
43
|
+
* columns are measured from its cells and fitted to its width), or a Text's lines. It is built again
|
|
44
|
+
* only when the context key or the width changes - the size rules and the one constraint building
|
|
45
|
+
* reads. Whether the page belongs to the key is decided by what was built (`onPage`): a subtree
|
|
46
|
+
* without a `PageBuilder` is the same on every page.
|
|
47
|
+
*/
|
|
48
|
+
export declare class BuiltFromContext<T> {
|
|
49
|
+
private readonly onPage;
|
|
50
|
+
private last?;
|
|
51
|
+
constructor(onPage: (value: T) => boolean);
|
|
52
|
+
get(ctx: LayoutContext, width: number, build: () => T): T;
|
|
53
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The layout cache - the one place a size is remembered. `PDFElement.measure` asks it before
|
|
3
|
+
* `computeSize` runs, and stores what `computeSize` returned.
|
|
4
|
+
*
|
|
5
|
+
* An element never changes after it is built, so its size is a pure function of its INPUTS: the
|
|
6
|
+
* constraints, plus the context fields listed in `Key` below. The same inputs again are answered from
|
|
7
|
+
* the element's own cache. That is what Flutter's dry-layout cache and Yoga's measure cache do; flex
|
|
8
|
+
* asks the same child the same question several times while it distributes space.
|
|
9
|
+
*
|
|
10
|
+
* What keeps it correct:
|
|
11
|
+
* - `computeSize` reads only the context fields in `Key`. A new field that can change a size is added
|
|
12
|
+
* HERE. `frame`, `belowContent`, `pageBodyHeight` and `onOverflow` steer placement and page breaks,
|
|
13
|
+
* never a size, so they are not part of it.
|
|
14
|
+
* - The page (`pageConfig`, `pageInfo`) is part of the key only for an element that
|
|
15
|
+
* `dependsOnPage()`. Every page and both passes bring new page objects, so keying everything on them
|
|
16
|
+
* would make the cache miss on each page.
|
|
17
|
+
* - Context values compare by IDENTITY. Code that derives one (a merged text style) returns the same
|
|
18
|
+
* object for the same input, or every element below it misses.
|
|
19
|
+
* - `fontEpoch` moves when a font face is added, and kerning can be switched on the same metrics; both
|
|
20
|
+
* change widths.
|
|
21
|
+
*
|
|
22
|
+
* The same key, without the constraints, decides when a subtree built at layout time can be reused
|
|
23
|
+
* (`BuiltFromContext`, below).
|
|
24
|
+
*
|
|
25
|
+
* Below this level sit value memos that are not size caches: glyph advances per font
|
|
26
|
+
* (`text/advance.ts`) and a Text's displayed content (`TextElement.display`).
|
|
27
|
+
*/
|
|
28
|
+
export const layoutCache = {
|
|
29
|
+
/** Off only in the test that renders every pinned document both ways and demands the same bytes. */
|
|
30
|
+
enabled: true,
|
|
31
|
+
};
|
|
32
|
+
const contextKeyOf = (ctx, onPage) => ({
|
|
33
|
+
metrics: ctx.metrics,
|
|
34
|
+
fontEpoch: ctx.metrics?.fontEpoch ?? 0,
|
|
35
|
+
kerning: ctx.metrics?.kerningEnabled,
|
|
36
|
+
textStyle: ctx.textStyle,
|
|
37
|
+
pageConfig: onPage ? ctx.pageConfig : undefined,
|
|
38
|
+
pageInfo: onPage ? ctx.pageInfo : undefined,
|
|
39
|
+
boxPaddingBase: ctx.boxPaddingBase,
|
|
40
|
+
});
|
|
41
|
+
const sameContext = (a, b) => a.metrics === b.metrics &&
|
|
42
|
+
a.fontEpoch === b.fontEpoch &&
|
|
43
|
+
a.kerning === b.kerning &&
|
|
44
|
+
a.textStyle === b.textStyle &&
|
|
45
|
+
a.pageConfig === b.pageConfig &&
|
|
46
|
+
a.pageInfo === b.pageInfo &&
|
|
47
|
+
a.boxPaddingBase === b.boxPaddingBase;
|
|
48
|
+
const keyOf = (c, ctx, onPage) => ({
|
|
49
|
+
minWidth: c.minWidth,
|
|
50
|
+
maxWidth: c.maxWidth,
|
|
51
|
+
minHeight: c.minHeight,
|
|
52
|
+
maxHeight: c.maxHeight,
|
|
53
|
+
context: contextKeyOf(ctx, onPage),
|
|
54
|
+
});
|
|
55
|
+
const sameKey = (a, b) => a.minWidth === b.minWidth &&
|
|
56
|
+
a.maxWidth === b.maxWidth &&
|
|
57
|
+
a.minHeight === b.minHeight &&
|
|
58
|
+
a.maxHeight === b.maxHeight &&
|
|
59
|
+
sameContext(a.context, b.context);
|
|
60
|
+
/**
|
|
61
|
+
* How many different questions one element remembers. Flex asks a child at more than one width (its
|
|
62
|
+
* natural width, then its share), so one entry would evict itself.
|
|
63
|
+
*/
|
|
64
|
+
const ENTRIES = 4;
|
|
65
|
+
/** One element's remembered sizes, oldest overwritten first. */
|
|
66
|
+
export class SizeCache {
|
|
67
|
+
constructor() {
|
|
68
|
+
this.entries = [];
|
|
69
|
+
this.next = 0;
|
|
70
|
+
}
|
|
71
|
+
get(constraints, ctx, onPage) {
|
|
72
|
+
if (!layoutCache.enabled)
|
|
73
|
+
return undefined;
|
|
74
|
+
const key = keyOf(constraints, ctx, onPage);
|
|
75
|
+
const hit = this.entries.find((e) => sameKey(e.key, key));
|
|
76
|
+
// A copy: a caller that adjusts the size it was handed must not change the remembered one.
|
|
77
|
+
return hit && { ...hit.size };
|
|
78
|
+
}
|
|
79
|
+
set(constraints, ctx, onPage, size) {
|
|
80
|
+
const entry = { key: keyOf(constraints, ctx, onPage), size: { ...size } };
|
|
81
|
+
if (this.entries.length < ENTRIES)
|
|
82
|
+
this.entries.push(entry);
|
|
83
|
+
else
|
|
84
|
+
this.entries[this.next] = entry;
|
|
85
|
+
this.next = (this.next + 1) % ENTRIES;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* What an element builds from the context at layout time: a subtree (`Deferred`: a table whose `auto`
|
|
90
|
+
* columns are measured from its cells and fitted to its width), or a Text's lines. It is built again
|
|
91
|
+
* only when the context key or the width changes - the size rules and the one constraint building
|
|
92
|
+
* reads. Whether the page belongs to the key is decided by what was built (`onPage`): a subtree
|
|
93
|
+
* without a `PageBuilder` is the same on every page.
|
|
94
|
+
*/
|
|
95
|
+
export class BuiltFromContext {
|
|
96
|
+
constructor(onPage) {
|
|
97
|
+
this.onPage = onPage;
|
|
98
|
+
}
|
|
99
|
+
get(ctx, width, build) {
|
|
100
|
+
const last = this.last;
|
|
101
|
+
if (layoutCache.enabled &&
|
|
102
|
+
last &&
|
|
103
|
+
last.width === width &&
|
|
104
|
+
sameContext(last.key, contextKeyOf(ctx, this.onPage(last.value))))
|
|
105
|
+
return last.value;
|
|
106
|
+
const value = build();
|
|
107
|
+
this.last = { key: contextKeyOf(ctx, this.onPage(value)), width, value };
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export declare function readFileBytes(
|
|
2
|
-
export declare function readFileBytesAsync(_path: string): Promise<Uint8Array>;
|
|
1
|
+
export declare function readFileBytes(path: string): Uint8Array;
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
// Browser stand-in for platform/node-fs.ts (selected by the package.json "browser" field). The browser has
|
|
2
2
|
// no file paths, so loading from one throws a clear, actionable error - pass bytes instead.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
export function readFileBytesAsync(_path) {
|
|
8
|
-
throw new Error(`Loading an image from a file path ${hint}`);
|
|
3
|
+
export function readFileBytes(path) {
|
|
4
|
+
throw new Error(`Loading "${path}" from a file path needs Node. In the browser pass the bytes (a Uint8Array) ` +
|
|
5
|
+
"instead - e.g. import the file as a URL and fetch() it.");
|
|
9
6
|
}
|
package/dist/platform/node-fs.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
// Node implementation of the platform file reads. In a browser bundle this whole module is swapped for
|
|
2
2
|
// platform/browser-fs.ts via the package.json "browser" field, so `node:fs` never reaches the browser.
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
|
-
import { readFile } from "node:fs/promises";
|
|
5
4
|
export function readFileBytes(path) {
|
|
6
5
|
return readFileSync(path);
|
|
7
6
|
}
|
|
8
|
-
export function readFileBytesAsync(path) {
|
|
9
|
-
return readFile(path);
|
|
10
|
-
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
2
|
import { AnchorElement } from "../elements/layout/anchor-element.js";
|
|
3
|
+
import { type RenderScope } from "../utils/renderer-registry.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
export declare class AnchorRenderer {
|
|
5
|
-
static render(element: AnchorElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
6
|
+
static render(element: AnchorElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
6
7
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { RendererRegistry } from "../utils/renderer-registry.js";
|
|
2
2
|
export class AnchorRenderer {
|
|
3
|
-
static async render(element, objectManager) {
|
|
4
|
-
const { name, child, y } = element.getProps();
|
|
5
|
-
|
|
6
|
-
const
|
|
3
|
+
static async render(element, objectManager, scope) {
|
|
4
|
+
const { name, child, y: ownY } = element.getProps();
|
|
5
|
+
// Its own position is relative to `scope.origin`; the IR wants page coordinates.
|
|
6
|
+
const y = scope.origin.y + (ownY ?? 0);
|
|
7
|
+
const childNodes = await RendererRegistry.render(child, objectManager, scope);
|
|
7
8
|
// The child draws normally; an Anchor IR node carries the name + scroll target for the page renderer
|
|
8
9
|
// to register as a named destination (it produces no content-stream ops itself).
|
|
9
10
|
return [...childNodes, { type: "anchor", y, name }];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
2
|
import { BookmarkElement } from "../elements/layout/bookmark-element.js";
|
|
3
|
+
import { type RenderScope } from "../utils/renderer-registry.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
export declare class BookmarkRenderer {
|
|
5
|
-
static render(element: BookmarkElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
6
|
+
static render(element: BookmarkElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
6
7
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { RendererRegistry } from "../utils/renderer-registry.js";
|
|
2
2
|
export class BookmarkRenderer {
|
|
3
|
-
static async render(element, objectManager) {
|
|
4
|
-
const { title, level, child, y } = element.getProps();
|
|
5
|
-
|
|
6
|
-
const
|
|
3
|
+
static async render(element, objectManager, scope) {
|
|
4
|
+
const { title, level, child, y: ownY } = element.getProps();
|
|
5
|
+
// Its own position is relative to `scope.origin`; the IR wants page coordinates.
|
|
6
|
+
const y = scope.origin.y + (ownY ?? 0);
|
|
7
|
+
const childNodes = await RendererRegistry.render(child, objectManager, scope);
|
|
7
8
|
// The child draws normally; an Outline IR node carries the title + nesting + scroll target for the
|
|
8
9
|
// page renderer to collect into the /Outlines tree (it produces no content-stream ops itself).
|
|
9
10
|
return [...childNodes, { type: "outline", y, title, level }];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RenderScope } from "../utils/renderer-registry.js";
|
|
1
2
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
3
|
import { CanvasElement } from "../elements/canvas-element.js";
|
|
3
4
|
import type { IRNode } from "../ir/display-list.js";
|
|
@@ -10,5 +11,5 @@ import type { IRNode } from "../ir/display-list.js";
|
|
|
10
11
|
* past its own edge would otherwise bleed into the layout beside it.
|
|
11
12
|
*/
|
|
12
13
|
export declare class CanvasRenderer {
|
|
13
|
-
static render(element: CanvasElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
14
|
+
static render(element: CanvasElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
14
15
|
}
|
|
@@ -8,8 +8,11 @@ import { CanvasPainter } from "../canvas/painter.js";
|
|
|
8
8
|
* past its own edge would otherwise bleed into the layout beside it.
|
|
9
9
|
*/
|
|
10
10
|
export class CanvasRenderer {
|
|
11
|
-
static async render(element, objectManager) {
|
|
12
|
-
const { x, y, width, height, paint, alt } = element.getProps();
|
|
11
|
+
static async render(element, objectManager, scope) {
|
|
12
|
+
const { x: ownX, y: ownY, width, height, paint, alt } = element.getProps();
|
|
13
|
+
// Its own position is relative to `scope.origin`; the IR wants page coordinates.
|
|
14
|
+
const x = scope.origin.x + (ownX ?? 0);
|
|
15
|
+
const y = scope.origin.y + (ownY ?? 0);
|
|
13
16
|
// The layout bounds are kept as plain numbers, and the painter and the callback each get their
|
|
14
17
|
// OWN size object. Sharing one meant a callback that wrote to `size.width` moved the clip away
|
|
15
18
|
// from the box layout had reserved - the drawing would then bleed into what sits beside it.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RenderScope } from "../utils/renderer-registry.js";
|
|
2
|
+
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
3
|
+
import { ColumnBreakElement } from "../elements/layout/column-break-element.js";
|
|
4
|
+
import { IRNode } from "../ir/display-list.js";
|
|
5
|
+
/** A `ColumnBreak` that reaches this pass was nowhere a Flow could break at it - it had no effect. */
|
|
6
|
+
export declare class ColumnBreakRenderer {
|
|
7
|
+
static render(element: ColumnBreakElement, objectManager: PDFObjectManager, _scope: RenderScope): Promise<IRNode[]>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** A `ColumnBreak` that reaches this pass was nowhere a Flow could break at it - it had no effect. */
|
|
2
|
+
export class ColumnBreakRenderer {
|
|
3
|
+
static async render(element, objectManager, _scope) {
|
|
4
|
+
objectManager.diagnostics.report({
|
|
5
|
+
code: "column-break-ignored",
|
|
6
|
+
severity: "warning",
|
|
7
|
+
message: "ColumnBreak had no effect: it breaks only where a Flow's content runs down a Region - not " +
|
|
8
|
+
"outside a Flow, and not in a Row or a table row, which never break. To start a new page, " +
|
|
9
|
+
"use PageBreak.",
|
|
10
|
+
about: element,
|
|
11
|
+
page: element.page,
|
|
12
|
+
});
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
2
|
import { ContainerElement } from "../elements/container-element.js";
|
|
3
|
+
import { type RenderScope } from "../utils/renderer-registry.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
export declare class ContainerRenderer {
|
|
5
|
-
static render(containerElement: ContainerElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
6
|
+
static render(containerElement: ContainerElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
6
7
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { RendererRegistry } from "../utils/renderer-registry.js";
|
|
1
|
+
import { RendererRegistry, within } from "../utils/renderer-registry.js";
|
|
2
2
|
export class ContainerRenderer {
|
|
3
|
-
static async render(containerElement, objectManager) {
|
|
4
|
-
const { children } = containerElement.getProps();
|
|
3
|
+
static async render(containerElement, objectManager, scope) {
|
|
4
|
+
const { x, y, children } = containerElement.getProps();
|
|
5
5
|
const nodes = [];
|
|
6
|
+
// Its children are placed relative to its own top-left.
|
|
7
|
+
const inner = within(scope, { x, y });
|
|
6
8
|
if (children)
|
|
7
9
|
for (const child of children) {
|
|
8
|
-
|
|
9
|
-
nodes.push(...(await renderer(child, objectManager)));
|
|
10
|
+
nodes.push(...(await RendererRegistry.render(child, objectManager, inner)));
|
|
10
11
|
}
|
|
11
12
|
return nodes;
|
|
12
13
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
|
+
import { type RenderScope } from "../utils/renderer-registry.js";
|
|
2
3
|
import { DefaultTextStyleElement } from "../elements/layout/default-text-style-element.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
export declare class DefaultTextStyleRenderer {
|
|
5
|
-
static render(element: DefaultTextStyleElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
6
|
+
static render(element: DefaultTextStyleElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
6
7
|
}
|
|
@@ -2,9 +2,8 @@ import { RendererRegistry } from "../utils/renderer-registry.js";
|
|
|
2
2
|
// Transparent wrapper: the text style was already resolved onto the descendants at layout time, so
|
|
3
3
|
// the renderer just emits the child's display list (like PaddingRenderer).
|
|
4
4
|
export class DefaultTextStyleRenderer {
|
|
5
|
-
static async render(element, objectManager) {
|
|
5
|
+
static async render(element, objectManager, scope) {
|
|
6
6
|
const { child } = element.getProps();
|
|
7
|
-
|
|
8
|
-
return renderer(child, objectManager);
|
|
7
|
+
return RendererRegistry.render(child, objectManager, scope);
|
|
9
8
|
}
|
|
10
9
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
2
|
import { DeferredElement } from "../elements/layout/deferred-element.js";
|
|
3
|
+
import { type RenderScope } from "../utils/renderer-registry.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
export declare class DeferredRenderer {
|
|
5
|
-
static render(element: DeferredElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
6
|
+
static render(element: DeferredElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
6
7
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { RendererRegistry } from "../utils/renderer-registry.js";
|
|
2
2
|
export class DeferredRenderer {
|
|
3
|
-
static async render(element, objectManager) {
|
|
3
|
+
static async render(element, objectManager, scope) {
|
|
4
4
|
const { composed } = element.getProps();
|
|
5
5
|
if (!composed)
|
|
6
6
|
return [];
|
|
7
|
-
|
|
8
|
-
return renderer(composed, objectManager);
|
|
7
|
+
return RendererRegistry.render(composed, objectManager, scope);
|
|
9
8
|
}
|
|
10
9
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CustomBytesImage } from "../elements/image-element.js";
|
|
2
|
-
import { decodePngToRgbFlate } from "../utils/image-helper.js";
|
|
2
|
+
import { decodePngToRgbFlate, jpegColor } from "../utils/image-helper.js";
|
|
3
3
|
import { bytesFromLatin1 } from "../utils/bytes.js";
|
|
4
4
|
// Per-URL fetch cache (process-wide): an emoji image is fetched once, however many times it appears.
|
|
5
5
|
const cache = new Map();
|
|
@@ -48,6 +48,7 @@ export async function emojiImageNode(codePoint, source, x, baselineY, em) {
|
|
|
48
48
|
// JPEG embeds raw; PNG is decoded to DeviceRGB + an /SMask alpha channel (transparency).
|
|
49
49
|
let data = fileData;
|
|
50
50
|
let smask;
|
|
51
|
+
const color = imageType === "DCTDecode" ? jpegColor(bytesFromLatin1(fileData)) : undefined;
|
|
51
52
|
if (imageType === "FlateDecode") {
|
|
52
53
|
const decoded = await decodePngToRgbFlate(bytesFromLatin1(fileData));
|
|
53
54
|
data = decoded.data;
|
|
@@ -63,6 +64,7 @@ export async function emojiImageNode(codePoint, source, x, baselineY, em) {
|
|
|
63
64
|
intrinsicHeight: dims.height,
|
|
64
65
|
data,
|
|
65
66
|
imageType,
|
|
67
|
+
...(color ? { color } : {}),
|
|
66
68
|
...(smask ? { smask } : {}),
|
|
67
69
|
};
|
|
68
70
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
|
+
import { type RenderScope } from "../utils/renderer-registry.js";
|
|
2
3
|
import { ExpandedElement } from "../elements/index.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
export declare class ExpandedRenderer {
|
|
5
|
-
static render(expandedElement: ExpandedElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
6
|
+
static render(expandedElement: ExpandedElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
6
7
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { RendererRegistry } from "../utils/renderer-registry.js";
|
|
2
2
|
export class ExpandedRenderer {
|
|
3
|
-
static async render(expandedElement, objectManager) {
|
|
3
|
+
static async render(expandedElement, objectManager, scope) {
|
|
4
4
|
const { child } = expandedElement.getProps();
|
|
5
|
-
|
|
6
|
-
return renderer(child, objectManager);
|
|
5
|
+
return RendererRegistry.render(child, objectManager, scope);
|
|
7
6
|
}
|
|
8
7
|
}
|