@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.
Files changed (246) hide show
  1. package/dist/api/color.d.ts +1 -24
  2. package/dist/api/color.js +2 -278
  3. package/dist/api/content.d.ts +10 -5
  4. package/dist/api/content.js +29 -13
  5. package/dist/api/descriptor.js +30 -3
  6. package/dist/api/flow.d.ts +55 -0
  7. package/dist/api/flow.js +71 -0
  8. package/dist/api/font-url.d.ts +1 -2
  9. package/dist/api/font-url.js +8 -74
  10. package/dist/api/forms.d.ts +3 -0
  11. package/dist/api/forms.js +3 -0
  12. package/dist/api/gradient.d.ts +1 -53
  13. package/dist/api/gradient.js +2 -97
  14. package/dist/api/index.d.ts +4 -0
  15. package/dist/api/index.js +3 -0
  16. package/dist/api/layout.d.ts +6 -0
  17. package/dist/api/layout.js +9 -3
  18. package/dist/api/page-builder.d.ts +4 -0
  19. package/dist/api/page-builder.js +4 -0
  20. package/dist/api/structure.d.ts +10 -2
  21. package/dist/api/structure.js +9 -6
  22. package/dist/api/table.d.ts +5 -3
  23. package/dist/api/table.js +101 -22
  24. package/dist/api/text.d.ts +8 -8
  25. package/dist/api/text.js +6 -0
  26. package/dist/canvas/painter.d.ts +2 -2
  27. package/dist/canvas/painter.js +2 -2
  28. package/dist/common/color-input.d.ts +24 -0
  29. package/dist/common/color-input.js +278 -0
  30. package/dist/common/diagnostics.d.ts +61 -0
  31. package/dist/common/diagnostics.js +77 -0
  32. package/dist/common/gradient.d.ts +53 -0
  33. package/dist/common/gradient.js +97 -0
  34. package/dist/edit/acroform-reader.js +7 -7
  35. package/dist/edit/appearance.js +3 -3
  36. package/dist/edit/attachments.d.ts +52 -0
  37. package/dist/edit/attachments.js +178 -0
  38. package/dist/edit/document.d.ts +38 -8
  39. package/dist/edit/document.js +208 -51
  40. package/dist/edit/fill.js +8 -23
  41. package/dist/edit/filters.d.ts +15 -0
  42. package/dist/edit/filters.js +157 -0
  43. package/dist/edit/index.d.ts +4 -1
  44. package/dist/edit/index.js +3 -1
  45. package/dist/edit/objects.d.ts +3 -4
  46. package/dist/edit/objects.js +5 -18
  47. package/dist/elements/canvas-element.d.ts +3 -0
  48. package/dist/elements/canvas-element.js +14 -3
  49. package/dist/elements/container-element.d.ts +8 -1
  50. package/dist/elements/container-element.js +49 -17
  51. package/dist/elements/forms/checkbox-element.d.ts +2 -0
  52. package/dist/elements/forms/checkbox-element.js +12 -3
  53. package/dist/elements/forms/choice-element.d.ts +6 -1
  54. package/dist/elements/forms/choice-element.js +17 -6
  55. package/dist/elements/forms/field-font.d.ts +8 -0
  56. package/dist/elements/forms/field-font.js +5 -0
  57. package/dist/elements/forms/push-button-element.d.ts +6 -1
  58. package/dist/elements/forms/push-button-element.js +16 -4
  59. package/dist/elements/forms/radio-element.d.ts +2 -0
  60. package/dist/elements/forms/radio-element.js +12 -3
  61. package/dist/elements/forms/signature-element.d.ts +6 -1
  62. package/dist/elements/forms/signature-element.js +16 -4
  63. package/dist/elements/forms/text-field-element.d.ts +6 -1
  64. package/dist/elements/forms/text-field-element.js +16 -4
  65. package/dist/elements/image-element.d.ts +70 -21
  66. package/dist/elements/image-element.js +173 -52
  67. package/dist/elements/index.d.ts +3 -0
  68. package/dist/elements/index.js +3 -0
  69. package/dist/elements/layout/anchor-element.d.ts +8 -10
  70. package/dist/elements/layout/anchor-element.js +10 -18
  71. package/dist/elements/layout/bookmark-element.d.ts +9 -11
  72. package/dist/elements/layout/bookmark-element.js +11 -20
  73. package/dist/elements/layout/column-break-element.d.ts +17 -0
  74. package/dist/elements/layout/column-break-element.js +26 -0
  75. package/dist/elements/layout/default-text-style-element.d.ts +11 -13
  76. package/dist/elements/layout/default-text-style-element.js +14 -31
  77. package/dist/elements/layout/deferred-element.d.ts +20 -4
  78. package/dist/elements/layout/deferred-element.js +41 -9
  79. package/dist/elements/layout/expanded-element.d.ts +11 -0
  80. package/dist/elements/layout/expanded-element.js +53 -18
  81. package/dist/elements/layout/flow-element.d.ts +109 -0
  82. package/dist/elements/layout/flow-element.js +317 -0
  83. package/dist/elements/layout/keep-together-element.d.ts +8 -18
  84. package/dist/elements/layout/keep-together-element.js +33 -45
  85. package/dist/elements/layout/link-element.d.ts +8 -13
  86. package/dist/elements/layout/link-element.js +9 -19
  87. package/dist/elements/layout/padding-element.d.ts +18 -1
  88. package/dist/elements/layout/padding-element.js +63 -28
  89. package/dist/elements/layout/page-break-element.d.ts +4 -1
  90. package/dist/elements/layout/page-break-element.js +6 -1
  91. package/dist/elements/layout/page-builder-element.d.ts +5 -0
  92. package/dist/elements/layout/page-builder-element.js +13 -2
  93. package/dist/elements/layout/positioned-element.d.ts +23 -4
  94. package/dist/elements/layout/positioned-element.js +42 -12
  95. package/dist/elements/layout/proxy-element.d.ts +47 -0
  96. package/dist/elements/layout/proxy-element.js +106 -0
  97. package/dist/elements/layout/region-element.d.ts +53 -0
  98. package/dist/elements/layout/region-element.js +108 -0
  99. package/dist/elements/layout/repeating-header-element.d.ts +9 -0
  100. package/dist/elements/layout/repeating-header-element.js +55 -13
  101. package/dist/elements/layout/rotated-box-element.d.ts +6 -0
  102. package/dist/elements/layout/rotated-box-element.js +27 -14
  103. package/dist/elements/layout/rotated-element.d.ts +9 -0
  104. package/dist/elements/layout/rotated-element.js +33 -2
  105. package/dist/elements/layout/struct-group.d.ts +9 -17
  106. package/dist/elements/layout/struct-group.js +10 -35
  107. package/dist/elements/line-element.d.ts +1 -0
  108. package/dist/elements/line-element.js +6 -0
  109. package/dist/elements/page-element.d.ts +10 -3
  110. package/dist/elements/page-element.js +39 -31
  111. package/dist/elements/pdf-document-element.d.ts +3 -0
  112. package/dist/elements/pdf-document-element.js +7 -0
  113. package/dist/elements/pdf-element.d.ts +105 -16
  114. package/dist/elements/pdf-element.js +118 -19
  115. package/dist/elements/rectangle-element.d.ts +22 -2
  116. package/dist/elements/rectangle-element.js +119 -55
  117. package/dist/elements/row-element.d.ts +17 -12
  118. package/dist/elements/row-element.js +89 -9
  119. package/dist/elements/svg-element.d.ts +30 -6
  120. package/dist/elements/svg-element.js +91 -26
  121. package/dist/elements/text-element.d.ts +48 -13
  122. package/dist/elements/text-element.js +161 -116
  123. package/dist/forms/acroform.d.ts +9 -1
  124. package/dist/forms/acroform.js +83 -34
  125. package/dist/forms/appearance.d.ts +17 -6
  126. package/dist/forms/appearance.js +18 -16
  127. package/dist/ir/display-list.d.ts +18 -3
  128. package/dist/layout/box-constraints.d.ts +17 -0
  129. package/dist/layout/box-constraints.js +31 -0
  130. package/dist/layout/collect-images.d.ts +6 -4
  131. package/dist/layout/collect-images.js +14 -8
  132. package/dist/layout/flex-item.d.ts +11 -0
  133. package/dist/layout/flex-item.js +51 -0
  134. package/dist/layout/fragmentation.d.ts +23 -9
  135. package/dist/layout/fragmentation.js +62 -19
  136. package/dist/layout/layout-cache.d.ts +53 -0
  137. package/dist/layout/layout-cache.js +110 -0
  138. package/dist/platform/browser-fs.d.ts +1 -2
  139. package/dist/platform/browser-fs.js +3 -6
  140. package/dist/platform/node-fs.d.ts +0 -1
  141. package/dist/platform/node-fs.js +0 -4
  142. package/dist/renderer/anchor-renderer.d.ts +2 -1
  143. package/dist/renderer/anchor-renderer.js +5 -4
  144. package/dist/renderer/bookmark-renderer.d.ts +2 -1
  145. package/dist/renderer/bookmark-renderer.js +5 -4
  146. package/dist/renderer/canvas-renderer.d.ts +2 -1
  147. package/dist/renderer/canvas-renderer.js +5 -2
  148. package/dist/renderer/column-break-renderer.d.ts +8 -0
  149. package/dist/renderer/column-break-renderer.js +15 -0
  150. package/dist/renderer/container-renderer.d.ts +2 -1
  151. package/dist/renderer/container-renderer.js +6 -5
  152. package/dist/renderer/default-text-style-renderer.d.ts +2 -1
  153. package/dist/renderer/default-text-style-renderer.js +2 -3
  154. package/dist/renderer/deferred-renderer.d.ts +2 -1
  155. package/dist/renderer/deferred-renderer.js +2 -3
  156. package/dist/renderer/emoji-image.js +3 -1
  157. package/dist/renderer/expanded-renderer.d.ts +2 -1
  158. package/dist/renderer/expanded-renderer.js +2 -3
  159. package/dist/renderer/flow-renderer.d.ts +16 -0
  160. package/dist/renderer/flow-renderer.js +21 -0
  161. package/dist/renderer/form-field-renderer.d.ts +2 -1
  162. package/dist/renderer/form-field-renderer.js +16 -3
  163. package/dist/renderer/image-renderer.d.ts +2 -1
  164. package/dist/renderer/image-renderer.js +33 -53
  165. package/dist/renderer/index.d.ts +2 -0
  166. package/dist/renderer/index.js +2 -0
  167. package/dist/renderer/keep-together-renderer.d.ts +2 -1
  168. package/dist/renderer/keep-together-renderer.js +2 -3
  169. package/dist/renderer/line-renderer.d.ts +2 -1
  170. package/dist/renderer/line-renderer.js +7 -2
  171. package/dist/renderer/link-renderer.d.ts +2 -1
  172. package/dist/renderer/link-renderer.js +36 -5
  173. package/dist/renderer/padding-renderer.d.ts +2 -1
  174. package/dist/renderer/padding-renderer.js +5 -5
  175. package/dist/renderer/page-break-renderer.d.ts +6 -5
  176. package/dist/renderer/page-break-renderer.js +14 -7
  177. package/dist/renderer/page-builder-renderer.d.ts +2 -1
  178. package/dist/renderer/page-builder-renderer.js +2 -3
  179. package/dist/renderer/page-renderer.js +30 -10
  180. package/dist/renderer/pdf-backend.d.ts +4 -3
  181. package/dist/renderer/pdf-backend.js +14 -7
  182. package/dist/renderer/pdf-document-renderer.d.ts +1 -8
  183. package/dist/renderer/pdf-document-renderer.js +17 -17
  184. package/dist/renderer/pdf-renderer.js +20 -11
  185. package/dist/renderer/positioned-renderer.d.ts +18 -1
  186. package/dist/renderer/positioned-renderer.js +43 -6
  187. package/dist/renderer/rectangle-renderer.d.ts +2 -1
  188. package/dist/renderer/rectangle-renderer.js +18 -8
  189. package/dist/renderer/repeating-header-renderer.d.ts +2 -1
  190. package/dist/renderer/repeating-header-renderer.js +6 -5
  191. package/dist/renderer/rotated-renderer.d.ts +2 -1
  192. package/dist/renderer/rotated-renderer.js +9 -5
  193. package/dist/renderer/row-renderer.d.ts +2 -1
  194. package/dist/renderer/row-renderer.js +6 -5
  195. package/dist/renderer/struct-group-renderer.d.ts +2 -1
  196. package/dist/renderer/struct-group-renderer.js +2 -3
  197. package/dist/renderer/svg-renderer.d.ts +2 -1
  198. package/dist/renderer/svg-renderer.js +8 -2
  199. package/dist/renderer/text-renderer.d.ts +4 -6
  200. package/dist/renderer/text-renderer.js +114 -127
  201. package/dist/svg/gradients.js +5 -0
  202. package/dist/svg/index.d.ts +1 -1
  203. package/dist/svg/index.js +36 -6
  204. package/dist/svg/style.d.ts +2 -0
  205. package/dist/svg/style.js +12 -1
  206. package/dist/text/advance.d.ts +4 -0
  207. package/dist/text/advance.js +17 -4
  208. package/dist/text/bidi.d.ts +0 -2
  209. package/dist/text/bidi.js +0 -10
  210. package/dist/text/glyph-coverage.d.ts +1 -1
  211. package/dist/text/glyph-coverage.js +7 -3
  212. package/dist/text/hyphen-breaks.d.ts +17 -0
  213. package/dist/text/hyphen-breaks.js +54 -0
  214. package/dist/text/line-breaker.d.ts +55 -29
  215. package/dist/text/line-breaker.js +453 -188
  216. package/dist/text/line-metrics.d.ts +8 -3
  217. package/dist/text/line-metrics.js +11 -2
  218. package/dist/text/pdf-text-string.d.ts +21 -0
  219. package/dist/text/pdf-text-string.js +114 -0
  220. package/dist/text/text-decoration.d.ts +5 -5
  221. package/dist/text/text-decoration.js +5 -5
  222. package/dist/text/word-splitting.d.ts +15 -2
  223. package/dist/text/word-splitting.js +45 -13
  224. package/dist/utils/afm-parser.d.ts +2 -0
  225. package/dist/utils/afm-parser.js +10 -1
  226. package/dist/utils/dest-registry.d.ts +1 -1
  227. package/dist/utils/dest-registry.js +3 -2
  228. package/dist/utils/fetch-bytes.d.ts +19 -0
  229. package/dist/utils/fetch-bytes.js +79 -0
  230. package/dist/utils/flex-layout.d.ts +16 -14
  231. package/dist/utils/flex-layout.js +427 -217
  232. package/dist/utils/font-metrics.d.ts +4 -3
  233. package/dist/utils/image-helper.d.ts +59 -11
  234. package/dist/utils/image-helper.js +209 -81
  235. package/dist/utils/pdf-object-manager.d.ts +17 -6
  236. package/dist/utils/pdf-object-manager.js +70 -20
  237. package/dist/utils/renderer-registry.d.ts +49 -2
  238. package/dist/utils/renderer-registry.js +40 -0
  239. package/dist/utils/struct-tree.d.ts +24 -0
  240. package/dist/utils/struct-tree.js +61 -9
  241. package/dist/utils/ttf-parser.d.ts +4 -0
  242. package/dist/utils/ttf-parser.js +30 -6
  243. package/dist/validators/element-validator.js +2 -1
  244. package/package.json +1 -1
  245. package/dist/elements/layout/sized-container-element.d.ts +0 -14
  246. package/dist/elements/layout/sized-container-element.js +0 -32
