@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
@@ -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 page break (a `PageBreak`), not because the region filled up. The
16
- * remainder must start a fresh page, and an enclosing flow must stop packing too - so this bubbles
17
- * up through nested `fragment()` calls. Absent/false for an ordinary height-driven break. */
18
- forceBreak?: boolean;
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
- * True if packing `children` will hit a forced cut: a child that IS a break, contains one deeper in its
39
- * subtree, or asks to break before/after itself. A flow container reports this from `hasForcedBreak` so
40
- * its parent fragments it (runs `packChildren`) instead of placing it whole and swallowing the cut.
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: boolean;
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
- export function reportOverflow(child, childHeight, maxHeight, policy) {
14
- if (policy === "ignore")
15
- return;
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
- const detail = `${name} is ${Math.round(childHeight)}pt tall but the page region is only ` +
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
- console.warn(`Layout overflow (clipped): ${detail}`);
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 deeper in its
26
- * subtree, or asks to break before/after itself. A flow container reports this from `hasForcedBreak` so
27
- * its parent fragments it (runs `packChildren`) instead of placing it whole and swallowing the cut.
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.calculateLayout(BoxConstraints.loose(width, Infinity), { x: 0, y: 0 }, ctx).height;
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 && !child.hasForcedBreak()) {
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 split = child.fragment(Math.max(0, remaining), width, ctx);
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
- usedHeight += lead + childHeight;
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 (fitted.length === 0 && !childBroke) {
105
- // Taller than the whole region and unsplittable: force it on (it overflows and is clipped)
106
- // so the next region still advances - and surface it per the overflow policy.
107
- reportOverflow(child, childHeight, maxHeight, ctx.onOverflow ?? "ignore");
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(_path: string): Uint8Array;
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
- const hint = "needs Node. In the browser pass bytes (Uint8Array / ArrayBuffer) instead - e.g. import the file as a URL and fetch() it, or register a font from its bytes.";
4
- export function readFileBytes(_path) {
5
- throw new Error(`Loading a font from a file path ${hint}`);
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
  }
@@ -1,2 +1 @@
1
1
  export declare function readFileBytes(path: string): Uint8Array;
2
- export declare function readFileBytesAsync(path: string): Promise<Uint8Array>;
@@ -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
- const renderer = RendererRegistry.getRenderer(child);
6
- const childNodes = await renderer(child, objectManager);
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
- const renderer = RendererRegistry.getRenderer(child);
6
- const childNodes = await renderer(child, objectManager);
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
- const renderer = RendererRegistry.getRenderer(child);
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
- const renderer = RendererRegistry.getRenderer(child);
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
- const renderer = RendererRegistry.getRenderer(composed);
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
- const renderer = RendererRegistry.getRenderer(child);
6
- return renderer(child, objectManager);
5
+ return RendererRegistry.render(child, objectManager, scope);
7
6
  }
8
7
  }