@jasy/pdf 1.0.0-beta.3 → 1.0.0-beta.4
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/content.d.ts +5 -5
- package/dist/api/content.js +12 -6
- 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/index.d.ts +2 -0
- package/dist/api/index.js +1 -0
- package/dist/api/layout.d.ts +6 -0
- package/dist/api/layout.js +7 -2
- 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 +99 -22
- package/dist/common/diagnostics.d.ts +53 -0
- package/dist/common/diagnostics.js +77 -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 +5 -1
- package/dist/elements/container-element.js +35 -15
- 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 +39 -1
- package/dist/elements/image-element.js +95 -12
- 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/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 +12 -4
- package/dist/elements/layout/deferred-element.js +24 -7
- package/dist/elements/layout/expanded-element.d.ts +7 -0
- package/dist/elements/layout/expanded-element.js +40 -18
- package/dist/elements/layout/keep-together-element.d.ts +8 -18
- package/dist/elements/layout/keep-together-element.js +21 -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 +15 -1
- package/dist/elements/layout/padding-element.js +55 -27
- 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 +11 -0
- package/dist/elements/layout/positioned-element.d.ts +14 -2
- package/dist/elements/layout/positioned-element.js +36 -10
- package/dist/elements/layout/proxy-element.d.ts +43 -0
- package/dist/elements/layout/proxy-element.js +94 -0
- package/dist/elements/layout/repeating-header-element.d.ts +6 -0
- package/dist/elements/layout/repeating-header-element.js +40 -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 +7 -0
- package/dist/elements/layout/rotated-element.js +25 -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 +75 -15
- package/dist/elements/pdf-element.js +68 -18
- package/dist/elements/rectangle-element.d.ts +14 -0
- package/dist/elements/rectangle-element.js +97 -52
- package/dist/elements/row-element.d.ts +11 -0
- package/dist/elements/row-element.js +58 -8
- package/dist/elements/svg-element.d.ts +30 -6
- package/dist/elements/svg-element.js +88 -17
- package/dist/elements/text-element.d.ts +32 -13
- package/dist/elements/text-element.js +119 -97
- 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 +12 -2
- package/dist/layout/box-constraints.d.ts +5 -0
- package/dist/layout/box-constraints.js +14 -0
- package/dist/layout/collect-images.d.ts +6 -4
- package/dist/layout/collect-images.js +6 -4
- package/dist/layout/flex-item.d.ts +9 -0
- package/dist/layout/flex-item.js +39 -0
- package/dist/layout/fragmentation.d.ts +12 -4
- package/dist/layout/fragmentation.js +37 -14
- package/dist/layout/layout-cache.d.ts +53 -0
- package/dist/layout/layout-cache.js +107 -0
- 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/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/expanded-renderer.d.ts +2 -1
- package/dist/renderer/expanded-renderer.js +2 -3
- 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 +5 -2
- 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 +28 -7
- package/dist/renderer/pdf-backend.d.ts +4 -3
- package/dist/renderer/pdf-backend.js +5 -5
- package/dist/renderer/pdf-document-renderer.d.ts +1 -8
- package/dist/renderer/pdf-document-renderer.js +15 -16
- package/dist/renderer/pdf-renderer.js +11 -11
- package/dist/renderer/positioned-renderer.d.ts +6 -1
- package/dist/renderer/positioned-renderer.js +6 -5
- package/dist/renderer/rectangle-renderer.d.ts +2 -1
- package/dist/renderer/rectangle-renderer.js +9 -4
- 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 +8 -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 +101 -111
- package/dist/svg/gradients.js +5 -0
- package/dist/svg/index.js +10 -1
- package/dist/svg/style.d.ts +2 -0
- package/dist/svg/style.js +11 -0
- 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 +34 -31
- package/dist/text/line-breaker.js +364 -176
- package/dist/text/line-metrics.d.ts +6 -3
- package/dist/text/line-metrics.js +7 -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 +34 -8
- 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 +13 -13
- package/dist/utils/flex-layout.js +318 -216
- package/dist/utils/font-metrics.d.ts +4 -3
- package/dist/utils/image-helper.js +2 -1
- package/dist/utils/pdf-object-manager.d.ts +11 -3
- package/dist/utils/pdf-object-manager.js +39 -13
- package/dist/utils/renderer-registry.d.ts +43 -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 +27 -4
- 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
|
@@ -17,6 +17,13 @@ export class PDFDocumentElement extends PDFElement {
|
|
|
17
17
|
this.children.forEach((child) => child.calculateLayout(new BoxConstraints(), origin, ctx));
|
|
18
18
|
return { width: 0, height: 0 };
|
|
19
19
|
}
|
|
20
|
+
/** The root has no size of its own. */
|
|
21
|
+
computeSize() {
|
|
22
|
+
return { width: 0, height: 0 };
|
|
23
|
+
}
|
|
24
|
+
layoutChildren() {
|
|
25
|
+
return this.children;
|
|
26
|
+
}
|
|
20
27
|
getProps() {
|
|
21
28
|
return { children: this.children, defaultTextStyle: this.defaultTextStyle };
|
|
22
29
|
}
|
|
@@ -2,6 +2,7 @@ import type { FontMetrics } from "../utils/font-metrics.js";
|
|
|
2
2
|
import type { PDFPageConfig } from "./page-element.js";
|
|
3
3
|
import type { ResolvedTextStyle } from "../text/text-style.js";
|
|
4
4
|
import type { OverflowPolicy } from "../layout/fragmentation.js";
|
|
5
|
+
import type { Diagnostics } from "../common/diagnostics.js";
|
|
5
6
|
import type { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
|
|
6
7
|
import type { CrossAlign } from "../layout/alignment.js";
|
|
7
8
|
/**
|
|
@@ -11,18 +12,14 @@ import type { CrossAlign } from "../layout/alignment.js";
|
|
|
11
12
|
* height. The PDF byte writer is deliberately absent - layout must not touch it.
|
|
12
13
|
*/
|
|
13
14
|
/**
|
|
14
|
-
* A positioning frame - the CSS "containing block" that `Positioned` children resolve their
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* A positioning frame - the CSS "containing block" that `Positioned` children resolve their offsets
|
|
16
|
+
* against: the page's content box, or a `relative` Box. Threaded to the subtree so a `Positioned`
|
|
17
|
+
* can tell it has one. The frame's owner finds its `Positioned` descendants by walking the tree
|
|
18
|
+
* after sizing itself, and lays them out against its own box - layout itself registers nothing.
|
|
18
19
|
*/
|
|
19
20
|
export interface PositioningFrame {
|
|
20
21
|
origin: Offset;
|
|
21
22
|
size: Size;
|
|
22
|
-
place: Array<(frame: {
|
|
23
|
-
origin: Offset;
|
|
24
|
-
size: Size;
|
|
25
|
-
}, ctx: LayoutContext) => void>;
|
|
26
23
|
}
|
|
27
24
|
/**
|
|
28
25
|
* What a `PageBuilder` learns about the page it landed on. `pageNumber` is 1-based and counts PHYSICAL
|
|
@@ -62,24 +59,86 @@ export interface LayoutContext {
|
|
|
62
59
|
/** What to do when an element overflows a page region and cannot break (set from the render option;
|
|
63
60
|
* absent = clip silently). Evaluated in `packChildren` where the forced placement happens. */
|
|
64
61
|
onOverflow?: OverflowPolicy;
|
|
65
|
-
/** The
|
|
66
|
-
*
|
|
67
|
-
|
|
62
|
+
/** The render's diagnostics channel. Never part of a size, so never part of the layout-cache key;
|
|
63
|
+
* absent when an element is laid out on its own, which then warns as before. */
|
|
64
|
+
diagnostics?: Diagnostics;
|
|
65
|
+
/** The physical page (1-based) pagination is filling - only so a diagnostic can name it; the render
|
|
66
|
+
* pass knows it as `pageInfo`. Never part of a size. */
|
|
67
|
+
paginatingPage?: number;
|
|
68
|
+
/** The height a FRESH page gives this region: the page body (between header and footer, set by the
|
|
69
|
+
* page driver) minus what encloses the region on every page - a border, padding, a repeated table
|
|
70
|
+
* header (`insetContext`). A `keepTogether` group reads it to decide the degrade rule: veto splitting
|
|
71
|
+
* only when the group would fit on a fresh page; a group taller than that drops the veto and splits. */
|
|
68
72
|
pageBodyHeight?: number;
|
|
73
|
+
/** Something already sits above this element in the current page region. Then "does not fit"
|
|
74
|
+
* means "move to the next page", never an overflow - only content at the top of a fresh page is
|
|
75
|
+
* forced on and reported. Set by `packChildren`; absent = top of the page. */
|
|
76
|
+
belowContent?: boolean;
|
|
77
|
+
/** What a `Box`'s percentage padding resolves against: the width the Box itself was offered (CSS:
|
|
78
|
+
* the containing block), not its inner width. Set by the Box for its own padding only. */
|
|
79
|
+
boxPaddingBase?: number;
|
|
69
80
|
}
|
|
70
81
|
export declare abstract class PDFElement {
|
|
71
82
|
private _structId;
|
|
72
83
|
get structId(): number;
|
|
73
84
|
/** Make this element share `from`'s tagging identity - used by fragmentation clones. Returns this. */
|
|
74
85
|
adoptStructId(from: PDFElement): this;
|
|
86
|
+
/**
|
|
87
|
+
* Marks this element as a piece of `original`, split across pages: it is the same element to a
|
|
88
|
+
* reader of the tagged PDF (one structure element) and to the Row or Column it sits in (its flex
|
|
89
|
+
* properties). Every fragmentation clone ends in this call, so a property added to the base is
|
|
90
|
+
* carried in ONE place. Returns this.
|
|
91
|
+
*/
|
|
92
|
+
asPieceOf(original: PDFElement): this;
|
|
93
|
+
/** Takes the flex properties `original` set (CSS `align-self`, `order`, `flex-shrink`). Returns this. */
|
|
94
|
+
takeFlexItemFrom(original: PDFElement): this;
|
|
75
95
|
abstract getProps(): unknown;
|
|
76
96
|
/**
|
|
77
97
|
* Lays the element out: `constraints` bound its size (flows DOWN), `offset` is the
|
|
78
|
-
*
|
|
98
|
+
* top-left position the parent assigns it, relative to the parent's own top-left (absolute
|
|
99
|
+
* coordinates exist only in the render pass), and the returned `Size` is the
|
|
79
100
|
* space it actually took (flows UP). Layout works in a top-left origin; the Y-flip
|
|
80
101
|
* happens once at the IR -> backend seam.
|
|
81
102
|
*/
|
|
82
103
|
abstract calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
104
|
+
/**
|
|
105
|
+
* The size `calculateLayout` would return under these constraints - with NO side effects: no
|
|
106
|
+
* position, no stored size, nothing registered with a frame. A parent asks this to decide, and lays
|
|
107
|
+
* a child out once afterwards; asking with a full layout doubled the work at every nesting level.
|
|
108
|
+
* Do not override it - implement `computeSize` (as Flutter's `getDryLayout` / `computeDryLayout`).
|
|
109
|
+
* The same question twice is answered from the layout cache (`layout/layout-cache.ts`).
|
|
110
|
+
*/
|
|
111
|
+
measure(constraints: BoxConstraints, ctx: LayoutContext): Size;
|
|
112
|
+
/**
|
|
113
|
+
* The part of the constraints this element's size actually reads - what the layout cache keys on.
|
|
114
|
+
* All of it by default. An element whose size ignores a bound returns it opened up, so two questions
|
|
115
|
+
* that differ only there share one answer. It must be TRUE for `computeSize`: reading a bound that
|
|
116
|
+
* is dropped here makes the cache hand back a wrong size.
|
|
117
|
+
*/
|
|
118
|
+
protected sizeInputs(constraints: BoxConstraints): BoxConstraints;
|
|
119
|
+
private sizeCache?;
|
|
120
|
+
/**
|
|
121
|
+
* Whether this element's size can depend on the page it lands on (`pageConfig`, `pageInfo`): a
|
|
122
|
+
* `PageBuilder`, a `Page`, and everything holding one. Only those key a cached size on the page, so
|
|
123
|
+
* every other size is reused across pages and across the pagination and render passes. Remembered:
|
|
124
|
+
* the tree does not change, and an answer that was `false` can never become `true`.
|
|
125
|
+
*/
|
|
126
|
+
dependsOnPage(): boolean;
|
|
127
|
+
private pageDependent?;
|
|
128
|
+
/**
|
|
129
|
+
* How this element sizes itself for `measure`. It must come from the SAME sizing computation as
|
|
130
|
+
* `calculateLayout`, or a measured size and a laid-out one can differ.
|
|
131
|
+
*/
|
|
132
|
+
protected abstract computeSize(constraints: BoxConstraints, ctx: LayoutContext): Size;
|
|
133
|
+
/** The elements this one lays out, for walks that must see the whole tree. Leaves have none. */
|
|
134
|
+
layoutChildren(): readonly PDFElement[];
|
|
135
|
+
/**
|
|
136
|
+
* The element this one is transparent for, if any: a `ProxyElement` returns its child. A surrounding
|
|
137
|
+
* Row or Column looks through it for the flex item (`layout/flex-item.ts`).
|
|
138
|
+
*/
|
|
139
|
+
proxied(): PDFElement | undefined;
|
|
140
|
+
/** Lays out its own `Positioned` descendants (a page, a `relative` Box); a walk for them stops here. */
|
|
141
|
+
isPositioningFrame(): boolean;
|
|
83
142
|
/**
|
|
84
143
|
* The relative-size fraction (0..1) this element asked for on the given axis, if any (`horizontal` =
|
|
85
144
|
* width). A flex parent reads it to resolve a percentage child against its OWN main size - e.g. a
|
|
@@ -141,9 +200,9 @@ export declare abstract class PDFElement {
|
|
|
141
200
|
/**
|
|
142
201
|
* Where this child sits among its siblings (CSS `order`), lowest first, source order deciding ties.
|
|
143
202
|
* It moves the child in the LAYOUT only - the element tree, and therefore the reading order a tagged
|
|
144
|
-
* PDF exposes, is untouched.
|
|
203
|
+
* PDF exposes, is untouched. Unset means 0; a stack reads it through `layout/flex-item.ts`.
|
|
145
204
|
*/
|
|
146
|
-
order
|
|
205
|
+
order?: number;
|
|
147
206
|
/**
|
|
148
207
|
* How willingly this child gives up main-axis space when the line overflows (CSS `flex-shrink`),
|
|
149
208
|
* weighted by its own size as CSS does. Default 1, as in CSS: an overflowing line squeezes its
|
|
@@ -154,8 +213,9 @@ export declare abstract class PDFElement {
|
|
|
154
213
|
* caution outlived its use: four of the gallery cases turned out to be overflowing their page
|
|
155
214
|
* margin without anyone noticing, because nothing ever pulled them back. Shrinking is bounded from
|
|
156
215
|
* below by `minIntrinsicMain`, so a child is never squeezed past what it can actually hold.
|
|
216
|
+
* Unset means 1; a stack reads it through `layout/flex-item.ts`.
|
|
157
217
|
*/
|
|
158
|
-
flexShrink
|
|
218
|
+
flexShrink?: number;
|
|
159
219
|
/** Sets `flexShrink` and returns the element. */
|
|
160
220
|
withFlexShrink(shrink: number | undefined): this;
|
|
161
221
|
/** Sets `order` and returns the element, so a factory can thread it through in one expression. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SizeCache } from "../layout/layout-cache.js";
|
|
1
2
|
let _nextStructId = 0;
|
|
2
3
|
export class PDFElement {
|
|
3
4
|
constructor() {
|
|
@@ -5,24 +6,6 @@ export class PDFElement {
|
|
|
5
6
|
// fragmentation copies (adoptStructId), so a paragraph or table split across pages stays ONE structure
|
|
6
7
|
// element. Only the elements that actually tag (Text, Image, StructGroup) read it.
|
|
7
8
|
this._structId = _nextStructId++;
|
|
8
|
-
/**
|
|
9
|
-
* Where this child sits among its siblings (CSS `order`), lowest first, source order deciding ties.
|
|
10
|
-
* It moves the child in the LAYOUT only - the element tree, and therefore the reading order a tagged
|
|
11
|
-
* PDF exposes, is untouched. Default 0.
|
|
12
|
-
*/
|
|
13
|
-
this.order = 0;
|
|
14
|
-
/**
|
|
15
|
-
* How willingly this child gives up main-axis space when the line overflows (CSS `flex-shrink`),
|
|
16
|
-
* weighted by its own size as CSS does. Default 1, as in CSS: an overflowing line squeezes its
|
|
17
|
-
* children back inside instead of letting them run past the edge of the box. `0` opts out and keeps
|
|
18
|
-
* a child at its natural size.
|
|
19
|
-
*
|
|
20
|
-
* This was 0 until the alpha, so that adding flexShrink could not move an existing layout. That
|
|
21
|
-
* caution outlived its use: four of the gallery cases turned out to be overflowing their page
|
|
22
|
-
* margin without anyone noticing, because nothing ever pulled them back. Shrinking is bounded from
|
|
23
|
-
* below by `minIntrinsicMain`, so a child is never squeezed past what it can actually hold.
|
|
24
|
-
*/
|
|
25
|
-
this.flexShrink = 1;
|
|
26
9
|
}
|
|
27
10
|
get structId() {
|
|
28
11
|
return this._structId;
|
|
@@ -32,6 +15,73 @@ export class PDFElement {
|
|
|
32
15
|
this._structId = from._structId;
|
|
33
16
|
return this;
|
|
34
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Marks this element as a piece of `original`, split across pages: it is the same element to a
|
|
20
|
+
* reader of the tagged PDF (one structure element) and to the Row or Column it sits in (its flex
|
|
21
|
+
* properties). Every fragmentation clone ends in this call, so a property added to the base is
|
|
22
|
+
* carried in ONE place. Returns this.
|
|
23
|
+
*/
|
|
24
|
+
asPieceOf(original) {
|
|
25
|
+
return this.adoptStructId(original).takeFlexItemFrom(original);
|
|
26
|
+
}
|
|
27
|
+
/** Takes the flex properties `original` set (CSS `align-self`, `order`, `flex-shrink`). Returns this. */
|
|
28
|
+
takeFlexItemFrom(original) {
|
|
29
|
+
this.alignSelf = original.alignSelf ?? this.alignSelf;
|
|
30
|
+
this.order = original.order ?? this.order;
|
|
31
|
+
this.flexShrink = original.flexShrink ?? this.flexShrink;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The size `calculateLayout` would return under these constraints - with NO side effects: no
|
|
36
|
+
* position, no stored size, nothing registered with a frame. A parent asks this to decide, and lays
|
|
37
|
+
* a child out once afterwards; asking with a full layout doubled the work at every nesting level.
|
|
38
|
+
* Do not override it - implement `computeSize` (as Flutter's `getDryLayout` / `computeDryLayout`).
|
|
39
|
+
* The same question twice is answered from the layout cache (`layout/layout-cache.ts`).
|
|
40
|
+
*/
|
|
41
|
+
measure(constraints, ctx) {
|
|
42
|
+
const cache = (this.sizeCache ?? (this.sizeCache = new SizeCache()));
|
|
43
|
+
const asked = this.sizeInputs(constraints);
|
|
44
|
+
const onPage = this.dependsOnPage();
|
|
45
|
+
const known = cache.get(asked, ctx, onPage);
|
|
46
|
+
if (known)
|
|
47
|
+
return known;
|
|
48
|
+
const size = this.computeSize(constraints, ctx);
|
|
49
|
+
cache.set(asked, ctx, onPage, size);
|
|
50
|
+
return size;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The part of the constraints this element's size actually reads - what the layout cache keys on.
|
|
54
|
+
* All of it by default. An element whose size ignores a bound returns it opened up, so two questions
|
|
55
|
+
* that differ only there share one answer. It must be TRUE for `computeSize`: reading a bound that
|
|
56
|
+
* is dropped here makes the cache hand back a wrong size.
|
|
57
|
+
*/
|
|
58
|
+
sizeInputs(constraints) {
|
|
59
|
+
return constraints;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Whether this element's size can depend on the page it lands on (`pageConfig`, `pageInfo`): a
|
|
63
|
+
* `PageBuilder`, a `Page`, and everything holding one. Only those key a cached size on the page, so
|
|
64
|
+
* every other size is reused across pages and across the pagination and render passes. Remembered:
|
|
65
|
+
* the tree does not change, and an answer that was `false` can never become `true`.
|
|
66
|
+
*/
|
|
67
|
+
dependsOnPage() {
|
|
68
|
+
return (this.pageDependent ?? (this.pageDependent = this.layoutChildren().some((child) => child.dependsOnPage())));
|
|
69
|
+
}
|
|
70
|
+
/** The elements this one lays out, for walks that must see the whole tree. Leaves have none. */
|
|
71
|
+
layoutChildren() {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The element this one is transparent for, if any: a `ProxyElement` returns its child. A surrounding
|
|
76
|
+
* Row or Column looks through it for the flex item (`layout/flex-item.ts`).
|
|
77
|
+
*/
|
|
78
|
+
proxied() {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
/** Lays out its own `Positioned` descendants (a page, a `relative` Box); a walk for them stops here. */
|
|
82
|
+
isPositioningFrame() {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
35
85
|
/**
|
|
36
86
|
* The relative-size fraction (0..1) this element asked for on the given axis, if any (`horizontal` =
|
|
37
87
|
* width). A flex parent reads it to resolve a percentage child against its OWN main size - e.g. a
|
|
@@ -78,9 +78,22 @@ export declare class RectangleElement extends SizedPDFElement implements Fragmen
|
|
|
78
78
|
* `Spacer` in a box can only resolve if the box itself was given a bounded extent to pass down. With an
|
|
79
79
|
* explicit size on an axis the box already knows its extent there and asks for nothing. */
|
|
80
80
|
needsBoundedMain(horizontal: boolean): boolean;
|
|
81
|
+
/** A Box's own padding resolves a percentage against what the Box was OFFERED (CSS: the containing
|
|
82
|
+
* block), not against the inner width it hands its children - so it is told. Only a bounded offer:
|
|
83
|
+
* in a Row a child is offered no width at all, and there the padding keeps resolving against the
|
|
84
|
+
* Box's own width, as it always did. */
|
|
85
|
+
private paddingContext;
|
|
81
86
|
/** A Box stacks its children vertically inside its border, which is on both sides of the axis. */
|
|
82
87
|
minIntrinsicMain(horizontal: boolean, ctx: LayoutContext): number;
|
|
83
88
|
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
89
|
+
protected computeSize(constraints: BoxConstraints, ctx: LayoutContext): Size;
|
|
90
|
+
/**
|
|
91
|
+
* The one sizing path. With an `offset` it lays the children out and keeps its geometry; with
|
|
92
|
+
* `null` it only measures - no field written, no child placed, no frame drained.
|
|
93
|
+
*/
|
|
94
|
+
private sizeWith;
|
|
95
|
+
isPositioningFrame(): boolean;
|
|
96
|
+
layoutChildren(): readonly PDFElement[];
|
|
84
97
|
getProps(): {
|
|
85
98
|
x: number;
|
|
86
99
|
y: number;
|
|
@@ -93,6 +106,7 @@ export declare class RectangleElement extends SizedPDFElement implements Fragmen
|
|
|
93
106
|
radius: number | Radii;
|
|
94
107
|
sideBorders: SideBorders | undefined;
|
|
95
108
|
overflow: "hidden" | "visible";
|
|
109
|
+
relative: boolean;
|
|
96
110
|
};
|
|
97
111
|
}
|
|
98
112
|
export {};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { widthRules } from "../layout/box-constraints.js";
|
|
1
2
|
import { Color } from "../common/color.js";
|
|
2
3
|
import { BoxConstraints, extentSpecs, resolveSize, } from "../layout/box-constraints.js";
|
|
3
4
|
import { stackMinIntrinsic, withDeclaredExtent } from "../layout/min-intrinsic.js";
|
|
4
|
-
import {
|
|
5
|
+
import { positionedIn } from "./layout/positioned-element.js";
|
|
6
|
+
import { PaddingElement } from "./layout/padding-element.js";
|
|
7
|
+
import { childrenForceBreak, insetContext, packChildren, } from "../layout/fragmentation.js";
|
|
5
8
|
import { SizedPDFElement, } from "./pdf-element.js";
|
|
6
9
|
export class RectangleElement extends SizedPDFElement {
|
|
7
10
|
constructor({ children = [], color = new Color(0, 0, 0), backgroundColor, borderWidth, width, height, radius, sideBorders, relative, overflow, breakBefore, breakAfter, ...sizing }) {
|
|
@@ -20,8 +23,10 @@ export class RectangleElement extends SizedPDFElement {
|
|
|
20
23
|
this.breakAfter = breakAfter ?? false;
|
|
21
24
|
this.sizeMemory = { ...sizing, x: 0, y: 0, width, height };
|
|
22
25
|
}
|
|
26
|
+
// A break before the FIRST child is a break before this stack (CSS propagates it): the whole stack
|
|
27
|
+
// moves to the next page, instead of leaving an empty piece - or an empty border - behind.
|
|
23
28
|
breaksBefore() {
|
|
24
|
-
return this.breakBefore;
|
|
29
|
+
return this.breakBefore || (this.children[0]?.breaksBefore() ?? false);
|
|
25
30
|
}
|
|
26
31
|
breaksAfter() {
|
|
27
32
|
return this.breakAfter;
|
|
@@ -35,23 +40,29 @@ export class RectangleElement extends SizedPDFElement {
|
|
|
35
40
|
* box is sized by what it actually holds on each page.
|
|
36
41
|
*/
|
|
37
42
|
fragment(maxHeight, width, ctx) {
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
const boxWidth = this.
|
|
41
|
-
(this.sizeMemory.widthFactor !== undefined ? width * this.sizeMemory.widthFactor : width);
|
|
43
|
+
// The box's own width rules (fixed, %, min/max) resolved against the region - the same sizing
|
|
44
|
+
// path as `measure`, so the content is packed at the width it will be drawn at.
|
|
45
|
+
const boxWidth = this.measure(BoxConstraints.loose(width, Infinity), ctx).width;
|
|
42
46
|
const innerWidth = Math.max(0, boxWidth - 2 * this.borderWidth);
|
|
43
47
|
// Border-box: the content is inset by the border on top and bottom, so a fragment
|
|
44
48
|
// holding `c` of content is `c + 2*border` tall. (Derived, not a fudge factor.)
|
|
45
49
|
const innerMaxHeight = maxHeight - 2 * this.borderWidth;
|
|
46
|
-
const { fitted, remainder, forceBreak } = packChildren(this.children, innerMaxHeight, innerWidth, ctx);
|
|
50
|
+
const { fitted, remainder, forceBreak } = packChildren(this.children, innerMaxHeight, innerWidth, insetContext(this.paddingContext(ctx, width), 2 * this.borderWidth));
|
|
47
51
|
// Fits with no forced cut: return the whole box unchanged. A trailing forced break is the
|
|
48
52
|
// exception - fall through so the box is rebuilt from the packed children (without the consumed
|
|
49
53
|
// break marker), rather than handing back the original that still holds it.
|
|
50
|
-
if (remainder.length === 0 && !forceBreak)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
if (remainder.length === 0 && !forceBreak) {
|
|
55
|
+
// The content fits, but a fixed height may not - such a box cannot shrink, so it moves on whole.
|
|
56
|
+
const own = this.measure(BoxConstraints.loose(width, Infinity), ctx).height;
|
|
57
|
+
return own <= maxHeight
|
|
58
|
+
? { fitted: this, remainder: null }
|
|
59
|
+
: { fitted: null, remainder: this };
|
|
60
|
+
}
|
|
61
|
+
// Nothing fit below the content above: move on whole, not as an empty bordered box.
|
|
62
|
+
if (fitted.length === 0 && !forceBreak)
|
|
63
|
+
return { fitted: null, remainder: this };
|
|
64
|
+
const childCtx = this.paddingContext(ctx, width);
|
|
65
|
+
const contentHeight = (kids) => kids.reduce((sum, child) => sum + child.measure(BoxConstraints.loose(innerWidth, Infinity), childCtx).height, 0);
|
|
55
66
|
return {
|
|
56
67
|
fitted: this.cloneWithChildren(fitted, contentHeight(fitted) + 2 * this.borderWidth),
|
|
57
68
|
// A trailing forced break leaves nothing to carry over: no remainder box, no extra page.
|
|
@@ -70,10 +81,9 @@ export class RectangleElement extends SizedPDFElement {
|
|
|
70
81
|
return new RectangleElement({
|
|
71
82
|
x: 0,
|
|
72
83
|
y: 0,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
//
|
|
76
|
-
// is intentionally dropped here - box-decoration-break, same as an explicit height.
|
|
84
|
+
...widthRules(this.sizeMemory),
|
|
85
|
+
// A split box is sized by its per-page content (height passed in), so the height rules are
|
|
86
|
+
// intentionally dropped here - box-decoration-break, same as an explicit height.
|
|
77
87
|
height,
|
|
78
88
|
children,
|
|
79
89
|
color: this.color,
|
|
@@ -84,7 +94,7 @@ export class RectangleElement extends SizedPDFElement {
|
|
|
84
94
|
relative: this.relative,
|
|
85
95
|
overflow: this.overflow,
|
|
86
96
|
breakAfter,
|
|
87
|
-
});
|
|
97
|
+
}).asPieceOf(this);
|
|
88
98
|
}
|
|
89
99
|
relativeSizeFactor(horizontal) {
|
|
90
100
|
return horizontal ? this.sizeMemory.widthFactor : this.sizeMemory.heightFactor;
|
|
@@ -100,12 +110,32 @@ export class RectangleElement extends SizedPDFElement {
|
|
|
100
110
|
return false;
|
|
101
111
|
return this.children.some((c) => c.needsBoundedMain(horizontal));
|
|
102
112
|
}
|
|
113
|
+
/** A Box's own padding resolves a percentage against what the Box was OFFERED (CSS: the containing
|
|
114
|
+
* block), not against the inner width it hands its children - so it is told. Only a bounded offer:
|
|
115
|
+
* in a Row a child is offered no width at all, and there the padding keeps resolving against the
|
|
116
|
+
* Box's own width, as it always did. */
|
|
117
|
+
paddingContext(ctx, offered) {
|
|
118
|
+
const own = this.children[0];
|
|
119
|
+
return own instanceof PaddingElement && own.ofBox && Number.isFinite(offered)
|
|
120
|
+
? { ...ctx, boxPaddingBase: offered }
|
|
121
|
+
: ctx;
|
|
122
|
+
}
|
|
103
123
|
/** A Box stacks its children vertically inside its border, which is on both sides of the axis. */
|
|
104
124
|
minIntrinsicMain(horizontal, ctx) {
|
|
105
125
|
const content = stackMinIntrinsic(this.children, 0, !horizontal, horizontal, ctx) + 2 * this.borderWidth;
|
|
106
126
|
return withDeclaredExtent(content, horizontal ? this.sizeMemory.width : this.sizeMemory.height, horizontal ? this.sizeMemory.minWidth : this.sizeMemory.minHeight);
|
|
107
127
|
}
|
|
108
128
|
calculateLayout(constraints, offset, ctx) {
|
|
129
|
+
return this.sizeWith(constraints, ctx, offset);
|
|
130
|
+
}
|
|
131
|
+
computeSize(constraints, ctx) {
|
|
132
|
+
return this.sizeWith(constraints, ctx, null);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The one sizing path. With an `offset` it lays the children out and keeps its geometry; with
|
|
136
|
+
* `null` it only measures - no field written, no child placed, no frame drained.
|
|
137
|
+
*/
|
|
138
|
+
sizeWith(constraints, ctx, offset) {
|
|
109
139
|
// An explicit extent is a fixed point size or a fraction of the offered box (relative sizing);
|
|
110
140
|
// the fraction only resolves in a bounded region. `undefined` = fill / shrink-wrap below.
|
|
111
141
|
const specs = extentSpecs(this.sizeMemory);
|
|
@@ -118,12 +148,11 @@ export class RectangleElement extends SizedPDFElement {
|
|
|
118
148
|
// fixed box would balloon to the parent's size.)
|
|
119
149
|
// Whether there is a region to fill is decided by the constraints we were GIVEN: a `maxWidth` caps
|
|
120
150
|
// a box, it does not turn a shrink-wrapping one into a filling one (CSS `max-width` does not either).
|
|
121
|
-
|
|
122
|
-
explicitWidth
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
: this.width;
|
|
151
|
+
let width = explicitWidth !== undefined
|
|
152
|
+
? bounds.constrainWidth(explicitWidth)
|
|
153
|
+
: constraints.hasBoundedWidth
|
|
154
|
+
? bounds.maxWidth
|
|
155
|
+
: undefined;
|
|
127
156
|
// Width shrink-wrap: no explicit width AND an unbounded region (e.g. a `Box` badge inside a
|
|
128
157
|
// `Positioned`). Resolved after the children are measured, just below.
|
|
129
158
|
const shrinkWrapWidth = explicitWidth === undefined && !constraints.hasBoundedWidth;
|
|
@@ -131,43 +160,46 @@ export class RectangleElement extends SizedPDFElement {
|
|
|
131
160
|
// SHRINK-WRAP the content in an unbounded one (a note box in a stack). Shrink-wrap is
|
|
132
161
|
// resolved after the children are measured, just below.
|
|
133
162
|
const shrinkWrapHeight = explicitHeight === undefined && !constraints.hasBoundedHeight;
|
|
134
|
-
|
|
135
|
-
explicitHeight
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
? { origin: { x: 0, y: 0 }, size: { width: 0, height: 0 }, place: [] }
|
|
163
|
+
let height = explicitHeight !== undefined
|
|
164
|
+
? bounds.constrainHeight(explicitHeight)
|
|
165
|
+
: constraints.hasBoundedHeight
|
|
166
|
+
? bounds.maxHeight
|
|
167
|
+
: undefined;
|
|
168
|
+
const x = this.sizeMemory.x + (offset?.x ?? 0);
|
|
169
|
+
const y = this.sizeMemory.y + (offset?.y ?? 0);
|
|
170
|
+
// A `relative` box is a positioning frame: its subtree is told it has one, and once the box is
|
|
171
|
+
// sized it lays out the `Positioned` descendants against itself (below). Measuring places
|
|
172
|
+
// nothing, so it needs no frame. A plain box leaves `ctx` untouched.
|
|
173
|
+
const frame = this.relative && offset
|
|
174
|
+
? { origin: { x: 0, y: 0 }, size: { width: 0, height: 0 } }
|
|
147
175
|
: undefined;
|
|
148
|
-
const childCtx = frame ? { ...ctx, frame } : ctx;
|
|
176
|
+
const childCtx = this.paddingContext(frame ? { ...ctx, frame } : ctx, constraints.maxWidth);
|
|
149
177
|
// Lay out children stacked inside the border (inset by the border width). Width is finalized here;
|
|
150
178
|
// height is left unbounded so each child sizes to its own content - EXCEPT for a child that cannot
|
|
151
179
|
// lay itself out without a bound (a stack holding an `Expanded`/`Spacer`). That one gets the height
|
|
152
180
|
// still free inside the box, so its flex child has real leftover space instead of an infinite one.
|
|
153
181
|
const innerWidth = shrinkWrapWidth
|
|
154
182
|
? Infinity
|
|
155
|
-
: Math.max(0, (
|
|
183
|
+
: Math.max(0, (width ?? 0) - 2 * this.borderWidth);
|
|
156
184
|
const innerHeight = shrinkWrapHeight
|
|
157
185
|
? Infinity
|
|
158
|
-
: Math.max(0, (
|
|
186
|
+
: Math.max(0, (height ?? 0) - 2 * this.borderWidth);
|
|
159
187
|
let contentWidth = 0;
|
|
160
188
|
let contentHeight = 0;
|
|
161
|
-
|
|
189
|
+
// Children are placed relative to this box's top-left, inside the border.
|
|
190
|
+
let yCursor = this.borderWidth;
|
|
162
191
|
for (const child of this.children) {
|
|
163
|
-
const consumed = yCursor -
|
|
192
|
+
const consumed = yCursor - this.borderWidth;
|
|
164
193
|
// Same rule the flex helper applies: a child gets a finite main extent when it cannot lay itself
|
|
165
194
|
// out without one - a stack holding an `Expanded`/`Spacer`, or a child sized as a percentage of us.
|
|
166
195
|
const needsBound = child.needsBoundedMain(false) || child.relativeSizeFactor(false) !== undefined;
|
|
167
196
|
const childHeight = needsBound
|
|
168
197
|
? Math.max(0, innerHeight - consumed) // Infinity - consumed stays Infinity, as it should
|
|
169
198
|
: Infinity;
|
|
170
|
-
const
|
|
199
|
+
const childConstraints = BoxConstraints.loose(innerWidth, childHeight);
|
|
200
|
+
const childSize = offset
|
|
201
|
+
? child.calculateLayout(childConstraints, { x: this.borderWidth, y: yCursor }, childCtx)
|
|
202
|
+
: child.measure(childConstraints, childCtx);
|
|
171
203
|
yCursor += childSize.height;
|
|
172
204
|
contentHeight += childSize.height;
|
|
173
205
|
contentWidth = Math.max(contentWidth, childSize.width);
|
|
@@ -175,32 +207,44 @@ export class RectangleElement extends SizedPDFElement {
|
|
|
175
207
|
// No explicit width and no bounded region: shrink-wrap to the widest child.
|
|
176
208
|
// Clamped, so a min/max still applies to a box that sized itself to its content.
|
|
177
209
|
if (shrinkWrapWidth)
|
|
178
|
-
|
|
210
|
+
width = bounds.constrainWidth(contentWidth + 2 * this.borderWidth);
|
|
179
211
|
// A ratio on a shrink-wrapping box can only be applied HERE: before the children were measured
|
|
180
212
|
// there was no width to derive the height from.
|
|
181
213
|
const ratio = this.sizeMemory.aspectRatio;
|
|
182
214
|
const ratioSizesHeight = ratio !== undefined && ratio > 0 && shrinkWrapWidth && shrinkWrapHeight;
|
|
183
215
|
// No explicit height and no bounded region: the border hugs its content.
|
|
184
216
|
if (ratioSizesHeight)
|
|
185
|
-
|
|
217
|
+
height = bounds.constrainHeight((width ?? 0) / ratio);
|
|
186
218
|
else if (shrinkWrapHeight)
|
|
187
|
-
|
|
188
|
-
|
|
219
|
+
height = bounds.constrainHeight(contentHeight + 2 * this.borderWidth);
|
|
220
|
+
if (offset) {
|
|
221
|
+
this.x = x;
|
|
222
|
+
this.y = y;
|
|
223
|
+
this.width = width;
|
|
224
|
+
this.height = height;
|
|
225
|
+
}
|
|
226
|
+
// The box is sized now: place its out-of-flow `Positioned` descendants, relative to its own
|
|
227
|
+
// top-left. Each is drawn at its own place in the tree (tree order).
|
|
189
228
|
if (frame) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
place(frame, ctx);
|
|
229
|
+
const box = { width: width ?? 0, height: height ?? 0 };
|
|
230
|
+
for (const p of positionedIn(this.children))
|
|
231
|
+
p.placeIn(box, childCtx);
|
|
194
232
|
}
|
|
195
233
|
// Border-box model: width/height ARE the outer box (the rect we draw); the content
|
|
196
234
|
// is inset by the border on every side. Report the honest box size - no phantom
|
|
197
235
|
// border added on (that asymmetric "+border" was the source of the magic-3 fudge in
|
|
198
236
|
// fragment). Top-left coordinates; the Y-flip happens at the IR -> backend seam.
|
|
199
237
|
return {
|
|
200
|
-
width:
|
|
201
|
-
height:
|
|
238
|
+
width: width ?? 0,
|
|
239
|
+
height: height ?? 0,
|
|
202
240
|
};
|
|
203
241
|
}
|
|
242
|
+
isPositioningFrame() {
|
|
243
|
+
return this.relative;
|
|
244
|
+
}
|
|
245
|
+
layoutChildren() {
|
|
246
|
+
return this.children ?? [];
|
|
247
|
+
}
|
|
204
248
|
getProps() {
|
|
205
249
|
return {
|
|
206
250
|
x: this.x,
|
|
@@ -214,6 +258,7 @@ export class RectangleElement extends SizedPDFElement {
|
|
|
214
258
|
radius: this.radius,
|
|
215
259
|
sideBorders: this.sideBorders,
|
|
216
260
|
overflow: this.overflow,
|
|
261
|
+
relative: this.relative,
|
|
217
262
|
};
|
|
218
263
|
}
|
|
219
264
|
}
|
|
@@ -68,6 +68,17 @@ export declare class RowElement extends SizedPDFElement {
|
|
|
68
68
|
/** A Row lays out side by side, so widths add up (gaps included) and heights overlap. */
|
|
69
69
|
minIntrinsicMain(horizontal: boolean, ctx: LayoutContext): number;
|
|
70
70
|
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
71
|
+
protected computeSize(constraints: BoxConstraints, ctx: LayoutContext): Size;
|
|
72
|
+
/** The first element inside this row that asks for a page break by flag, once found (or `null`). */
|
|
73
|
+
private declaredBreak?;
|
|
74
|
+
/**
|
|
75
|
+
* A row is one line: nothing inside it starts a new page. A `breakBefore` / `breakAfter` in a cell
|
|
76
|
+
* (a table row is a Row too) is therefore ignored - say so. A `PageBreak` reports itself.
|
|
77
|
+
*/
|
|
78
|
+
private reportIgnoredBreak;
|
|
79
|
+
/** The one sizing path: `layout` places the children (relative to this box), `measure` only sizes them. */
|
|
80
|
+
private sizeWith;
|
|
81
|
+
layoutChildren(): readonly PDFElement[];
|
|
71
82
|
getProps(): {
|
|
72
83
|
x: number;
|
|
73
84
|
y: number;
|