@@ -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
- * offsets against. A `relative` Box (later the page) creates one and threads it to its subtree;
16
- * `Positioned` descendants register a placement closure in `place`, which the frame drains once it
17
- * has finished sizing itself (so `right`/`bottom` can resolve against the final box).
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,104 @@ 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 FULL body height of the current page (between header and footer), set by the page driver. A
66
- * `keepTogether` group reads it to decide the degrade rule: veto splitting only when the group would
67
- * fit on a fresh page; a group taller than a whole page drops the veto and splits. */
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
+ /** Packing into a Region of a `Flow`, where a `ColumnBreak` moves on to the next Region. */
78
+ inFlowRegion?: boolean;
79
+ /** Laying out a page of a `Flow`'s template: the page a `Region` laid out here belongs to. */
80
+ flowPage?: object;
81
+ /** What a `Box`'s percentage padding resolves against (CSS: the containing block). A Row sets it for
82
+ * its children - it offers them no width, so the Box could not know it; otherwise the Box sets it
83
+ * from what it was offered. Consumed by the Box's own padding, so it never travels further down. */
84
+ boxPaddingBase?: number;
69
85
  }
86
+ /** `ctx` with `boxPaddingBase` set to `base` - the same object when nothing changes. */
87
+ export declare function withPaddingBase(ctx: LayoutContext, base: number | undefined): LayoutContext;
70
88
  export declare abstract class PDFElement {
71
89
  private _structId;
72
90
  get structId(): number;
73
91
  /** Make this element share `from`'s tagging identity - used by fragmentation clones. Returns this. */
74
92
  adoptStructId(from: PDFElement): this;
93
+ /**
94
+ * Marks this element as a piece of `original`, split across pages: it is the same element to a
95
+ * reader of the tagged PDF (one structure element) and to the Row or Column it sits in (its flex
96
+ * properties). Every fragmentation clone ends in this call, so a property added to the base is
97
+ * carried in ONE place. Returns this.
98
+ */
99
+ asPieceOf(original: PDFElement): this;
100
+ /** Takes the flex properties `original` set (CSS `align-self`, `order`, `flex-shrink`). Returns this. */
101
+ takeFlexItemFrom(original: PDFElement): this;
75
102
  abstract getProps(): unknown;
76
103
  /**
77
104
  * Lays the element out: `constraints` bound its size (flows DOWN), `offset` is the
78
- * absolute top-left position the parent assigns it, and the returned `Size` is the
105
+ * top-left position the parent assigns it, relative to the parent's own top-left (absolute
106
+ * coordinates exist only in the render pass), and the returned `Size` is the
79
107
  * space it actually took (flows UP). Layout works in a top-left origin; the Y-flip
80
108
  * happens once at the IR -> backend seam.
81
109
  */
82
110
  abstract calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
111
+ /**
112
+ * The size `calculateLayout` would return under these constraints - with NO side effects: no
113
+ * position, no stored size, nothing registered with a frame. A parent asks this to decide, and lays
114
+ * a child out once afterwards; asking with a full layout doubled the work at every nesting level.
115
+ * Do not override it - implement `computeSize` (as Flutter's `getDryLayout` / `computeDryLayout`).
116
+ * The same question twice is answered from the layout cache (`layout/layout-cache.ts`).
117
+ */
118
+ measure(constraints: BoxConstraints, ctx: LayoutContext): Size;
119
+ /**
120
+ * The part of the constraints this element's size actually reads - what the layout cache keys on.
121
+ * All of it by default. An element whose size ignores a bound returns it opened up, so two questions
122
+ * that differ only there share one answer. It must be TRUE for `computeSize`: reading a bound that
123
+ * is dropped here makes the cache hand back a wrong size.
124
+ */
125
+ protected sizeInputs(constraints: BoxConstraints): BoxConstraints;
126
+ private sizeCache?;
127
+ /**
128
+ * Whether this element's size can depend on the page it lands on (`pageConfig`, `pageInfo`): a
129
+ * `PageBuilder`, a `Page`, and everything holding one. Only those key a cached size on the page, so
130
+ * every other size is reused across pages and across the pagination and render passes. Remembered:
131
+ * the tree does not change, and an answer that was `false` can never become `true`.
132
+ */
133
+ dependsOnPage(): boolean;
134
+ private pageDependent?;
135
+ /**
136
+ * How this element sizes itself for `measure`. It must come from the SAME sizing computation as
137
+ * `calculateLayout`, or a measured size and a laid-out one can differ.
138
+ */
139
+ protected abstract computeSize(constraints: BoxConstraints, ctx: LayoutContext): Size;
140
+ /**
141
+ * A copy of this element and of every element it holds, as it was built - to place one element
142
+ * twice, which a single instance cannot (it has one position). Everything else stays shared: an
143
+ * image's pixels, a callback. The copy tags as an element of its own.
144
+ */
145
+ clone(): this;
146
+ /** The elements this one lays out, for walks that must see the whole tree. Leaves have none. */
147
+ layoutChildren(): readonly PDFElement[];
148
+ /**
149
+ * The element this one is transparent for, if any: a `ProxyElement` returns its child. A surrounding
150
+ * Row or Column looks through it for the flex item (`layout/flex-item.ts`).
151
+ */
152
+ proxied(): PDFElement | undefined;
153
+ /** The context the element `proxied()` names is laid out in: this one's, unless it hands something
154
+ * down (a `DefaultTextStyle`). */
155
+ proxiedContext(ctx: LayoutContext): LayoutContext;
156
+ /** A `Box` with percentage padding: a surrounding Row tells it its own width (`boxPaddingBase`). */
157
+ hasPercentPadding(): boolean;
158
+ /** Lays out its own `Positioned` descendants (a page, a `relative` Box); a walk for them stops here. */
159
+ isPositioningFrame(): boolean;
83
160
  /**
84
161
  * The relative-size fraction (0..1) this element asked for on the given axis, if any (`horizontal` =
85
162
  * width). A flex parent reads it to resolve a percentage child against its OWN main size - e.g. a
@@ -87,6 +164,9 @@ export declare abstract class PDFElement {
87
164
  * fraction would have nothing to resolve against. Default: the element is not relatively sized.
88
165
  */
89
166
  relativeSizeFactor(_horizontal: boolean): number | undefined;
167
+ /** The most this element may be on an axis in points (its `maxWidth`/`maxHeight`): a flex line freezes
168
+ * a flex child there. A percentage max resolves against what the child is given, so it is not one. */
169
+ maxExtent(_horizontal: boolean): number;
90
170
  /**
91
171
  * Whether this element needs a BOUNDED extent on the given axis to lay itself out (`true` for a
92
172
  * horizontal axis = width). A flex parent measures its fixed children with an unbounded main axis, so
@@ -106,15 +186,23 @@ export declare abstract class PDFElement {
106
186
  * override it; containers recurse, since a Row is only as unsqueezable as its children.
107
187
  */
108
188
  minIntrinsicMain(_horizontal: boolean, _ctx: LayoutContext): number;
189
+ /**
190
+ * Whether this element takes its height from the REGION it is fragmented into (a `Flow`), anywhere
191
+ * in a subtree that has no height of its own. Such an element has no natural height to measure, so
192
+ * the packer fragments it into the space left instead of placing it whole. Default: no.
193
+ */
194
+ needsRegion(): boolean;
109
195
  /**
110
196
  * Whether this element IS a forced page break (a `PageBreak`). The pagination packer cuts the flow
111
197
  * at such a marker: everything before it stays, everything after starts a new page. Default: no.
112
198
  */
113
199
  isPageBreak(): boolean;
200
+ /** Whether this element IS a `ColumnBreak`: the packer of a Flow's Region cuts there. Default: no. */
201
+ isColumnBreak(): boolean;
114
202
  /**
115
203
  * Whether this element is, or CONTAINS anywhere in its subtree, a forced page break. A container
116
204
  * that merely fits by height must still be fragmented when this is true, so a break nested inside
117
- * it is honoured rather than swallowed. Containers override this to recurse into their children.
205
+ * it is honored rather than swallowed. Containers override this to recurse into their children.
118
206
  * Default: no.
119
207
  */
120
208
  hasForcedBreak(): boolean;
@@ -141,9 +229,9 @@ export declare abstract class PDFElement {
141
229
  /**
142
230
  * Where this child sits among its siblings (CSS `order`), lowest first, source order deciding ties.
143
231
  * It moves the child in the LAYOUT only - the element tree, and therefore the reading order a tagged
144
- * PDF exposes, is untouched. Default 0.
232
+ * PDF exposes, is untouched. Unset means 0; a stack reads it through `layout/flex-item.ts`.
145
233
  */
146
- order: number;
234
+ order?: number;
147
235
  /**
148
236
  * How willingly this child gives up main-axis space when the line overflows (CSS `flex-shrink`),
149
237
  * weighted by its own size as CSS does. Default 1, as in CSS: an overflowing line squeezes its
@@ -154,8 +242,9 @@ export declare abstract class PDFElement {
154
242
  * caution outlived its use: four of the gallery cases turned out to be overflowing their page
155
243
  * margin without anyone noticing, because nothing ever pulled them back. Shrinking is bounded from
156
244
  * below by `minIntrinsicMain`, so a child is never squeezed past what it can actually hold.
245
+ * Unset means 1; a stack reads it through `layout/flex-item.ts`.
157
246
  */
158
- flexShrink: number;
247
+ flexShrink?: number;
159
248
  /** Sets `flexShrink` and returns the element. */
160
249
  withFlexShrink(shrink: number | undefined): this;
161
250
  /** Sets `order` and returns the element, so a factory can thread it through in one expression. */
@@ -1,3 +1,8 @@
1
+ import { SizeCache } from "../layout/layout-cache.js";
2
+ /** `ctx` with `boxPaddingBase` set to `base` - the same object when nothing changes. */
3
+ export function withPaddingBase(ctx, base) {
4
+ return ctx.boxPaddingBase === base ? ctx : { ...ctx, boxPaddingBase: base };
5
+ }
1
6
  let _nextStructId = 0;
2
7
  export class PDFElement {
3
8
  constructor() {
@@ -5,24 +10,6 @@ export class PDFElement {
5
10
  // fragmentation copies (adoptStructId), so a paragraph or table split across pages stays ONE structure
6
11
  // element. Only the elements that actually tag (Text, Image, StructGroup) read it.
7
12
  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
13
  }
27
14
  get structId() {
28
15
  return this._structId;
@@ -32,6 +19,101 @@ export class PDFElement {
32
19
  this._structId = from._structId;
33
20
  return this;
34
21
  }
22
+ /**
23
+ * Marks this element as a piece of `original`, split across pages: it is the same element to a
24
+ * reader of the tagged PDF (one structure element) and to the Row or Column it sits in (its flex
25
+ * properties). Every fragmentation clone ends in this call, so a property added to the base is
26
+ * carried in ONE place. Returns this.
27
+ */
28
+ asPieceOf(original) {
29
+ return this.adoptStructId(original).takeFlexItemFrom(original);
30
+ }
31
+ /** Takes the flex properties `original` set (CSS `align-self`, `order`, `flex-shrink`). Returns this. */
32
+ takeFlexItemFrom(original) {
33
+ this.alignSelf = original.alignSelf ?? this.alignSelf;
34
+ this.order = original.order ?? this.order;
35
+ this.flexShrink = original.flexShrink ?? this.flexShrink;
36
+ return this;
37
+ }
38
+ /**
39
+ * The size `calculateLayout` would return under these constraints - with NO side effects: no
40
+ * position, no stored size, nothing registered with a frame. A parent asks this to decide, and lays
41
+ * a child out once afterwards; asking with a full layout doubled the work at every nesting level.
42
+ * Do not override it - implement `computeSize` (as Flutter's `getDryLayout` / `computeDryLayout`).
43
+ * The same question twice is answered from the layout cache (`layout/layout-cache.ts`).
44
+ */
45
+ measure(constraints, ctx) {
46
+ const cache = (this.sizeCache ?? (this.sizeCache = new SizeCache()));
47
+ const asked = this.sizeInputs(constraints);
48
+ const onPage = this.dependsOnPage();
49
+ const known = cache.get(asked, ctx, onPage);
50
+ if (known)
51
+ return known;
52
+ const size = this.computeSize(constraints, ctx);
53
+ cache.set(asked, ctx, onPage, size);
54
+ return size;
55
+ }
56
+ /**
57
+ * The part of the constraints this element's size actually reads - what the layout cache keys on.
58
+ * All of it by default. An element whose size ignores a bound returns it opened up, so two questions
59
+ * that differ only there share one answer. It must be TRUE for `computeSize`: reading a bound that
60
+ * is dropped here makes the cache hand back a wrong size.
61
+ */
62
+ sizeInputs(constraints) {
63
+ return constraints;
64
+ }
65
+ /**
66
+ * Whether this element's size can depend on the page it lands on (`pageConfig`, `pageInfo`): a
67
+ * `PageBuilder`, a `Page`, and everything holding one. Only those key a cached size on the page, so
68
+ * every other size is reused across pages and across the pagination and render passes. Remembered:
69
+ * the tree does not change, and an answer that was `false` can never become `true`.
70
+ */
71
+ dependsOnPage() {
72
+ return (this.pageDependent ?? (this.pageDependent = this.layoutChildren().some((child) => child.dependsOnPage())));
73
+ }
74
+ /**
75
+ * A copy of this element and of every element it holds, as it was built - to place one element
76
+ * twice, which a single instance cannot (it has one position). Everything else stays shared: an
77
+ * image's pixels, a callback. The copy tags as an element of its own.
78
+ */
79
+ clone() {
80
+ const copyOf = (value) => value instanceof PDFElement
81
+ ? value.clone()
82
+ : Array.isArray(value)
83
+ ? value.map(copyOf)
84
+ : value;
85
+ const copy = Object.create(Object.getPrototypeOf(this));
86
+ for (const [key, value] of Object.entries(this)) {
87
+ copy[key] = copyOf(value);
88
+ }
89
+ copy.sizeCache = undefined;
90
+ copy._structId = _nextStructId++;
91
+ return copy;
92
+ }
93
+ /** The elements this one lays out, for walks that must see the whole tree. Leaves have none. */
94
+ layoutChildren() {
95
+ return [];
96
+ }
97
+ /**
98
+ * The element this one is transparent for, if any: a `ProxyElement` returns its child. A surrounding
99
+ * Row or Column looks through it for the flex item (`layout/flex-item.ts`).
100
+ */
101
+ proxied() {
102
+ return undefined;
103
+ }
104
+ /** The context the element `proxied()` names is laid out in: this one's, unless it hands something
105
+ * down (a `DefaultTextStyle`). */
106
+ proxiedContext(ctx) {
107
+ return ctx;
108
+ }
109
+ /** A `Box` with percentage padding: a surrounding Row tells it its own width (`boxPaddingBase`). */
110
+ hasPercentPadding() {
111
+ return false;
112
+ }
113
+ /** Lays out its own `Positioned` descendants (a page, a `relative` Box); a walk for them stops here. */
114
+ isPositioningFrame() {
115
+ return false;
116
+ }
35
117
  /**
36
118
  * The relative-size fraction (0..1) this element asked for on the given axis, if any (`horizontal` =
37
119
  * width). A flex parent reads it to resolve a percentage child against its OWN main size - e.g. a
@@ -41,6 +123,11 @@ export class PDFElement {
41
123
  relativeSizeFactor(_horizontal) {
42
124
  return undefined;
43
125
  }
126
+ /** The most this element may be on an axis in points (its `maxWidth`/`maxHeight`): a flex line freezes
127
+ * a flex child there. A percentage max resolves against what the child is given, so it is not one. */
128
+ maxExtent(_horizontal) {
129
+ return Infinity;
130
+ }
44
131
  /**
45
132
  * Whether this element needs a BOUNDED extent on the given axis to lay itself out (`true` for a
46
133
  * horizontal axis = width). A flex parent measures its fixed children with an unbounded main axis, so
@@ -64,6 +151,14 @@ export class PDFElement {
64
151
  minIntrinsicMain(_horizontal, _ctx) {
65
152
  return 0;
66
153
  }
154
+ /**
155
+ * Whether this element takes its height from the REGION it is fragmented into (a `Flow`), anywhere
156
+ * in a subtree that has no height of its own. Such an element has no natural height to measure, so
157
+ * the packer fragments it into the space left instead of placing it whole. Default: no.
158
+ */
159
+ needsRegion() {
160
+ return false;
161
+ }
67
162
  /**
68
163
  * Whether this element IS a forced page break (a `PageBreak`). The pagination packer cuts the flow
69
164
  * at such a marker: everything before it stays, everything after starts a new page. Default: no.
@@ -71,10 +166,14 @@ export class PDFElement {
71
166
  isPageBreak() {
72
167
  return false;
73
168
  }
169
+ /** Whether this element IS a `ColumnBreak`: the packer of a Flow's Region cuts there. Default: no. */
170
+ isColumnBreak() {
171
+ return false;
172
+ }
74
173
  /**
75
174
  * Whether this element is, or CONTAINS anywhere in its subtree, a forced page break. A container
76
175
  * that merely fits by height must still be fragmented when this is true, so a break nested inside
77
- * it is honoured rather than swallowed. Containers override this to recurse into their children.
176
+ * it is honored rather than swallowed. Containers override this to recurse into their children.
78
177
  * Default: no.
79
178
  */
80
179
  hasForcedBreak() {
@@ -1,5 +1,5 @@
1
1
  import type { Radii } from "../ir/display-list.js";
2
- import type { GradientInput } from "../api/gradient.js";
2
+ import type { GradientInput } from "../common/gradient.js";
3
3
  import { Color } from "../common/color.js";
4
4
  import { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
5
5
  import { Fragmentable, FragmentResult } from "../layout/fragmentation.js";
@@ -14,7 +14,7 @@ export interface SideBorders {
14
14
  }
15
15
  interface RectangleElementParams extends SizedElement, WithChildren {
16
16
  color?: Color;
17
- /** Solid colour, or a box-relative gradient the renderer resolves against this box. */
17
+ /** Solid color, or a box-relative gradient the renderer resolves against this box. */
18
18
  backgroundColor?: Color | GradientInput;
19
19
  borderWidth?: number;
20
20
  /** Corner radius in points - one number for all four corners, or per corner. 0 = sharp (default). */
@@ -74,13 +74,32 @@ export declare class RectangleElement extends SizedPDFElement implements Fragmen
74
74
  hasForcedBreak(): boolean;
75
75
  private cloneWithChildren;
76
76
  relativeSizeFactor(horizontal: boolean): number | undefined;
77
+ maxExtent(horizontal: boolean): number;
77
78
  /** A box has no flex children of its own, but it must not swallow the need of the stack inside it: a
78
79
  * `Spacer` in a box can only resolve if the box itself was given a bounded extent to pass down. With an
79
80
  * explicit size on an axis the box already knows its extent there and asks for nothing. */
80
81
  needsBoundedMain(horizontal: boolean): boolean;
82
+ /** As a Column: a height of its own is the region; without one, a region-sized child needs the page's. */
83
+ needsRegion(): boolean;
84
+ /** A Box's own padding resolves a percentage against its containing block, not against the inner
85
+ * width it hands its children - so it is told: the base a surrounding Row set, else what the Box was
86
+ * offered. Neither (an unbounded offer outside a Row) leaves the Box's own width. */
87
+ private paddingContext;
88
+ hasPercentPadding(): boolean;
81
89
  /** A Box stacks its children vertically inside its border, which is on both sides of the axis. */
82
90
  minIntrinsicMain(horizontal: boolean, ctx: LayoutContext): number;
83
91
  calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
92
+ protected computeSize(constraints: BoxConstraints, ctx: LayoutContext): Size;
93
+ /**
94
+ * The one sizing path. With an `offset` it lays the children out and keeps its geometry; with
95
+ * `null` it only measures - no field written, no child placed, no frame drained.
96
+ */
97
+ private sizeWith;
98
+ isPositioningFrame(): boolean;
99
+ /** Sorts the `zIndex` of the `Positioned` below it: a frame does, and so does a clip - what it crops
100
+ * stays cropped, whatever its `zIndex`. */
101
+ isStackingContext(): boolean;
102
+ layoutChildren(): readonly PDFElement[];
84
103
  getProps(): {
85
104
  x: number;
86
105
  y: number;
@@ -93,6 +112,7 @@ export declare class RectangleElement extends SizedPDFElement implements Fragmen
93
112
  radius: number | Radii;
94
113
  sideBorders: SideBorders | undefined;
95
114
  overflow: "hidden" | "visible";
115
+ relative: boolean;
96
116
  };
97
117
  }
98
118
  export {};