@jasy/pdf 1.0.0-alpha.8 → 1.0.0-beta.1
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 +29 -10
- package/dist/api/color.js +69 -0
- package/dist/api/content.d.ts +45 -5
- package/dist/api/content.js +96 -7
- package/dist/api/descriptor.js +6 -1
- package/dist/api/dimension.d.ts +57 -0
- package/dist/api/dimension.js +27 -0
- package/dist/api/font-url.d.ts +28 -0
- package/dist/api/font-url.js +135 -0
- package/dist/api/gradient.d.ts +53 -0
- package/dist/api/gradient.js +97 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +2 -0
- package/dist/api/insets.d.ts +19 -12
- package/dist/api/insets.js +18 -7
- package/dist/api/layout.d.ts +20 -6
- package/dist/api/layout.js +31 -6
- package/dist/api/page-builder.d.ts +8 -0
- package/dist/api/page-builder.js +12 -0
- package/dist/api/structure.d.ts +12 -0
- package/dist/api/structure.js +54 -7
- package/dist/api/text.d.ts +65 -8
- package/dist/api/text.js +38 -5
- package/dist/canvas/painter.d.ts +102 -0
- package/dist/canvas/painter.js +183 -0
- package/dist/edit/document.d.ts +14 -4
- package/dist/edit/document.js +15 -22
- package/dist/edit/fill.d.ts +19 -2
- package/dist/edit/fill.js +63 -34
- package/dist/edit/flatten.d.ts +13 -1
- package/dist/edit/flatten.js +38 -13
- package/dist/edit/index.d.ts +2 -0
- package/dist/edit/index.js +3 -1
- package/dist/edit/objects.d.ts +5 -0
- package/dist/edit/objects.js +27 -0
- package/dist/edit/writer.d.ts +7 -0
- package/dist/edit/writer.js +23 -1
- package/dist/elements/canvas-element.d.ts +38 -0
- package/dist/elements/canvas-element.js +47 -0
- package/dist/elements/container-element.d.ts +23 -1
- package/dist/elements/container-element.js +31 -10
- package/dist/elements/image-element.d.ts +18 -4
- package/dist/elements/image-element.js +27 -12
- package/dist/elements/index.d.ts +2 -0
- package/dist/elements/index.js +2 -0
- package/dist/elements/layout/expanded-element.d.ts +5 -1
- package/dist/elements/layout/expanded-element.js +16 -3
- package/dist/elements/layout/keep-together-element.d.ts +2 -0
- package/dist/elements/layout/keep-together-element.js +4 -0
- package/dist/elements/layout/padding-element.d.ts +9 -2
- package/dist/elements/layout/padding-element.js +12 -2
- package/dist/elements/layout/page-builder-element.js +2 -0
- package/dist/elements/layout/struct-group.d.ts +2 -0
- package/dist/elements/layout/struct-group.js +4 -0
- package/dist/elements/pdf-element.d.ts +75 -1
- package/dist/elements/pdf-element.js +80 -1
- package/dist/elements/rectangle-element.d.ts +22 -6
- package/dist/elements/rectangle-element.js +31 -12
- package/dist/elements/row-element.d.ts +26 -1
- package/dist/elements/row-element.js +31 -10
- package/dist/elements/svg-element.d.ts +41 -0
- package/dist/elements/svg-element.js +93 -0
- package/dist/elements/text-element.d.ts +92 -1
- package/dist/elements/text-element.js +208 -33
- package/dist/ir/display-list.d.ts +67 -11
- package/dist/ir/display-list.js +8 -1
- package/dist/layout/alignment.d.ts +10 -0
- package/dist/layout/alignment.js +6 -0
- package/dist/layout/box-constraints.d.ts +53 -0
- package/dist/layout/box-constraints.js +72 -0
- package/dist/layout/insets.d.ts +28 -0
- package/dist/layout/insets.js +20 -0
- package/dist/layout/min-intrinsic.d.ts +29 -0
- package/dist/layout/min-intrinsic.js +37 -0
- package/dist/renderer/anchor-renderer.js +1 -1
- package/dist/renderer/bookmark-renderer.js +1 -1
- package/dist/renderer/canvas-renderer.d.ts +14 -0
- package/dist/renderer/canvas-renderer.js +36 -0
- package/dist/renderer/container-renderer.js +1 -3
- package/dist/renderer/default-text-style-renderer.js +1 -1
- package/dist/renderer/deferred-renderer.js +1 -1
- package/dist/renderer/expanded-renderer.js +1 -1
- package/dist/renderer/image-renderer.js +2 -1
- package/dist/renderer/index.d.ts +2 -0
- package/dist/renderer/index.js +2 -0
- package/dist/renderer/keep-together-renderer.js +1 -1
- package/dist/renderer/link-renderer.js +1 -1
- package/dist/renderer/padding-renderer.js +1 -1
- package/dist/renderer/page-builder-renderer.js +1 -1
- package/dist/renderer/page-renderer.js +1 -3
- package/dist/renderer/pdf-backend.d.ts +21 -4
- package/dist/renderer/pdf-backend.js +198 -61
- package/dist/renderer/pdf-document-renderer.js +8 -1
- package/dist/renderer/pdf-renderer.js +5 -1
- package/dist/renderer/positioned-renderer.js +1 -1
- package/dist/renderer/rectangle-renderer.js +9 -5
- package/dist/renderer/repeating-header-renderer.js +1 -2
- package/dist/renderer/rotated-renderer.js +1 -1
- package/dist/renderer/row-renderer.js +1 -3
- package/dist/renderer/struct-group-renderer.js +1 -1
- package/dist/renderer/svg-renderer.d.ts +11 -0
- package/dist/renderer/svg-renderer.js +27 -0
- package/dist/renderer/text-renderer.d.ts +2 -2
- package/dist/renderer/text-renderer.js +176 -57
- package/dist/svg/css.d.ts +38 -0
- package/dist/svg/css.js +115 -0
- package/dist/svg/errors.d.ts +24 -0
- package/dist/svg/errors.js +30 -0
- package/dist/svg/gradients.d.ts +34 -0
- package/dist/svg/gradients.js +156 -0
- package/dist/svg/index.d.ts +22 -0
- package/dist/svg/index.js +331 -0
- package/dist/svg/shapes.d.ts +6 -0
- package/dist/svg/shapes.js +177 -0
- package/dist/svg/style.d.ts +61 -0
- package/dist/svg/style.js +144 -0
- package/dist/svg/transform.d.ts +13 -0
- package/dist/svg/transform.js +68 -0
- package/dist/svg/units.d.ts +11 -0
- package/dist/svg/units.js +73 -0
- package/dist/svg/xml.d.ts +24 -0
- package/dist/svg/xml.js +158 -0
- package/dist/text/advance.d.ts +3 -0
- package/dist/text/advance.js +8 -4
- package/dist/text/arabic.d.ts +20 -0
- package/dist/text/arabic.js +101 -0
- package/dist/text/bidi.d.ts +33 -0
- package/dist/text/bidi.js +94 -0
- package/dist/text/font-fallback.d.ts +25 -0
- package/dist/text/font-fallback.js +38 -0
- package/dist/text/glyph-coverage.d.ts +15 -0
- package/dist/text/glyph-coverage.js +77 -0
- package/dist/text/line-breaker.d.ts +43 -1
- package/dist/text/line-breaker.js +181 -45
- package/dist/text/orphans-widows.d.ts +27 -0
- package/dist/text/orphans-widows.js +53 -0
- package/dist/text/shape.d.ts +29 -0
- package/dist/text/shape.js +91 -0
- package/dist/text/text-style.d.ts +38 -0
- package/dist/text/text-style.js +50 -1
- package/dist/text/whitespace.d.ts +4 -0
- package/dist/text/whitespace.js +43 -0
- package/dist/text/word-splitting.d.ts +42 -0
- package/dist/text/word-splitting.js +72 -0
- package/dist/utils/flex-layout.d.ts +24 -4
- package/dist/utils/flex-layout.js +218 -7
- package/dist/utils/font-metrics.d.ts +13 -2
- package/dist/utils/gsub.d.ts +36 -0
- package/dist/utils/gsub.js +178 -0
- package/dist/utils/inflate.d.ts +16 -0
- package/dist/utils/inflate.js +52 -0
- package/dist/utils/pdf-object-manager.d.ts +44 -3
- package/dist/utils/pdf-object-manager.js +176 -14
- package/dist/utils/renderer-registry.d.ts +13 -1
- package/dist/utils/renderer-registry.js +22 -1
- package/dist/utils/ttf-parser.d.ts +6 -0
- package/dist/utils/ttf-parser.js +19 -0
- package/dist/utils/utf8-to-windows1252-encoder.d.ts +6 -0
- package/dist/utils/utf8-to-windows1252-encoder.js +10 -0
- package/dist/utils/woff.d.ts +10 -0
- package/dist/utils/woff.js +116 -0
- package/dist/utils/woff2.d.ts +6 -0
- package/dist/utils/woff2.js +651 -0
- package/dist/validators/element-validator.js +9 -2
- package/dist/vector/path.d.ts +33 -0
- package/dist/vector/path.js +81 -0
- package/package.json +6 -2
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { FlexLayoutHelper, VERTICAL_AXIS } from "../utils/flex-layout.js";
|
|
2
|
-
import {
|
|
2
|
+
import { stackMinIntrinsic, withDeclaredExtent } from "../layout/min-intrinsic.js";
|
|
3
|
+
import { extentSpecs, resolveSize, } from "../layout/box-constraints.js";
|
|
3
4
|
import { childrenForceBreak, packChildren, } from "../layout/fragmentation.js";
|
|
4
5
|
import { FlexiblePDFElement, SizedPDFElement, } from "./pdf-element.js";
|
|
5
6
|
export class ContainerElement extends SizedPDFElement {
|
|
6
|
-
constructor({ x, y, width, height, children, gap, main, cross,
|
|
7
|
+
constructor({ x, y, width, height, children, gap, main, cross, reverse, wrap, alignContent, breakBefore, breakAfter, ...sizing }) {
|
|
7
8
|
super({ x, y, width, height });
|
|
8
9
|
this.children = children;
|
|
9
10
|
this.gap = gap ?? 0;
|
|
10
11
|
this.main = main ?? "start";
|
|
11
12
|
this.cross = cross ?? "stretch";
|
|
12
|
-
this.
|
|
13
|
+
this.reverse = reverse ?? false;
|
|
14
|
+
this.wrap = wrap ?? false;
|
|
15
|
+
this.alignContent = alignContent;
|
|
16
|
+
this.requested = { ...sizing, width, height };
|
|
13
17
|
this.breakBefore = breakBefore ?? false;
|
|
14
18
|
this.breakAfter = breakAfter ?? false;
|
|
15
19
|
}
|
|
@@ -62,6 +66,9 @@ export class ContainerElement extends SizedPDFElement {
|
|
|
62
66
|
gap: this.gap,
|
|
63
67
|
main: this.main,
|
|
64
68
|
cross: this.cross,
|
|
69
|
+
reverse: this.reverse,
|
|
70
|
+
wrap: this.wrap,
|
|
71
|
+
alignContent: this.alignContent,
|
|
65
72
|
breakAfter,
|
|
66
73
|
});
|
|
67
74
|
}
|
|
@@ -87,23 +94,30 @@ export class ContainerElement extends SizedPDFElement {
|
|
|
87
94
|
const ownFlexChild = !horizontal && this.children.some((c) => c instanceof FlexiblePDFElement);
|
|
88
95
|
return ownFlexChild || this.children.some((c) => c.needsBoundedMain(horizontal));
|
|
89
96
|
}
|
|
97
|
+
/** A Column stacks vertically, so widths overlap and heights add up. */
|
|
98
|
+
minIntrinsicMain(horizontal, ctx) {
|
|
99
|
+
const content = stackMinIntrinsic(this.children, this.gap, !horizontal, horizontal, ctx, this.wrap);
|
|
100
|
+
return withDeclaredExtent(content, horizontal ? this.requested.width : this.requested.height, horizontal ? this.requested.minWidth : this.requested.minHeight);
|
|
101
|
+
}
|
|
90
102
|
calculateLayout(constraints, offset, ctx) {
|
|
91
103
|
this.x = offset.x;
|
|
92
104
|
this.y = offset.y;
|
|
93
105
|
// Relative sizing: a pinned extent (fixed points or a fraction of the offered box, clamped into
|
|
94
106
|
// the constraints) wins; else fill a bounded axis; else stay `undefined` and shrink-wrap below.
|
|
95
107
|
// A Column nested in a Row gets unbounded width - passing 0 there would collapse children to 0.
|
|
96
|
-
const
|
|
97
|
-
const
|
|
108
|
+
const specs = extentSpecs(this.requested);
|
|
109
|
+
const resolved = resolveSize(specs.width, specs.height, this.requested.aspectRatio, constraints);
|
|
110
|
+
const { width: explicitWidth, height: explicitHeight, constraints: bounds } = resolved;
|
|
111
|
+
// Fill-or-shrink-wrap is decided by the constraints we were GIVEN; a min/max only caps the result.
|
|
98
112
|
const boundedWidth = explicitWidth !== undefined
|
|
99
|
-
?
|
|
113
|
+
? bounds.constrainWidth(explicitWidth)
|
|
100
114
|
: constraints.hasBoundedWidth
|
|
101
|
-
?
|
|
115
|
+
? bounds.maxWidth
|
|
102
116
|
: undefined;
|
|
103
117
|
const boundedHeight = explicitHeight !== undefined
|
|
104
|
-
?
|
|
118
|
+
? bounds.constrainHeight(explicitHeight)
|
|
105
119
|
: constraints.hasBoundedHeight
|
|
106
|
-
?
|
|
120
|
+
? bounds.maxHeight
|
|
107
121
|
: undefined;
|
|
108
122
|
// Vertical stack: cross = width (children fill it), main = height (the stacking extent).
|
|
109
123
|
const crossAvail = boundedWidth ?? Infinity;
|
|
@@ -113,7 +127,14 @@ export class ContainerElement extends SizedPDFElement {
|
|
|
113
127
|
// Vertical flex stack (main = height, cross = width). The shared helper measures
|
|
114
128
|
// fixed children, distributes the leftover to flex children, and places everything
|
|
115
129
|
// in source order.
|
|
116
|
-
result = FlexLayoutHelper.layout(this.children, VERTICAL_AXIS, mainAvail, crossAvail, this.y, this.x, {
|
|
130
|
+
result = FlexLayoutHelper.layout(this.children, VERTICAL_AXIS, mainAvail, crossAvail, this.y, this.x, {
|
|
131
|
+
gap: this.gap,
|
|
132
|
+
main: this.main,
|
|
133
|
+
cross: this.cross,
|
|
134
|
+
reverse: this.reverse,
|
|
135
|
+
wrap: this.wrap,
|
|
136
|
+
alignContent: this.alignContent,
|
|
137
|
+
}, ctx);
|
|
117
138
|
}
|
|
118
139
|
// Pinned/bounded axis takes that extent; an unbounded one shrink-wraps to the children (height =
|
|
119
140
|
// the stack, width = the widest child). Top-left coordinates; the container draws nothing, and
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Radii } from "../ir/display-list.js";
|
|
1
2
|
import { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
|
|
2
3
|
import { LayoutContext, SizedPDFElement } from "./pdf-element.js";
|
|
3
4
|
export declare enum BoxFit {
|
|
@@ -55,9 +56,20 @@ interface ImageElementParams {
|
|
|
55
56
|
widthFactor?: number;
|
|
56
57
|
/** Height as a fraction (0..1) of the offered height; see `widthFactor`. */
|
|
57
58
|
heightFactor?: number;
|
|
59
|
+
/** Lower / upper bounds per axis, in points or as a fraction; see `SizingParams`. */
|
|
60
|
+
minWidth?: number;
|
|
61
|
+
maxWidth?: number;
|
|
62
|
+
minHeight?: number;
|
|
63
|
+
maxHeight?: number;
|
|
64
|
+
minWidthFactor?: number;
|
|
65
|
+
maxWidthFactor?: number;
|
|
66
|
+
minHeightFactor?: number;
|
|
67
|
+
maxHeightFactor?: number;
|
|
68
|
+
/** width / height; overrides the image's OWN ratio (CSS `aspect-ratio`), `fit` then places it. */
|
|
69
|
+
aspectRatio?: number;
|
|
58
70
|
fit?: BoxFit;
|
|
59
|
-
/** Corner radius in points; rounds the image box (0 = sharp, default). */
|
|
60
|
-
radius?: number;
|
|
71
|
+
/** Corner radius in points - one number or per corner; rounds the image box (0 = sharp, default). */
|
|
72
|
+
radius?: number | Radii;
|
|
61
73
|
/** Alternate text for accessibility (tagged PDF). With `alt` the image is a Figure; without, decoration. */
|
|
62
74
|
alt?: string;
|
|
63
75
|
}
|
|
@@ -69,8 +81,10 @@ export declare class ImageElement extends SizedPDFElement {
|
|
|
69
81
|
private radius;
|
|
70
82
|
private readonly alt?;
|
|
71
83
|
private requested;
|
|
84
|
+
/** min/max/aspectRatio, kept as given so every layout pass re-resolves them. */
|
|
85
|
+
private sizing;
|
|
72
86
|
private intrinsic?;
|
|
73
|
-
constructor({ image, width, height, widthFactor, heightFactor, fit, radius, alt, }: ImageElementParams);
|
|
87
|
+
constructor({ image, width, height, widthFactor, heightFactor, fit, radius, alt, ...sizing }: ImageElementParams);
|
|
74
88
|
/**
|
|
75
89
|
* Loads the image and records its intrinsic pixel size. Runs in the async pre-layout pass (layout
|
|
76
90
|
* itself is synchronous and cannot await jimp) so `calculateLayout` can turn a width-only image
|
|
@@ -87,7 +101,7 @@ export declare class ImageElement extends SizedPDFElement {
|
|
|
87
101
|
height: number | undefined;
|
|
88
102
|
image: CustomImage;
|
|
89
103
|
fit: BoxFit;
|
|
90
|
-
radius: number;
|
|
104
|
+
radius: number | Radii;
|
|
91
105
|
alt: string | undefined;
|
|
92
106
|
};
|
|
93
107
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getImageDimensions } from "../utils/image-helper.js";
|
|
2
2
|
import { latin1FromBytes } from "../utils/bytes.js";
|
|
3
3
|
import { readFileBytesAsync } from "../platform/node-fs.js";
|
|
4
|
-
import {
|
|
4
|
+
import { extentSpecs, resolveSize, } from "../layout/box-constraints.js";
|
|
5
5
|
import { SizedPDFElement } from "./pdf-element.js";
|
|
6
6
|
// path.extname without node:path (browser-safe): the substring from the last dot, if it sits after the
|
|
7
7
|
// last slash (so a dot in a directory name does not count). Enough for image file extensions.
|
|
@@ -100,7 +100,7 @@ export class CustomBytesImage extends CustomImage {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
export class ImageElement extends SizedPDFElement {
|
|
103
|
-
constructor({ image, width, height, widthFactor, heightFactor, fit = BoxFit.none, radius, alt, }) {
|
|
103
|
+
constructor({ image, width, height, widthFactor, heightFactor, fit = BoxFit.none, radius, alt, ...sizing }) {
|
|
104
104
|
// Seed this.width/height from the request so getProps() reflects it before layout; calculateLayout
|
|
105
105
|
// then reads `requested` (never the mutated fields) and overwrites these with the laid-out size.
|
|
106
106
|
super({ x: 0, y: 0, width });
|
|
@@ -109,6 +109,7 @@ export class ImageElement extends SizedPDFElement {
|
|
|
109
109
|
this.requested = { width, height };
|
|
110
110
|
this.widthFactor = widthFactor;
|
|
111
111
|
this.heightFactor = heightFactor;
|
|
112
|
+
this.sizing = sizing;
|
|
112
113
|
this.fit = fit;
|
|
113
114
|
this.radius = radius ?? 0;
|
|
114
115
|
this.alt = alt;
|
|
@@ -136,22 +137,36 @@ export class ImageElement extends SizedPDFElement {
|
|
|
136
137
|
this.y = offset.y;
|
|
137
138
|
// Relative sizing: a fixed size or a fraction of the offered box (fraction only in a bounded axis).
|
|
138
139
|
// Read from `requested` (not this.width/height, which we overwrite below) so every pass re-resolves.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
const specs = extentSpecs({
|
|
141
|
+
...this.sizing,
|
|
142
|
+
width: this.requested.width,
|
|
143
|
+
height: this.requested.height,
|
|
144
|
+
widthFactor: this.widthFactor,
|
|
145
|
+
heightFactor: this.heightFactor,
|
|
146
|
+
});
|
|
147
|
+
// An explicit `aspectRatio` wins over the image's own, as it does in CSS - and only it may size a
|
|
148
|
+
// box with NEITHER axis pinned. Left to the intrinsic ratio that would change what an unsized image
|
|
149
|
+
// has always done here (fill both axes and let `fit` sort it out).
|
|
150
|
+
const resolved = resolveSize(specs.width, specs.height, this.sizing.aspectRatio, constraints);
|
|
151
|
+
let w = resolved.width;
|
|
152
|
+
let h = resolved.height;
|
|
153
|
+
const bounds = resolved.constraints;
|
|
154
|
+
// Aspect auto-size: when exactly ONE axis is pinned, derive the other from the intrinsic ratio
|
|
155
|
+
// (CSS `width: 50%; height: auto`). Only fires once the pre-pass resolved the pixel size.
|
|
156
|
+
if (this.sizing.aspectRatio === undefined &&
|
|
157
|
+
this.intrinsic &&
|
|
158
|
+
this.intrinsic.width > 0 &&
|
|
159
|
+
this.intrinsic.height > 0) {
|
|
144
160
|
const ratio = this.intrinsic.width / this.intrinsic.height;
|
|
145
161
|
if (w !== undefined && h === undefined)
|
|
146
|
-
h = w / ratio;
|
|
162
|
+
h = bounds.constrainHeight(w / ratio);
|
|
147
163
|
else if (h !== undefined && w === undefined)
|
|
148
|
-
w = h * ratio;
|
|
164
|
+
w = bounds.constrainWidth(h * ratio);
|
|
149
165
|
}
|
|
150
166
|
// Fall back to the prior behavior for an unpinned axis: a bounded axis fills, otherwise keep the
|
|
151
167
|
// requested fixed size (or undefined). Read from `requested`, never the mutated this.width/height.
|
|
152
|
-
this.width = w ?? (
|
|
153
|
-
this.height =
|
|
154
|
-
h ?? (constraints.hasBoundedHeight ? constraints.maxHeight : this.requested.height);
|
|
168
|
+
this.width = w ?? (bounds.hasBoundedWidth ? bounds.maxWidth : this.requested.width);
|
|
169
|
+
this.height = h ?? (bounds.hasBoundedHeight ? bounds.maxHeight : this.requested.height);
|
|
155
170
|
// Top-left coordinates; the fit logic (renderer) and the Y-flip (seam) run later.
|
|
156
171
|
return { width: this.width ?? 0, height: this.height ?? 0 };
|
|
157
172
|
}
|
package/dist/elements/index.d.ts
CHANGED
package/dist/elements/index.js
CHANGED
|
@@ -9,7 +9,9 @@ export declare class ExpandedElement extends FlexiblePDFElement implements Fragm
|
|
|
9
9
|
private y;
|
|
10
10
|
private width;
|
|
11
11
|
private height;
|
|
12
|
-
constructor({ flex, child }: ExpandedElementParams);
|
|
12
|
+
constructor({ flex, basis, basisFactor, child }: ExpandedElementParams);
|
|
13
|
+
/** Layout-transparent: the floor is whatever the wrapped child needs. */
|
|
14
|
+
minIntrinsicMain(horizontal: boolean, ctx: LayoutContext): number;
|
|
13
15
|
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
14
16
|
/**
|
|
15
17
|
* When the column paginates, a flex region can't "fill" across pages, so it delegates to
|
|
@@ -24,6 +26,8 @@ export declare class ExpandedElement extends FlexiblePDFElement implements Fragm
|
|
|
24
26
|
y: number;
|
|
25
27
|
width: number;
|
|
26
28
|
height: number;
|
|
29
|
+
basis: number;
|
|
30
|
+
basisFactor: number | undefined;
|
|
27
31
|
child: PDFElement;
|
|
28
32
|
};
|
|
29
33
|
}
|
|
@@ -3,14 +3,18 @@ import { FlexiblePDFElement, } from "../pdf-element.js";
|
|
|
3
3
|
import { BoxConstraints } from "../../layout/box-constraints.js";
|
|
4
4
|
import { isFragmentable } from "../../layout/fragmentation.js";
|
|
5
5
|
export class ExpandedElement extends FlexiblePDFElement {
|
|
6
|
-
constructor({ flex, child }) {
|
|
7
|
-
super({ flex });
|
|
6
|
+
constructor({ flex, basis, basisFactor, child }) {
|
|
7
|
+
super({ flex, basis, basisFactor });
|
|
8
8
|
this.x = 0;
|
|
9
9
|
this.y = 0;
|
|
10
10
|
this.width = 0;
|
|
11
11
|
this.height = 0;
|
|
12
12
|
this.child = child;
|
|
13
13
|
}
|
|
14
|
+
/** Layout-transparent: the floor is whatever the wrapped child needs. */
|
|
15
|
+
minIntrinsicMain(horizontal, ctx) {
|
|
16
|
+
return this.child.minIntrinsicMain(horizontal, ctx);
|
|
17
|
+
}
|
|
14
18
|
calculateLayout(constraints, offset, ctx) {
|
|
15
19
|
if (constraints.hasBoundedWidth)
|
|
16
20
|
this.width = constraints.maxWidth;
|
|
@@ -50,7 +54,14 @@ export class ExpandedElement extends FlexiblePDFElement {
|
|
|
50
54
|
};
|
|
51
55
|
}
|
|
52
56
|
cloneWithChild(child) {
|
|
53
|
-
|
|
57
|
+
// The basis has to come along: a fragment that lost it would claim only its share of the leftover,
|
|
58
|
+
// so a `flexBasis` slot would silently change width on the page it continues onto.
|
|
59
|
+
return new ExpandedElement({
|
|
60
|
+
flex: this.flex,
|
|
61
|
+
basis: this.basis,
|
|
62
|
+
basisFactor: this.basisFactor,
|
|
63
|
+
child,
|
|
64
|
+
});
|
|
54
65
|
}
|
|
55
66
|
getProps() {
|
|
56
67
|
return {
|
|
@@ -58,6 +69,8 @@ export class ExpandedElement extends FlexiblePDFElement {
|
|
|
58
69
|
y: this.y,
|
|
59
70
|
width: this.width,
|
|
60
71
|
height: this.height,
|
|
72
|
+
basis: this.basis,
|
|
73
|
+
basisFactor: this.basisFactor,
|
|
61
74
|
child: this.child,
|
|
62
75
|
};
|
|
63
76
|
}
|
|
@@ -26,6 +26,8 @@ export declare class KeepTogetherElement extends PDFElement implements Fragmenta
|
|
|
26
26
|
constructor({ child }: {
|
|
27
27
|
child: PDFElement;
|
|
28
28
|
});
|
|
29
|
+
/** Layout-transparent: the floor is whatever the wrapped child needs. */
|
|
30
|
+
minIntrinsicMain(horizontal: boolean, ctx: LayoutContext): number;
|
|
29
31
|
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
30
32
|
relativeSizeFactor(horizontal: boolean): number | undefined;
|
|
31
33
|
needsBoundedMain(horizontal: boolean): boolean;
|
|
@@ -26,6 +26,10 @@ export class KeepTogetherElement extends PDFElement {
|
|
|
26
26
|
this.warnedBreakConflict = false;
|
|
27
27
|
this.child = child;
|
|
28
28
|
}
|
|
29
|
+
/** Layout-transparent: the floor is whatever the wrapped child needs. */
|
|
30
|
+
minIntrinsicMain(horizontal, ctx) {
|
|
31
|
+
return this.child.minIntrinsicMain(horizontal, ctx);
|
|
32
|
+
}
|
|
29
33
|
calculateLayout(constraints, offset, ctx) {
|
|
30
34
|
return this.child.calculateLayout(constraints, offset, ctx);
|
|
31
35
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { PDFElement, LayoutContext, WithChild, SizedPDFElement } from "../pdf-element.js";
|
|
2
2
|
import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
|
|
3
3
|
import { Fragmentable, FragmentResult } from "../../layout/fragmentation.js";
|
|
4
|
+
import { type EdgeSpecs } from "../../layout/insets.js";
|
|
4
5
|
interface PaddingElementParams extends WithChild {
|
|
5
|
-
|
|
6
|
+
/** Still unresolved: a side may be a percentage of the offered WIDTH (see `Insets`). */
|
|
7
|
+
margin: EdgeSpecs;
|
|
6
8
|
}
|
|
7
9
|
export declare class PaddingElement extends SizedPDFElement implements Fragmentable {
|
|
8
10
|
private child;
|
|
@@ -19,13 +21,18 @@ export declare class PaddingElement extends SizedPDFElement implements Fragmenta
|
|
|
19
21
|
breaksBefore(): boolean;
|
|
20
22
|
breaksAfter(): boolean;
|
|
21
23
|
private cloneWithChild;
|
|
24
|
+
/**
|
|
25
|
+
* The child plus our own insets. A PERCENTAGE inset counts as zero here: it resolves against a width
|
|
26
|
+
* that is not decided yet, which is exactly how CSS treats a percentage when sizing intrinsically.
|
|
27
|
+
*/
|
|
28
|
+
minIntrinsicMain(horizontal: boolean, ctx: LayoutContext): number;
|
|
22
29
|
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
23
30
|
getProps(): {
|
|
24
31
|
x: number;
|
|
25
32
|
y: number;
|
|
26
33
|
width: number | undefined;
|
|
27
34
|
height: number | undefined;
|
|
28
|
-
margin:
|
|
35
|
+
margin: EdgeSpecs;
|
|
29
36
|
child: PDFElement;
|
|
30
37
|
};
|
|
31
38
|
}
|
|
@@ -2,6 +2,7 @@ import { Validator } from "../../validators/element-validator.js";
|
|
|
2
2
|
import { SizedPDFElement } from "../pdf-element.js";
|
|
3
3
|
import { BoxConstraints } from "../../layout/box-constraints.js";
|
|
4
4
|
import { isFragmentable } from "../../layout/fragmentation.js";
|
|
5
|
+
import { resolveEdges } from "../../layout/insets.js";
|
|
5
6
|
export class PaddingElement extends SizedPDFElement {
|
|
6
7
|
constructor({ margin, child }) {
|
|
7
8
|
super({ x: 0, y: 0 });
|
|
@@ -18,7 +19,7 @@ export class PaddingElement extends SizedPDFElement {
|
|
|
18
19
|
if (!isFragmentable(this.child)) {
|
|
19
20
|
return { fitted: null, remainder: this };
|
|
20
21
|
}
|
|
21
|
-
const [marginTop, marginRight, marginBottom, marginLeft] = this.margin;
|
|
22
|
+
const [marginTop, marginRight, marginBottom, marginLeft] = resolveEdges(this.margin, width);
|
|
22
23
|
const childWidth = width - marginLeft - marginRight;
|
|
23
24
|
const childMaxHeight = maxHeight - marginTop - marginBottom;
|
|
24
25
|
const split = this.child.fragment(childMaxHeight, childWidth, ctx);
|
|
@@ -42,13 +43,22 @@ export class PaddingElement extends SizedPDFElement {
|
|
|
42
43
|
cloneWithChild(child) {
|
|
43
44
|
return new PaddingElement({ margin: this.margin, child });
|
|
44
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* The child plus our own insets. A PERCENTAGE inset counts as zero here: it resolves against a width
|
|
48
|
+
* that is not decided yet, which is exactly how CSS treats a percentage when sizing intrinsically.
|
|
49
|
+
*/
|
|
50
|
+
minIntrinsicMain(horizontal, ctx) {
|
|
51
|
+
const [top, right, bottom, left] = resolveEdges(this.margin, 0);
|
|
52
|
+
return (this.child.minIntrinsicMain(horizontal, ctx) + (horizontal ? left + right : top + bottom));
|
|
53
|
+
}
|
|
45
54
|
calculateLayout(constraints, offset, ctx) {
|
|
46
55
|
// Padding takes the width it is offered; its height shrink-wraps the child.
|
|
47
56
|
if (constraints.hasBoundedWidth)
|
|
48
57
|
this.width = constraints.maxWidth;
|
|
49
58
|
this.x = offset.x;
|
|
50
59
|
this.y = offset.y;
|
|
51
|
-
|
|
60
|
+
// Percentages resolve against the width we were OFFERED, so every pass gets the same answer.
|
|
61
|
+
const [marginTop, marginRight, marginBottom, marginLeft] = resolveEdges(this.margin, constraints.maxWidth);
|
|
52
62
|
// The child is inset by the margins: shifted down/right, narrowed by the
|
|
53
63
|
// horizontal margins, and left height-unbounded so it sizes to its own content.
|
|
54
64
|
const childOffset = {
|
|
@@ -16,6 +16,8 @@ export declare class StructGroup extends PDFElement implements Fragmentable {
|
|
|
16
16
|
role: string;
|
|
17
17
|
child: PDFElement;
|
|
18
18
|
});
|
|
19
|
+
/** Layout-transparent: the floor is whatever the wrapped child needs. */
|
|
20
|
+
minIntrinsicMain(horizontal: boolean, ctx: LayoutContext): number;
|
|
19
21
|
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
20
22
|
/** Only splittable when the wrapped child is - so a StructGroup(Row) is moved whole to the next page,
|
|
21
23
|
* not clipped at the boundary (isFragmentable honours this veto). */
|
|
@@ -14,6 +14,10 @@ export class StructGroup extends PDFElement {
|
|
|
14
14
|
this.role = role;
|
|
15
15
|
this.child = child;
|
|
16
16
|
}
|
|
17
|
+
/** Layout-transparent: the floor is whatever the wrapped child needs. */
|
|
18
|
+
minIntrinsicMain(horizontal, ctx) {
|
|
19
|
+
return this.child.minIntrinsicMain(horizontal, ctx);
|
|
20
|
+
}
|
|
17
21
|
calculateLayout(constraints, offset, ctx) {
|
|
18
22
|
return this.child.calculateLayout(constraints, offset, ctx);
|
|
19
23
|
}
|
|
@@ -3,6 +3,7 @@ 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
5
|
import type { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
|
|
6
|
+
import type { CrossAlign } from "../layout/alignment.js";
|
|
6
7
|
/**
|
|
7
8
|
* Everything the layout pass needs, threaded explicitly (no global singleton):
|
|
8
9
|
* font metrics for measuring, and the geometry of the page currently being laid out.
|
|
@@ -29,8 +30,18 @@ export interface PositioningFrame {
|
|
|
29
30
|
* the document's final physical page total. `pageSize` is the media box in points, orientation applied.
|
|
30
31
|
*/
|
|
31
32
|
export interface PageInfo {
|
|
33
|
+
/** 1-based, counting PHYSICAL pages across the whole document. */
|
|
32
34
|
pageNumber: number;
|
|
35
|
+
/** Physical pages in the whole document. */
|
|
33
36
|
pageCount: number;
|
|
37
|
+
/**
|
|
38
|
+
* 1-based within the LOGICAL page this sheet came from - the `Page(...)` element the author wrote.
|
|
39
|
+
* A document of one `Page` has `subPageNumber === pageNumber`; a document of several (an invoice
|
|
40
|
+
* plus its attachment, say) restarts the count at each one.
|
|
41
|
+
*/
|
|
42
|
+
subPageNumber: number;
|
|
43
|
+
/** Physical pages this logical page produced. */
|
|
44
|
+
subPageTotalPages: number;
|
|
34
45
|
pageSize: {
|
|
35
46
|
width: number;
|
|
36
47
|
height: number;
|
|
@@ -84,6 +95,17 @@ export declare abstract class PDFElement {
|
|
|
84
95
|
* the parent hands it the line's bounded main extent instead of `Infinity`. Default: no.
|
|
85
96
|
*/
|
|
86
97
|
needsBoundedMain(_horizontal: boolean): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* The smallest main-axis extent this element can be squeezed into and still hold its content - CSS's
|
|
100
|
+
* `min-content` size, which is what an automatic `min-width` resolves to on a flex item. The shrink
|
|
101
|
+
* pass floors every child at this value, so a line that overflows badly stops squeezing rather than
|
|
102
|
+
* grinding a paragraph down to one word per line (which would only trade a wide box for a tall one).
|
|
103
|
+
*
|
|
104
|
+
* `horizontal` = the width. Default 0: an element with no opinion may be squeezed to nothing, which
|
|
105
|
+
* is what an empty box or a plain drawing can do without harm. Text and the layout containers
|
|
106
|
+
* override it; containers recurse, since a Row is only as unsqueezable as its children.
|
|
107
|
+
*/
|
|
108
|
+
minIntrinsicMain(_horizontal: boolean, _ctx: LayoutContext): number;
|
|
87
109
|
/**
|
|
88
110
|
* Whether this element IS a forced page break (a `PageBreak`). The pagination packer cuts the flow
|
|
89
111
|
* at such a marker: everything before it stays, everything after starts a new page. Default: no.
|
|
@@ -108,6 +130,36 @@ export declare abstract class PDFElement {
|
|
|
108
130
|
* parent packer once this element has been placed whole. Default: no.
|
|
109
131
|
*/
|
|
110
132
|
breaksAfter(): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* This child's own cross-axis alignment inside its Column / Row (CSS `align-self`), overriding the
|
|
135
|
+
* container's `align`. Lives on the base element because any child of a stack may set it, not just
|
|
136
|
+
* the sized ones. `undefined` means "follow the container".
|
|
137
|
+
*/
|
|
138
|
+
alignSelf?: CrossAlign;
|
|
139
|
+
/** Sets `alignSelf` and returns the element, so a factory can thread it through in one expression. */
|
|
140
|
+
withAlignSelf(align: CrossAlign | undefined): this;
|
|
141
|
+
/**
|
|
142
|
+
* Where this child sits among its siblings (CSS `order`), lowest first, source order deciding ties.
|
|
143
|
+
* 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.
|
|
145
|
+
*/
|
|
146
|
+
order: number;
|
|
147
|
+
/**
|
|
148
|
+
* How willingly this child gives up main-axis space when the line overflows (CSS `flex-shrink`),
|
|
149
|
+
* weighted by its own size as CSS does. Default 1, as in CSS: an overflowing line squeezes its
|
|
150
|
+
* children back inside instead of letting them run past the edge of the box. `0` opts out and keeps
|
|
151
|
+
* a child at its natural size.
|
|
152
|
+
*
|
|
153
|
+
* This was 0 until the alpha, so that adding flexShrink could not move an existing layout. That
|
|
154
|
+
* caution outlived its use: four of the gallery cases turned out to be overflowing their page
|
|
155
|
+
* margin without anyone noticing, because nothing ever pulled them back. Shrinking is bounded from
|
|
156
|
+
* below by `minIntrinsicMain`, so a child is never squeezed past what it can actually hold.
|
|
157
|
+
*/
|
|
158
|
+
flexShrink: number;
|
|
159
|
+
/** Sets `flexShrink` and returns the element. */
|
|
160
|
+
withFlexShrink(shrink: number | undefined): this;
|
|
161
|
+
/** Sets `order` and returns the element, so a factory can thread it through in one expression. */
|
|
162
|
+
withOrder(order: number | undefined): this;
|
|
111
163
|
}
|
|
112
164
|
export declare abstract class SizedPDFElement extends PDFElement {
|
|
113
165
|
protected x: number;
|
|
@@ -120,14 +172,32 @@ export declare abstract class SizedPDFElement extends PDFElement {
|
|
|
120
172
|
export declare abstract class FlexiblePDFElement extends PDFElement {
|
|
121
173
|
protected flex: number;
|
|
122
174
|
protected verticalChildAlignment: VerticalAlignment;
|
|
175
|
+
/** Points reserved before any leftover is shared out (CSS `flex-basis`); default 0. */
|
|
176
|
+
protected basis: number;
|
|
177
|
+
/** The same as a fraction of the line, for `flexBasis: "25%"`. */
|
|
178
|
+
protected basisFactor?: number;
|
|
123
179
|
constructor(data: FlexibleElement);
|
|
124
180
|
getFlex(): number;
|
|
181
|
+
/**
|
|
182
|
+
* The main extent this child starts from, before the leftover is shared out. `lineMain` is what the
|
|
183
|
+
* line offers its items (its extent minus the gaps), so a percentage basis resolves against the same
|
|
184
|
+
* base a percentage WIDTH already does - and falls back to 0 on an unbounded axis, where a fraction
|
|
185
|
+
* has no meaning.
|
|
186
|
+
*/
|
|
187
|
+
/** Whether a PERCENTAGE basis was given - it resolves to 0 on an unbounded axis, so asking for the
|
|
188
|
+
* number alone cannot tell "no basis" from "a basis that does not apply here". */
|
|
189
|
+
hasBasisFactor(): boolean;
|
|
190
|
+
getBasis(lineMain: number): number;
|
|
125
191
|
}
|
|
126
192
|
export declare enum HorizontalAlignment {
|
|
193
|
+
/** CSS `text-align: start` - the side the writing STARTS on: left in `ltr`, right in `rtl`. The
|
|
194
|
+
* default, so a right-to-left paragraph begins on the right without anyone asking for it. */
|
|
195
|
+
start = "START",
|
|
127
196
|
left = "LEFT",
|
|
128
197
|
right = "RIGHT",
|
|
129
198
|
center = "CENTER",
|
|
130
|
-
|
|
199
|
+
/** CSS `text-align: justify` - both edges line up, the last line of a paragraph excepted. */
|
|
200
|
+
justify = "JUSTIFY"
|
|
131
201
|
}
|
|
132
202
|
export declare enum VerticalAlignment {
|
|
133
203
|
top = "TOP",
|
|
@@ -142,6 +212,10 @@ export interface WithChild {
|
|
|
142
212
|
}
|
|
143
213
|
export interface FlexibleElement {
|
|
144
214
|
flex: number;
|
|
215
|
+
/** Points reserved before the leftover is shared out (CSS `flex-basis`). */
|
|
216
|
+
basis?: number;
|
|
217
|
+
/** The same as a fraction of the line, for `flexBasis: "25%"`. */
|
|
218
|
+
basisFactor?: number;
|
|
145
219
|
verticalChildAlignment?: VerticalAlignment;
|
|
146
220
|
}
|
|
147
221
|
export interface SizedElement {
|