@jasy/pdf 1.0.0-alpha.1 → 1.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/api/args.d.ts +1 -1
- package/dist/api/args.js +2 -5
- package/dist/api/color.d.ts +4 -4
- package/dist/api/color.js +11 -17
- package/dist/api/content.d.ts +8 -8
- package/dist/api/content.js +23 -24
- package/dist/api/descriptor.d.ts +2 -2
- package/dist/api/descriptor.js +75 -31
- package/dist/api/index.d.ts +8 -8
- package/dist/api/index.js +8 -24
- package/dist/api/insets.js +4 -8
- package/dist/api/layout.d.ts +27 -12
- package/dist/api/layout.js +46 -45
- package/dist/api/structure.d.ts +60 -13
- package/dist/api/structure.js +132 -88
- package/dist/api/table.d.ts +5 -5
- package/dist/api/table.js +28 -24
- package/dist/api/text.d.ts +27 -2
- package/dist/api/text.js +45 -27
- package/dist/assets/font-data.d.ts +2 -0
- package/dist/assets/font-data.js +6 -0
- package/dist/assets/font-data.ts +7 -0
- package/dist/common/color.js +1 -5
- package/dist/constants/page-sizes.js +3 -6
- package/dist/constants/pdf-parts.js +1 -4
- package/dist/elements/container-element.d.ts +4 -4
- package/dist/elements/container-element.js +9 -13
- package/dist/elements/image-element.d.ts +18 -2
- package/dist/elements/image-element.js +81 -105
- package/dist/elements/index.d.ts +12 -10
- package/dist/elements/index.js +12 -28
- package/dist/elements/layout/default-text-style-element.d.ts +30 -0
- package/dist/elements/layout/default-text-style-element.js +47 -0
- package/dist/elements/layout/deferred-element.d.ts +3 -3
- package/dist/elements/layout/deferred-element.js +4 -8
- package/dist/elements/layout/expanded-element.d.ts +3 -3
- package/dist/elements/layout/expanded-element.js +10 -14
- package/dist/elements/layout/padding-element.d.ts +3 -3
- package/dist/elements/layout/padding-element.js +9 -14
- package/dist/elements/layout/positioned-element.d.ts +44 -0
- package/dist/elements/layout/positioned-element.js +61 -0
- package/dist/elements/layout/repeating-header-element.d.ts +3 -3
- package/dist/elements/layout/repeating-header-element.js +8 -12
- package/dist/elements/layout/sized-container-element.d.ts +2 -2
- package/dist/elements/layout/sized-container-element.js +6 -11
- package/dist/elements/line-element.d.ts +3 -3
- package/dist/elements/line-element.js +5 -10
- package/dist/elements/page-element.d.ts +8 -6
- package/dist/elements/page-element.js +31 -23
- package/dist/elements/pdf-document-element.d.ts +10 -4
- package/dist/elements/pdf-document-element.js +11 -10
- package/dist/elements/pdf-element.d.ts +28 -3
- package/dist/elements/pdf-element.js +10 -19
- package/dist/elements/rectangle-element.d.ts +14 -6
- package/dist/elements/rectangle-element.js +44 -21
- package/dist/elements/row-element.d.ts +3 -3
- package/dist/elements/row-element.js +7 -11
- package/dist/elements/text-element.d.ts +37 -11
- package/dist/elements/text-element.js +64 -39
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -19
- package/dist/ir/display-list.d.ts +22 -3
- package/dist/ir/display-list.js +1 -2
- package/dist/layout/box-constraints.js +2 -6
- package/dist/layout/fragmentation.d.ts +8 -1
- package/dist/layout/fragmentation.js +22 -10
- package/dist/platform/browser-fs.d.ts +2 -0
- package/dist/platform/browser-fs.js +9 -0
- package/dist/platform/browser-image.d.ts +5 -0
- package/dist/platform/browser-image.js +13 -0
- package/dist/platform/node-fs.d.ts +2 -0
- package/dist/platform/node-fs.js +10 -0
- package/dist/platform/node-image.d.ts +5 -0
- package/dist/platform/node-image.js +9 -0
- package/dist/renderer/container-renderer.d.ts +3 -3
- package/dist/renderer/container-renderer.js +12 -27
- package/dist/renderer/default-text-style-renderer.d.ts +6 -0
- package/dist/renderer/default-text-style-renderer.js +10 -0
- package/dist/renderer/deferred-renderer.d.ts +3 -3
- package/dist/renderer/deferred-renderer.js +8 -23
- package/dist/renderer/expanded-renderer.d.ts +3 -3
- package/dist/renderer/expanded-renderer.js +6 -21
- package/dist/renderer/image-renderer.d.ts +3 -3
- package/dist/renderer/image-renderer.js +77 -75
- package/dist/renderer/index.d.ts +10 -10
- package/dist/renderer/index.js +10 -26
- package/dist/renderer/line-renderer.d.ts +3 -3
- package/dist/renderer/line-renderer.js +13 -28
- package/dist/renderer/padding-renderer.d.ts +3 -3
- package/dist/renderer/padding-renderer.js +6 -21
- package/dist/renderer/page-renderer.d.ts +2 -2
- package/dist/renderer/page-renderer.js +61 -77
- package/dist/renderer/pdf-backend.d.ts +2 -2
- package/dist/renderer/pdf-backend.js +34 -17
- package/dist/renderer/pdf-config.js +4 -7
- package/dist/renderer/pdf-document-class.d.ts +5 -5
- package/dist/renderer/pdf-document-class.js +24 -41
- package/dist/renderer/pdf-document-renderer.d.ts +3 -3
- package/dist/renderer/pdf-document-renderer.js +71 -85
- package/dist/renderer/pdf-renderer.d.ts +2 -2
- package/dist/renderer/pdf-renderer.js +83 -90
- package/dist/renderer/positioned-renderer.d.ts +6 -0
- package/dist/renderer/positioned-renderer.js +10 -0
- package/dist/renderer/rectangle-renderer.d.ts +3 -3
- package/dist/renderer/rectangle-renderer.js +45 -44
- package/dist/renderer/repeating-header-renderer.d.ts +3 -3
- package/dist/renderer/repeating-header-renderer.js +11 -26
- package/dist/renderer/row-renderer.d.ts +3 -3
- package/dist/renderer/row-renderer.js +12 -27
- package/dist/renderer/text-renderer.d.ts +6 -5
- package/dist/renderer/text-renderer.js +33 -42
- package/dist/text/line-breaker.d.ts +8 -5
- package/dist/text/line-breaker.js +67 -16
- package/dist/text/text-style.d.ts +25 -0
- package/dist/text/text-style.js +29 -0
- package/dist/utils/afm-parser.js +3 -13
- package/dist/utils/bytes.d.ts +24 -0
- package/dist/utils/bytes.js +76 -0
- package/dist/utils/flex-layout.d.ts +2 -2
- package/dist/utils/flex-layout.js +15 -20
- package/dist/utils/font-metrics.d.ts +1 -1
- package/dist/utils/font-metrics.js +1 -2
- package/dist/utils/font-path.js +3 -6
- package/dist/utils/image-helper.d.ts +6 -5
- package/dist/utils/image-helper.js +101 -111
- package/dist/utils/md5.d.ts +4 -0
- package/dist/utils/md5.js +80 -0
- package/dist/utils/pdf-object-manager.d.ts +10 -6
- package/dist/utils/pdf-object-manager.js +89 -94
- package/dist/utils/renderer-registry.js +1 -5
- package/dist/utils/ttf-parser.d.ts +2 -2
- package/dist/utils/ttf-parser.js +32 -36
- package/dist/utils/ttf-subsetter.d.ts +1 -1
- package/dist/utils/ttf-subsetter.js +40 -42
- package/dist/utils/utf8-to-windows1252-encoder.js +1 -4
- package/dist/validators/element-validator.d.ts +2 -2
- package/dist/validators/element-validator.js +17 -23
- package/package.json +14 -2
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const box_constraints_1 = require("../../layout/box-constraints");
|
|
7
|
-
const fragmentation_1 = require("../../layout/fragmentation");
|
|
8
|
-
class PaddingElement extends pdf_element_1.SizedPDFElement {
|
|
1
|
+
import { Validator } from "../../validators/element-validator.js";
|
|
2
|
+
import { SizedPDFElement } from "../pdf-element.js";
|
|
3
|
+
import { BoxConstraints } from "../../layout/box-constraints.js";
|
|
4
|
+
import { isFragmentable } from "../../layout/fragmentation.js";
|
|
5
|
+
export class PaddingElement extends SizedPDFElement {
|
|
9
6
|
constructor({ margin, child }) {
|
|
10
7
|
super({ x: 0, y: 0 });
|
|
11
8
|
this.child = child;
|
|
@@ -18,7 +15,7 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
|
|
|
18
15
|
* child can't be split, the whole padding moves on as the remainder.
|
|
19
16
|
*/
|
|
20
17
|
fragment(maxHeight, width, ctx) {
|
|
21
|
-
if (!
|
|
18
|
+
if (!isFragmentable(this.child)) {
|
|
22
19
|
return { fitted: null, remainder: this };
|
|
23
20
|
}
|
|
24
21
|
const [marginTop, marginRight, marginBottom, marginLeft] = this.margin;
|
|
@@ -34,7 +31,6 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
|
|
|
34
31
|
return new PaddingElement({ margin: this.margin, child });
|
|
35
32
|
}
|
|
36
33
|
calculateLayout(constraints, offset, ctx) {
|
|
37
|
-
var _a;
|
|
38
34
|
// Padding takes the width it is offered; its height shrink-wraps the child.
|
|
39
35
|
if (constraints.hasBoundedWidth)
|
|
40
36
|
this.width = constraints.maxWidth;
|
|
@@ -50,7 +46,7 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
|
|
|
50
46
|
const childWidth = constraints.hasBoundedWidth
|
|
51
47
|
? Math.max(0, constraints.maxWidth - marginLeft - marginRight)
|
|
52
48
|
: Infinity;
|
|
53
|
-
const childConstraints =
|
|
49
|
+
const childConstraints = BoxConstraints.loose(childWidth, Infinity);
|
|
54
50
|
const childSize = this.child.calculateLayout(childConstraints, childOffset, ctx);
|
|
55
51
|
this.height = childSize.height + marginTop + marginBottom;
|
|
56
52
|
// Unbounded width (e.g. a fixed child in a Row): shrink-wrap to the child + insets,
|
|
@@ -58,9 +54,9 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
|
|
|
58
54
|
if (!constraints.hasBoundedWidth) {
|
|
59
55
|
this.width = childSize.width + marginLeft + marginRight;
|
|
60
56
|
}
|
|
61
|
-
|
|
57
|
+
Validator.validateSizedElement(this);
|
|
62
58
|
// Top-left coordinates; the Y-flip now happens once at the IR -> backend seam.
|
|
63
|
-
return { width:
|
|
59
|
+
return { width: this.width ?? 0, height: this.height };
|
|
64
60
|
}
|
|
65
61
|
getProps() {
|
|
66
62
|
return {
|
|
@@ -73,4 +69,3 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
|
|
|
73
69
|
};
|
|
74
70
|
}
|
|
75
71
|
}
|
|
76
|
-
exports.PaddingElement = PaddingElement;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
|
|
2
|
+
import { LayoutContext, PDFElement, WithChild } from "../pdf-element.js";
|
|
3
|
+
/** A position anchor along one axis: `start` (left/top), `center`, or `end` (right/bottom). */
|
|
4
|
+
export type PositionAnchor = "start" | "center" | "end";
|
|
5
|
+
/**
|
|
6
|
+
* How a `Positioned` child sits in its frame. Two ways, pick per axis:
|
|
7
|
+
* - EDGE pinning: `top`/`right`/`bottom`/`left` (points from that edge; negative pokes outside).
|
|
8
|
+
* Pinning BOTH sides of an axis stretches the child to fill between them.
|
|
9
|
+
* - ANCHOR + nudge: `h`/`v` anchor the child (start/center/end) and `x`/`y` nudge it from there
|
|
10
|
+
* (e.g. `{ h: "center", x: -10 }` = centered minus 10pt). The child shrink-wraps to its content.
|
|
11
|
+
* An edge wins over an anchor on the same axis. With nothing set the child sits at the top-left.
|
|
12
|
+
*/
|
|
13
|
+
export interface PositionedInsets {
|
|
14
|
+
top?: number;
|
|
15
|
+
right?: number;
|
|
16
|
+
bottom?: number;
|
|
17
|
+
left?: number;
|
|
18
|
+
h?: PositionAnchor;
|
|
19
|
+
v?: PositionAnchor;
|
|
20
|
+
x?: number;
|
|
21
|
+
y?: number;
|
|
22
|
+
}
|
|
23
|
+
interface PositionedElementParams extends WithChild, PositionedInsets {
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* An out-of-flow child, placed relative to the nearest enclosing positioning frame (a `relative`
|
|
27
|
+
* Box). It takes ZERO space in the normal flow - `calculateLayout` returns `Size(0,0)` and instead
|
|
28
|
+
* registers a placement closure on the frame. The frame runs that closure once it knows its own
|
|
29
|
+
* size, so `right`/`bottom` resolve against the final box and the child can overflow it (a negative
|
|
30
|
+
* `top`/`left` makes it poke into / out of the corner, e.g. a badge or tab).
|
|
31
|
+
*
|
|
32
|
+
* With no frame in scope the element is a no-op (nothing is drawn) - `Positioned` only makes sense
|
|
33
|
+
* inside a `relative` Box.
|
|
34
|
+
*/
|
|
35
|
+
export declare class PositionedElement extends PDFElement {
|
|
36
|
+
private child;
|
|
37
|
+
private insets;
|
|
38
|
+
constructor({ child, top, right, bottom, left, h, v, x, y }: PositionedElementParams);
|
|
39
|
+
calculateLayout(_constraints: BoxConstraints, _offset: Offset, ctx: LayoutContext): Size;
|
|
40
|
+
/** Lays the child out at the resolved position inside (or overflowing) the frame box. */
|
|
41
|
+
private placeInFrame;
|
|
42
|
+
getProps(): WithChild;
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { BoxConstraints } from "../../layout/box-constraints.js";
|
|
2
|
+
import { PDFElement } from "../pdf-element.js";
|
|
3
|
+
/**
|
|
4
|
+
* An out-of-flow child, placed relative to the nearest enclosing positioning frame (a `relative`
|
|
5
|
+
* Box). It takes ZERO space in the normal flow - `calculateLayout` returns `Size(0,0)` and instead
|
|
6
|
+
* registers a placement closure on the frame. The frame runs that closure once it knows its own
|
|
7
|
+
* size, so `right`/`bottom` resolve against the final box and the child can overflow it (a negative
|
|
8
|
+
* `top`/`left` makes it poke into / out of the corner, e.g. a badge or tab).
|
|
9
|
+
*
|
|
10
|
+
* With no frame in scope the element is a no-op (nothing is drawn) - `Positioned` only makes sense
|
|
11
|
+
* inside a `relative` Box.
|
|
12
|
+
*/
|
|
13
|
+
export class PositionedElement extends PDFElement {
|
|
14
|
+
constructor({ child, top, right, bottom, left, h, v, x, y }) {
|
|
15
|
+
super();
|
|
16
|
+
this.child = child;
|
|
17
|
+
this.insets = { top, right, bottom, left, h, v, x, y };
|
|
18
|
+
}
|
|
19
|
+
calculateLayout(_constraints, _offset, ctx) {
|
|
20
|
+
// Defer to the frame: it calls back once it has sized itself. Out of flow either way.
|
|
21
|
+
ctx.frame?.place.push((frame, frameCtx) => this.placeInFrame(frame, frameCtx));
|
|
22
|
+
return { width: 0, height: 0 };
|
|
23
|
+
}
|
|
24
|
+
/** Lays the child out at the resolved position inside (or overflowing) the frame box. */
|
|
25
|
+
placeInFrame(frame, ctx) {
|
|
26
|
+
const { top, right, bottom, left, h, v, x: nudgeX, y: nudgeY } = this.insets;
|
|
27
|
+
// An axis is PINNED (stretched) only when BOTH of its EDGES are given; otherwise the child
|
|
28
|
+
// shrink-wraps its content (unbounded), the CSS rule for an absolutely-positioned element. An
|
|
29
|
+
// anchor never stretches - it positions a content-sized child.
|
|
30
|
+
const width = left !== undefined && right !== undefined
|
|
31
|
+
? Math.max(0, frame.size.width - left - right)
|
|
32
|
+
: Infinity;
|
|
33
|
+
const height = top !== undefined && bottom !== undefined
|
|
34
|
+
? Math.max(0, frame.size.height - top - bottom)
|
|
35
|
+
: Infinity;
|
|
36
|
+
const constraints = BoxConstraints.loose(width, height);
|
|
37
|
+
// Measure first (so end/center anchors and right/bottom edges resolve against the child's size).
|
|
38
|
+
const measured = this.child.calculateLayout(constraints, { x: 0, y: 0 }, ctx);
|
|
39
|
+
// Resolve one axis: a near-edge pins to origin, a far-edge pins to the far side; otherwise the
|
|
40
|
+
// anchor (default `start`) positions the child and the nudge shifts it from there.
|
|
41
|
+
const place = (origin, frameExtent, childExtent, nearEdge, farEdge, anchor, nudge) => {
|
|
42
|
+
if (nearEdge !== undefined)
|
|
43
|
+
return origin + nearEdge;
|
|
44
|
+
if (farEdge !== undefined)
|
|
45
|
+
return origin + frameExtent - childExtent - farEdge;
|
|
46
|
+
const base = anchor === "center"
|
|
47
|
+
? (frameExtent - childExtent) / 2
|
|
48
|
+
: anchor === "end"
|
|
49
|
+
? frameExtent - childExtent
|
|
50
|
+
: 0; // start (default)
|
|
51
|
+
return origin + base + (nudge ?? 0);
|
|
52
|
+
};
|
|
53
|
+
const x = place(frame.origin.x, frame.size.width, measured.width, left, right, h, nudgeX);
|
|
54
|
+
const y = place(frame.origin.y, frame.size.height, measured.height, top, bottom, v, nudgeY);
|
|
55
|
+
// Place it for real at the resolved position.
|
|
56
|
+
this.child.calculateLayout(constraints, { x, y }, ctx);
|
|
57
|
+
}
|
|
58
|
+
getProps() {
|
|
59
|
+
return { child: this.child };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BoxConstraints, Offset, Size } from "../../layout/box-constraints";
|
|
2
|
-
import { Fragmentable, FragmentResult } from "../../layout/fragmentation";
|
|
3
|
-
import { LayoutContext, PDFElement } from "../pdf-element";
|
|
1
|
+
import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
|
|
2
|
+
import { Fragmentable, FragmentResult } from "../../layout/fragmentation.js";
|
|
3
|
+
import { LayoutContext, PDFElement } from "../pdf-element.js";
|
|
4
4
|
/**
|
|
5
5
|
* Stacks a `header` above a `body` and, when it paginates, **repeats the header on every
|
|
6
6
|
* fragment**. Used by `Table` so column headings reappear at the top of each page. Layout
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const box_constraints_1 = require("../../layout/box-constraints");
|
|
5
|
-
const fragmentation_1 = require("../../layout/fragmentation");
|
|
6
|
-
const pdf_element_1 = require("../pdf-element");
|
|
1
|
+
import { BoxConstraints } from "../../layout/box-constraints.js";
|
|
2
|
+
import { isFragmentable } from "../../layout/fragmentation.js";
|
|
3
|
+
import { PDFElement } from "../pdf-element.js";
|
|
7
4
|
/**
|
|
8
5
|
* Stacks a `header` above a `body` and, when it paginates, **repeats the header on every
|
|
9
6
|
* fragment**. Used by `Table` so column headings reappear at the top of each page. Layout
|
|
10
7
|
* is just header-then-body (like a 2-row Column); the magic is in `fragment`: it splits the
|
|
11
8
|
* body and re-wraps each piece with the same header, so every physical page gets its own.
|
|
12
9
|
*/
|
|
13
|
-
class RepeatingHeaderElement extends
|
|
10
|
+
export class RepeatingHeaderElement extends PDFElement {
|
|
14
11
|
constructor(header, body, gap = 0) {
|
|
15
12
|
super();
|
|
16
13
|
this.header = header;
|
|
@@ -25,16 +22,16 @@ class RepeatingHeaderElement extends pdf_element_1.PDFElement {
|
|
|
25
22
|
this.x = offset.x;
|
|
26
23
|
this.y = offset.y;
|
|
27
24
|
const width = constraints.hasBoundedWidth ? constraints.maxWidth : 0;
|
|
28
|
-
const h = this.header.calculateLayout(
|
|
29
|
-
const b = this.body.calculateLayout(
|
|
25
|
+
const h = this.header.calculateLayout(BoxConstraints.loose(width, Infinity), { x: this.x, y: this.y }, ctx);
|
|
26
|
+
const b = this.body.calculateLayout(BoxConstraints.loose(width, Infinity), { x: this.x, y: this.y + h.height + this.gap }, ctx);
|
|
30
27
|
this.width = width;
|
|
31
28
|
this.height = h.height + this.gap + b.height;
|
|
32
29
|
return { width: this.width, height: this.height };
|
|
33
30
|
}
|
|
34
31
|
fragment(maxHeight, width, ctx) {
|
|
35
32
|
// Reserve the header's height on every page; the body flows in what's left.
|
|
36
|
-
const headerHeight = this.header.calculateLayout(
|
|
37
|
-
if (!
|
|
33
|
+
const headerHeight = this.header.calculateLayout(BoxConstraints.loose(width, Infinity), { x: 0, y: 0 }, ctx).height;
|
|
34
|
+
if (!isFragmentable(this.body))
|
|
38
35
|
return { fitted: this, remainder: null };
|
|
39
36
|
const split = this.body.fragment(Math.max(0, maxHeight - headerHeight - this.gap), width, ctx);
|
|
40
37
|
// Body fits whole → the whole thing fits on this page.
|
|
@@ -57,4 +54,3 @@ class RepeatingHeaderElement extends pdf_element_1.PDFElement {
|
|
|
57
54
|
};
|
|
58
55
|
}
|
|
59
56
|
}
|
|
60
|
-
exports.RepeatingHeaderElement = RepeatingHeaderElement;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SizedElement, WithChildren, SizedPDFElement, LayoutContext } from "../pdf-element";
|
|
2
|
-
import { BoxConstraints, Offset, Size } from "../../layout/box-constraints";
|
|
1
|
+
import { SizedElement, WithChildren, SizedPDFElement, LayoutContext } from "../pdf-element.js";
|
|
2
|
+
import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
|
|
3
3
|
interface ContainerElementParams extends SizedElement, WithChildren {
|
|
4
4
|
color?: [number, number, number];
|
|
5
5
|
backgroundColor?: [number, number, number];
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const pdf_element_1 = require("../pdf-element");
|
|
5
|
-
const box_constraints_1 = require("../../layout/box-constraints");
|
|
6
|
-
class SizedContainerElement extends pdf_element_1.SizedPDFElement {
|
|
1
|
+
import { SizedPDFElement, } from "../pdf-element.js";
|
|
2
|
+
import { BoxConstraints } from "../../layout/box-constraints.js";
|
|
3
|
+
export class SizedContainerElement extends SizedPDFElement {
|
|
7
4
|
constructor({ width, height, children }) {
|
|
8
5
|
super({ x: 0, y: 0, width, height });
|
|
9
6
|
this.children = children;
|
|
10
7
|
}
|
|
11
8
|
calculateLayout(constraints, offset, ctx) {
|
|
12
|
-
var _a, _b;
|
|
13
9
|
if (constraints.hasBoundedWidth)
|
|
14
10
|
this.width = constraints.maxWidth;
|
|
15
11
|
if (constraints.hasBoundedHeight)
|
|
@@ -17,10 +13,10 @@ class SizedContainerElement extends pdf_element_1.SizedPDFElement {
|
|
|
17
13
|
// Absolute placement from the parent; assignment (not +=) so re-layout is idempotent.
|
|
18
14
|
this.x = offset.x;
|
|
19
15
|
this.y = offset.y;
|
|
20
|
-
const width =
|
|
21
|
-
const height =
|
|
16
|
+
const width = this.width ?? 0;
|
|
17
|
+
const height = this.height ?? 0;
|
|
22
18
|
if (this.children)
|
|
23
|
-
this.children.forEach((child) => child.calculateLayout(
|
|
19
|
+
this.children.forEach((child) => child.calculateLayout(BoxConstraints.loose(width, height), { x: this.x, y: this.y }, ctx));
|
|
24
20
|
// Top-left coordinates; the Y-flip now happens once at the IR -> backend seam.
|
|
25
21
|
return { width, height };
|
|
26
22
|
}
|
|
@@ -34,4 +30,3 @@ class SizedContainerElement extends pdf_element_1.SizedPDFElement {
|
|
|
34
30
|
};
|
|
35
31
|
}
|
|
36
32
|
}
|
|
37
|
-
exports.SizedContainerElement = SizedContainerElement;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Color } from "../common/color";
|
|
2
|
-
import { BoxConstraints, Offset, Size } from "../layout/box-constraints";
|
|
3
|
-
import { LayoutContext, SizedElement, SizedPDFElement } from "./pdf-element";
|
|
1
|
+
import { Color } from "../common/color.js";
|
|
2
|
+
import { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
|
|
3
|
+
import { LayoutContext, SizedElement, SizedPDFElement } from "./pdf-element.js";
|
|
4
4
|
interface LineElementParams extends SizedElement {
|
|
5
5
|
color?: Color;
|
|
6
6
|
strokeWidth?: number;
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const pdf_element_1 = require("./pdf-element");
|
|
6
|
-
class LineElement extends pdf_element_1.SizedPDFElement {
|
|
7
|
-
constructor({ color = new color_1.Color(0, 0, 0), strokeWidth, x, y, xEnd, yEnd }) {
|
|
1
|
+
import { Color } from "../common/color.js";
|
|
2
|
+
import { SizedPDFElement } from "./pdf-element.js";
|
|
3
|
+
export class LineElement extends SizedPDFElement {
|
|
4
|
+
constructor({ color = new Color(0, 0, 0), strokeWidth, x, y, xEnd, yEnd }) {
|
|
8
5
|
super({ x: x, y: y, width: xEnd, height: y + yEnd });
|
|
9
6
|
this.color = color;
|
|
10
7
|
this.strokeWidth = strokeWidth ? strokeWidth : 1;
|
|
@@ -15,7 +12,6 @@ class LineElement extends pdf_element_1.SizedPDFElement {
|
|
|
15
12
|
this.sizeMemory = { x, y, width: xEnd, height: yEnd };
|
|
16
13
|
}
|
|
17
14
|
calculateLayout(constraints, offset, _ctx) {
|
|
18
|
-
var _a, _b;
|
|
19
15
|
// Set relative to parent
|
|
20
16
|
this.x = this.sizeMemory.x + offset.x;
|
|
21
17
|
this.y = this.sizeMemory.y + offset.y;
|
|
@@ -26,7 +22,7 @@ class LineElement extends pdf_element_1.SizedPDFElement {
|
|
|
26
22
|
this.xEnd = offset.x + constraints.maxWidth - this.sizeMemory.width;
|
|
27
23
|
this.yEnd = offset.y + this.sizeMemory.height;
|
|
28
24
|
// Top-left coordinates; the Y-flip happens once at the IR -> backend seam.
|
|
29
|
-
return { width:
|
|
25
|
+
return { width: this.width ?? 0, height: this.height ?? 0 };
|
|
30
26
|
}
|
|
31
27
|
getProps() {
|
|
32
28
|
return {
|
|
@@ -41,4 +37,3 @@ class LineElement extends pdf_element_1.SizedPDFElement {
|
|
|
41
37
|
};
|
|
42
38
|
}
|
|
43
39
|
}
|
|
44
|
-
exports.LineElement = LineElement;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { PageSize } from "../constants/page-sizes";
|
|
2
|
-
import { Orientation } from "../renderer/pdf-config";
|
|
3
|
-
import type { ColorMode, DefaultFont, Margin } from "../renderer";
|
|
4
|
-
import { BoxConstraints, Offset, Size } from "../layout/box-constraints";
|
|
5
|
-
import { LayoutContext, PDFElement, WithChildren } from "./pdf-element";
|
|
6
|
-
import { TextElement } from "./text-element";
|
|
1
|
+
import { PageSize } from "../constants/page-sizes.js";
|
|
2
|
+
import { Orientation } from "../renderer/pdf-config.js";
|
|
3
|
+
import type { ColorMode, DefaultFont, Margin } from "../renderer/index.js";
|
|
4
|
+
import { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
|
|
5
|
+
import { LayoutContext, PDFElement, WithChildren } from "./pdf-element.js";
|
|
6
|
+
import { TextElement } from "./text-element.js";
|
|
7
7
|
export interface PDFPageConfig {
|
|
8
8
|
pageSize?: PageSize;
|
|
9
|
+
/** Explicit [width, height] in points; overrides `pageSize` (e.g. a custom label format). */
|
|
10
|
+
customSize?: [number, number];
|
|
9
11
|
orientation?: Orientation;
|
|
10
12
|
margin?: Margin;
|
|
11
13
|
colorMode?: ColorMode;
|
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports.layoutPageBands = layoutPageBands;
|
|
6
|
-
const page_sizes_1 = require("../constants/page-sizes");
|
|
7
|
-
const pdf_config_1 = require("../renderer/pdf-config");
|
|
8
|
-
const box_constraints_1 = require("../layout/box-constraints");
|
|
9
|
-
const pdf_element_1 = require("./pdf-element");
|
|
1
|
+
import { pageFormats } from "../constants/page-sizes.js";
|
|
2
|
+
import { Orientation } from "../renderer/pdf-config.js";
|
|
3
|
+
import { BoxConstraints } from "../layout/box-constraints.js";
|
|
4
|
+
import { PDFElement } from "./pdf-element.js";
|
|
10
5
|
/**
|
|
11
6
|
* The content box of a page (inside the margins, orientation applied) for a fully
|
|
12
7
|
* resolved config. Single source of truth, shared by `PageElement` layout and the page
|
|
13
8
|
* driver so they can never drift.
|
|
14
9
|
*/
|
|
15
|
-
function resolvePageContentBox(config) {
|
|
10
|
+
export function resolvePageContentBox(config) {
|
|
16
11
|
const margin = config.margin;
|
|
17
|
-
|
|
18
|
-
let
|
|
19
|
-
|
|
12
|
+
const [pageW, pageH] = config.customSize ?? pageFormats[config.pageSize];
|
|
13
|
+
let width = pageW - margin.left - margin.right;
|
|
14
|
+
let height = pageH - margin.top - margin.bottom;
|
|
15
|
+
if (config.orientation === Orientation.landscape) {
|
|
20
16
|
[width, height] = [height, width];
|
|
21
17
|
}
|
|
22
18
|
return { origin: { x: margin.left, y: margin.top }, width, height };
|
|
@@ -29,17 +25,17 @@ function resolvePageContentBox(config) {
|
|
|
29
25
|
* no header/footer the bands are zero and the body equals the full content box - identical
|
|
30
26
|
* to a page without them.
|
|
31
27
|
*/
|
|
32
|
-
function layoutPageBands(config, header, footer, ctx) {
|
|
28
|
+
export function layoutPageBands(config, header, footer, ctx) {
|
|
33
29
|
const { origin, width, height } = resolvePageContentBox(config);
|
|
34
30
|
let headerHeight = 0;
|
|
35
31
|
if (header) {
|
|
36
|
-
headerHeight = header.calculateLayout(
|
|
32
|
+
headerHeight = header.calculateLayout(BoxConstraints.loose(width, Infinity), origin, ctx).height;
|
|
37
33
|
}
|
|
38
34
|
let footerHeight = 0;
|
|
39
35
|
if (footer) {
|
|
40
36
|
// Measure first to learn its height, then place it flush against the bottom edge.
|
|
41
|
-
footerHeight = footer.calculateLayout(
|
|
42
|
-
footer.calculateLayout(
|
|
37
|
+
footerHeight = footer.calculateLayout(BoxConstraints.loose(width, Infinity), origin, ctx).height;
|
|
38
|
+
footer.calculateLayout(BoxConstraints.loose(width, Infinity), { x: origin.x, y: origin.y + height - footerHeight }, ctx);
|
|
43
39
|
}
|
|
44
40
|
return {
|
|
45
41
|
bodyOrigin: { x: origin.x, y: origin.y + headerHeight },
|
|
@@ -49,11 +45,11 @@ function layoutPageBands(config, header, footer, ctx) {
|
|
|
49
45
|
footerHeight,
|
|
50
46
|
};
|
|
51
47
|
}
|
|
52
|
-
class PageElement extends
|
|
48
|
+
export class PageElement extends PDFElement {
|
|
53
49
|
constructor({ children, config, header, footer }) {
|
|
54
50
|
super();
|
|
55
51
|
this.children = children;
|
|
56
|
-
this.config = config
|
|
52
|
+
this.config = config ?? {};
|
|
57
53
|
this.header = header;
|
|
58
54
|
this.footer = footer;
|
|
59
55
|
}
|
|
@@ -61,16 +57,29 @@ class PageElement extends pdf_element_1.PDFElement {
|
|
|
61
57
|
// Merge the document defaults (carried in the context) with this page's overrides,
|
|
62
58
|
// then hand descendants a context bound to THIS page's geometry. This is what
|
|
63
59
|
// fixes the old last-page-wins global page-config bug.
|
|
64
|
-
this.config =
|
|
60
|
+
this.config = { ...ctx.pageConfig, ...this.config };
|
|
65
61
|
const pageCtx = {
|
|
66
62
|
metrics: ctx.metrics,
|
|
67
63
|
pageConfig: this.config,
|
|
64
|
+
textStyle: ctx.textStyle,
|
|
65
|
+
onOverflow: ctx.onOverflow,
|
|
68
66
|
};
|
|
69
67
|
// Place the header/footer bands; the body gets the region left in between (the whole
|
|
70
68
|
// content box when there is neither - byte-identical to a plain page).
|
|
71
69
|
const bands = layoutPageBands(this.config, this.header, this.footer, pageCtx);
|
|
72
|
-
const childConstraints =
|
|
73
|
-
|
|
70
|
+
const childConstraints = BoxConstraints.loose(bands.bodyWidth, bands.bodyHeight);
|
|
71
|
+
// The page body is itself a positioning frame: a `Positioned` with no `relative` ancestor
|
|
72
|
+
// resolves against the content box (a `relative` Box overrides it for its own subtree). Drained
|
|
73
|
+
// after the body is laid out, so a page-level Positioned isn't a silent no-op.
|
|
74
|
+
const frame = {
|
|
75
|
+
origin: bands.bodyOrigin,
|
|
76
|
+
size: { width: bands.bodyWidth, height: bands.bodyHeight },
|
|
77
|
+
place: [],
|
|
78
|
+
};
|
|
79
|
+
const bodyCtx = { ...pageCtx, frame };
|
|
80
|
+
this.children.forEach((child) => child.calculateLayout(childConstraints, bands.bodyOrigin, bodyCtx));
|
|
81
|
+
for (const place of frame.place)
|
|
82
|
+
place(frame, pageCtx);
|
|
74
83
|
const { width, height } = resolvePageContentBox(this.config);
|
|
75
84
|
return { width, height };
|
|
76
85
|
}
|
|
@@ -87,4 +96,3 @@ class PageElement extends pdf_element_1.PDFElement {
|
|
|
87
96
|
return this;
|
|
88
97
|
}
|
|
89
98
|
}
|
|
90
|
-
exports.PageElement = PageElement;
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import { PageElement } from "./page-element";
|
|
2
|
-
import { BoxConstraints, Offset, Size } from "../layout/box-constraints";
|
|
3
|
-
import { LayoutContext, PDFElement, WithChildren } from "./pdf-element";
|
|
1
|
+
import { PageElement } from "./page-element.js";
|
|
2
|
+
import { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
|
|
3
|
+
import { LayoutContext, PDFElement, WithChildren } from "./pdf-element.js";
|
|
4
|
+
import type { ResolvedTextStyle } from "../text/text-style.js";
|
|
4
5
|
interface PDFDocumentParams extends WithChildren {
|
|
5
6
|
children: PageElement[];
|
|
7
|
+
/** Document-level text defaults descendants inherit (seeded into the layout-context root). */
|
|
8
|
+
defaultTextStyle?: Partial<ResolvedTextStyle>;
|
|
6
9
|
}
|
|
7
10
|
export declare class PDFDocumentElement extends PDFElement {
|
|
8
11
|
private children;
|
|
9
|
-
|
|
12
|
+
private defaultTextStyle?;
|
|
13
|
+
constructor({ children, defaultTextStyle }: PDFDocumentParams);
|
|
14
|
+
/** The document-level text defaults; the renderer merges them into the cascade root. */
|
|
15
|
+
getDefaultTextStyle(): Partial<ResolvedTextStyle> | undefined;
|
|
10
16
|
calculateLayout(_constraints: BoxConstraints, _offset: Offset, ctx: LayoutContext): Size;
|
|
11
17
|
getProps(): PDFDocumentParams;
|
|
12
18
|
}
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const pdf_element_1 = require("./pdf-element");
|
|
6
|
-
class PDFDocumentElement extends pdf_element_1.PDFElement {
|
|
7
|
-
constructor({ children }) {
|
|
1
|
+
import { BoxConstraints } from "../layout/box-constraints.js";
|
|
2
|
+
import { PDFElement } from "./pdf-element.js";
|
|
3
|
+
export class PDFDocumentElement extends PDFElement {
|
|
4
|
+
constructor({ children, defaultTextStyle }) {
|
|
8
5
|
super();
|
|
9
6
|
this.children = children;
|
|
7
|
+
this.defaultTextStyle = defaultTextStyle;
|
|
8
|
+
}
|
|
9
|
+
/** The document-level text defaults; the renderer merges them into the cascade root. */
|
|
10
|
+
getDefaultTextStyle() {
|
|
11
|
+
return this.defaultTextStyle;
|
|
10
12
|
}
|
|
11
13
|
calculateLayout(_constraints, _offset, ctx) {
|
|
12
14
|
// The document is the root: each page derives its own geometry, so it ignores the
|
|
13
15
|
// incoming constraints/offset. It has no size of its own.
|
|
14
16
|
const origin = { x: 0, y: 0 };
|
|
15
|
-
this.children.forEach((child) => child.calculateLayout(new
|
|
17
|
+
this.children.forEach((child) => child.calculateLayout(new BoxConstraints(), origin, ctx));
|
|
16
18
|
return { width: 0, height: 0 };
|
|
17
19
|
}
|
|
18
20
|
getProps() {
|
|
19
|
-
return { children: this.children };
|
|
21
|
+
return { children: this.children, defaultTextStyle: this.defaultTextStyle };
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
|
-
exports.PDFDocumentElement = PDFDocumentElement;
|
|
@@ -1,15 +1,40 @@
|
|
|
1
|
-
import type { FontMetrics } from "../utils/font-metrics";
|
|
2
|
-
import type { PDFPageConfig } from "./page-element";
|
|
3
|
-
import type {
|
|
1
|
+
import type { FontMetrics } from "../utils/font-metrics.js";
|
|
2
|
+
import type { PDFPageConfig } from "./page-element.js";
|
|
3
|
+
import type { ResolvedTextStyle } from "../text/text-style.js";
|
|
4
|
+
import type { OverflowPolicy } from "../layout/fragmentation.js";
|
|
5
|
+
import type { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
|
|
4
6
|
/**
|
|
5
7
|
* Everything the layout pass needs, threaded explicitly (no global singleton):
|
|
6
8
|
* font metrics for measuring, and the geometry of the page currently being laid out.
|
|
7
9
|
* `PageElement` sets `pageConfig` for its subtree, so each page flips against its own
|
|
8
10
|
* height. The PDF byte writer is deliberately absent - layout must not touch it.
|
|
9
11
|
*/
|
|
12
|
+
/**
|
|
13
|
+
* A positioning frame - the CSS "containing block" that `Positioned` children resolve their
|
|
14
|
+
* offsets against. A `relative` Box (later the page) creates one and threads it to its subtree;
|
|
15
|
+
* `Positioned` descendants register a placement closure in `place`, which the frame drains once it
|
|
16
|
+
* has finished sizing itself (so `right`/`bottom` can resolve against the final box).
|
|
17
|
+
*/
|
|
18
|
+
export interface PositioningFrame {
|
|
19
|
+
origin: Offset;
|
|
20
|
+
size: Size;
|
|
21
|
+
place: Array<(frame: {
|
|
22
|
+
origin: Offset;
|
|
23
|
+
size: Size;
|
|
24
|
+
}, ctx: LayoutContext) => void>;
|
|
25
|
+
}
|
|
10
26
|
export interface LayoutContext {
|
|
11
27
|
metrics: FontMetrics;
|
|
12
28
|
pageConfig: PDFPageConfig;
|
|
29
|
+
/** The nearest enclosing positioning frame, if any (set by a `relative` Box). */
|
|
30
|
+
frame?: PositioningFrame;
|
|
31
|
+
/** The cascaded text style descendants inherit (CSS/Flutter-style). Seeded at the document root
|
|
32
|
+
* from the built-in defaults + the `Document` defaults, and carried through page contexts; a
|
|
33
|
+
* `Text` resolves its own unset properties against it. Absent falls back to the built-in defaults. */
|
|
34
|
+
textStyle?: ResolvedTextStyle;
|
|
35
|
+
/** What to do when an element overflows a page region and cannot break (set from the render option;
|
|
36
|
+
* absent = clip silently). Evaluated in `packChildren` where the forced placement happens. */
|
|
37
|
+
onOverflow?: OverflowPolicy;
|
|
13
38
|
}
|
|
14
39
|
export declare abstract class PDFElement {
|
|
15
40
|
abstract getProps(): unknown;
|
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.VerticalAlignment = exports.HorizontalAlignment = exports.FlexiblePDFElement = exports.SizedPDFElement = exports.PDFElement = void 0;
|
|
4
|
-
exports.isSizedElement = isSizedElement;
|
|
5
|
-
exports.hasChildrenProp = hasChildrenProp;
|
|
6
|
-
exports.hasChildProp = hasChildProp;
|
|
7
|
-
class PDFElement {
|
|
1
|
+
export class PDFElement {
|
|
8
2
|
}
|
|
9
|
-
|
|
10
|
-
class SizedPDFElement extends PDFElement {
|
|
3
|
+
export class SizedPDFElement extends PDFElement {
|
|
11
4
|
constructor(data) {
|
|
12
5
|
super();
|
|
13
6
|
this.x = data.x;
|
|
@@ -19,8 +12,7 @@ class SizedPDFElement extends PDFElement {
|
|
|
19
12
|
return { x: this.x, y: this.y, width: this.width, height: this.height };
|
|
20
13
|
}
|
|
21
14
|
}
|
|
22
|
-
|
|
23
|
-
class FlexiblePDFElement extends PDFElement {
|
|
15
|
+
export class FlexiblePDFElement extends PDFElement {
|
|
24
16
|
constructor(data) {
|
|
25
17
|
super();
|
|
26
18
|
this.flex = data.flex;
|
|
@@ -30,26 +22,25 @@ class FlexiblePDFElement extends PDFElement {
|
|
|
30
22
|
return this.flex;
|
|
31
23
|
}
|
|
32
24
|
}
|
|
33
|
-
|
|
34
|
-
var HorizontalAlignment;
|
|
25
|
+
export var HorizontalAlignment;
|
|
35
26
|
(function (HorizontalAlignment) {
|
|
36
27
|
HorizontalAlignment["left"] = "LEFT";
|
|
37
28
|
HorizontalAlignment["right"] = "RIGHT";
|
|
38
29
|
HorizontalAlignment["center"] = "CENTER";
|
|
39
30
|
HorizontalAlignment["block"] = "BLOCK";
|
|
40
|
-
})(HorizontalAlignment || (
|
|
41
|
-
var VerticalAlignment;
|
|
31
|
+
})(HorizontalAlignment || (HorizontalAlignment = {}));
|
|
32
|
+
export var VerticalAlignment;
|
|
42
33
|
(function (VerticalAlignment) {
|
|
43
34
|
VerticalAlignment["top"] = "TOP";
|
|
44
35
|
VerticalAlignment["middle"] = "MIDDLE";
|
|
45
36
|
VerticalAlignment["bottom"] = "BOTTOM";
|
|
46
|
-
})(VerticalAlignment || (
|
|
47
|
-
function isSizedElement(obj) {
|
|
37
|
+
})(VerticalAlignment || (VerticalAlignment = {}));
|
|
38
|
+
export function isSizedElement(obj) {
|
|
48
39
|
return typeof obj === "object" && obj !== null && "x" in obj && "y" in obj;
|
|
49
40
|
}
|
|
50
|
-
function hasChildrenProp(obj) {
|
|
41
|
+
export function hasChildrenProp(obj) {
|
|
51
42
|
return "children" in obj;
|
|
52
43
|
}
|
|
53
|
-
function hasChildProp(obj) {
|
|
44
|
+
export function hasChildProp(obj) {
|
|
54
45
|
return "child" in obj;
|
|
55
46
|
}
|