fleuron/layout/fragment.rs
1//! What the flow can move: one line, one image, one ornament,
2//! and what the blocks around it paint.
3
4use std::sync::Arc;
5
6use crate::content::NodeId;
7use crate::lines::Line;
8use crate::pages::{DrawItem, PageBox};
9use crate::style::{BorderRadius, BoxDecorationBreak, Break, Color, ComputedStyle, Edges};
10
11use super::background::Backdrop;
12
13use super::build::Reflow;
14use super::note::Note;
15
16/// Whether a page may end above a fragment.
17///
18/// Everything the cascade says about fragmentation — `break-before`,
19/// `break-after`, `break-inside`, `orphans`, `widows` — reaches the
20/// flow as one of these, decided while the fragments are built.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum BreakPoint {
23 /// A page break must fall here, on the side the break names.
24 Forced(Break),
25 /// A break may fall here.
26 Allowed,
27 /// A break may not fall here: this fragment moves with the one
28 /// above it.
29 Forbidden,
30}
31
32/// What one fragment paints.
33#[derive(Debug, Clone)]
34pub enum Piece {
35 /// A laid-out line, and the initial letter sunk beside it.
36 Line {
37 /// The line itself, shaped and measured.
38 line: Line,
39 /// The drop cap set beside this line, on the first line of a
40 /// paragraph that has one. Boxed: a book has thousands of
41 /// lines and a handful of initial letters.
42 cap: Option<Box<DropCap>>,
43 },
44 /// A placed image, sized against the content box.
45 Image {
46 /// Width in points, after any scaling.
47 width: f32,
48 /// Height in points, after any scaling.
49 height: f32,
50 /// Index into the asset table.
51 asset: u32,
52 },
53 /// Space with nothing in it: what a thematic break set in space
54 /// rather than in an ornament comes to.
55 Blank,
56 /// Where an image the sheet lifted out of the flow was written.
57 /// It takes no space and paints nothing. The page the flow
58 /// reaches here is the page that places the image.
59 Anchor(NodeId),
60 /// One row of a table, set whole.
61 Row(Box<TableRow>),
62}
63
64/// One row of a table, set whole: what it paints, and what the flow
65/// needs to set the table's header rows again on a new page.
66#[derive(Debug, Clone)]
67pub struct TableRow {
68 /// What the row paints, from the top of the row and the leading
69 /// edge of the content box.
70 pub items: Vec<DrawItem>,
71 /// The border boxes of the row, its cells, and the blocks inside
72 /// them, from the top of the row and the leading edge of the
73 /// content box.
74 pub boxes: Vec<(NodeId, PageBox)>,
75 /// Whether this is the first row of its table.
76 pub opens: bool,
77 /// Whether this is a header row, which is set again at the top of
78 /// every page or column the table continues onto.
79 pub head: bool,
80 /// Whether the header rows are set above this row when it is the
81 /// first thing on a page or in a column.
82 pub repeats: bool,
83}
84
85/// An initial letter sunk beside the lines that follow it.
86#[derive(Debug, Clone)]
87pub struct DropCap {
88 /// The letter, shaped at the size the sink works out to.
89 pub line: Line,
90 /// Leading edge, from the content box's own.
91 pub x: f32,
92 /// How far the cap's baseline sits below its line's.
93 pub drop: f32,
94}
95
96/// The marker of a list item, set to the left of the item on the
97/// baseline of its first line.
98#[derive(Debug, Clone)]
99pub struct Marker {
100 /// The marker and the space after it, shaped in the item's style.
101 pub line: Line,
102 /// Leading edge, from the content box's own.
103 pub x: f32,
104}
105
106/// One thing the flow can place: a line, an image, an ornament.
107///
108/// Everything horizontal is settled here — indentation, alignment,
109/// the measure a drop cap left — so the flow only stacks.
110#[derive(Debug, Clone)]
111pub struct Fragment {
112 /// Leading edge, from the content box's own.
113 pub x: f32,
114 /// Space above, from the margins around it. A page that opens on
115 /// this fragment drops it.
116 pub lead: f32,
117 /// Space above that a page break does not drop and no margin
118 /// collapses through: the borders and padding between this
119 /// fragment and whatever is above it.
120 pub fixed: f32,
121 /// The fragment's own height.
122 pub height: f32,
123 /// Whether a page may end above it.
124 pub break_before: BreakPoint,
125 /// What it paints.
126 pub piece: Piece,
127 /// What it tells the page furniture when it lands. Boxed because
128 /// a book has thousands of fragments and a handful of chapter
129 /// headings.
130 pub marks: Option<Box<Marks>>,
131 /// The decorated blocks this fragment opens and closes. Boxed
132 /// for the same reason: most fragments decorate nothing.
133 pub decorations: Option<Box<Decorations>>,
134 /// The markers of the list items that open on this fragment,
135 /// outermost first. Boxed, because most fragments open no item.
136 pub markers: Option<Box<Vec<Marker>>>,
137 /// The notes whose references were set on this fragment, in the
138 /// order they were written. They are set at the foot of whichever
139 /// page the fragment lands on. Boxed: a book has thousands of
140 /// lines and a handful of notes.
141 pub notes: Option<Box<Vec<Arc<Note>>>>,
142 /// The paragraph this line came out of, shared by every line of
143 /// it, and `None` on everything else. The flow reads it where an
144 /// image narrows the bands the paragraph is set in. A book that
145 /// anchors nothing keeps none of this.
146 pub reflow: Option<Arc<Reflow>>,
147 /// Whether it came out of a block that spans every column, from
148 /// `column-span: all`. Its leading edge and its measure are then
149 /// the whole content box's rather than one column's.
150 pub spanning: bool,
151 /// The layer the fragment's own items paint in, from the
152 /// `z-index` of the block it came out of. A row carries the
153 /// layers of the table it is part of on its items, so this is not
154 /// read for one.
155 pub layer: i32,
156 /// How far `position: relative` moves what the fragment paints,
157 /// across and down, from the blocks it came out of. Nothing around
158 /// the fragment moves with it.
159 pub offset: (f32, f32),
160 /// How much of what the fragment paints shows, from 0 to 1: the
161 /// `opacity` of the blocks it came out of, multiplied together.
162 pub opacity: f32,
163}
164
165impl Fragment {
166 /// A fragment with nothing above it: what a block emits before
167 /// the margins and breaks around it are folded in.
168 pub(super) fn plain(x: f32, height: f32, piece: Piece) -> Fragment {
169 Fragment {
170 x,
171 lead: 0.0,
172 fixed: 0.0,
173 height,
174 break_before: BreakPoint::Allowed,
175 piece,
176 marks: None,
177 decorations: None,
178 markers: None,
179 notes: None,
180 reflow: None,
181 spanning: false,
182 layer: 0,
183 offset: (0.0, 0.0),
184 opacity: 1.0,
185 }
186 }
187}
188
189/// What one fragment does to the blocks decorated around it.
190///
191/// A decoration spans a range of fragments. The range is settled
192/// while the flow is built and the geometry is not: the paginator
193/// places fragments one at a time and moves what it has already
194/// painted when one carries to the next page. So the range travels on
195/// the fragments at its ends, and the paginator resolves it, per
196/// page, into a border box over the fragments that landed there.
197#[derive(Debug, Clone, Default)]
198pub struct Decorations {
199 /// The blocks whose first fragment this is, outermost first.
200 pub opens: Vec<Decoration>,
201 /// How many of the open blocks end with this fragment,
202 /// innermost first.
203 pub closes: u32,
204}
205
206/// One block: what it paints, and where it sits around the fragments
207/// it spans.
208#[derive(Debug, Clone)]
209pub struct Decoration {
210 /// The content node the block stands for.
211 pub node: NodeId,
212 /// Whether the block paints a background or a border. A block that
213 /// paints neither still has a border box to answer for.
214 pub paints: bool,
215 /// Leading edge of the border box, from the content box's own.
216 pub x: f32,
217 /// Width of the border box.
218 pub width: f32,
219 /// Distance from the top of the block's first fragment up to the
220 /// top of its border box.
221 pub above: f32,
222 /// Distance from the bottom of its last fragment down to the
223 /// bottom of its border box.
224 pub below: f32,
225 /// Border widths, zero on an edge that is not drawn.
226 pub border: Edges,
227 /// What each edge is painted in, `currentColor` resolved.
228 pub colors: Edges<Color>,
229 /// How far each corner of the border box is rounded, before the
230 /// box's own size is known.
231 pub radius: BorderRadius,
232 /// What is painted behind the whole border box: the tint, and
233 /// the image over it.
234 pub(super) backdrop: Backdrop,
235 /// Whether `box-decoration-break: clone` closes the two edges a
236 /// page break cuts.
237 pub cloned: bool,
238 /// The layer the border box paints in, from the block's
239 /// `z-index`.
240 pub layer: i32,
241 /// How far `position: relative` moves the border box, across and
242 /// down.
243 pub offset: (f32, f32),
244 /// How much of what the border box paints shows, from 0 to 1: the
245 /// `opacity` of the block and the blocks around it, multiplied
246 /// together.
247 pub opacity: f32,
248}
249
250/// What a fragment tells the page it lands on: the running strings
251/// its element set, and the folio its page restarts at.
252///
253/// Both are captured from the content flow, so both are answers only
254/// pagination has: which page a heading fell on is not known until it
255/// falls there.
256#[derive(Debug, Clone, Default, PartialEq)]
257pub struct Marks {
258 /// Named strings, resolved from the element's own text, in the
259 /// order the cascade gave them.
260 pub strings: Vec<(String, String)>,
261 /// The folio of the page this fragment lands on.
262 pub page_number: Option<u32>,
263 /// The nodes a link can reach that open on this fragment. The page
264 /// it lands on is the page a reference to one of them prints.
265 pub targets: Vec<crate::content::NodeId>,
266}
267
268/// Whether a block paints anything behind or around its content.
269pub(super) fn decorated(style: &ComputedStyle) -> bool {
270 style.background.paints() || style.border.paints()
271}
272
273/// The border box of one block, and what it paints there. `x` and
274/// `measure` are what the block was laid out against; the border box
275/// takes its margins off them. `backdrop` is what the cascade put
276/// behind it, resolved against the asset table. `offset` is the sum of
277/// the moves of the relative blocks around it, itself included, and
278/// `opacity` the product of their `opacity`, beside it.
279pub(super) fn decoration(
280 node: NodeId,
281 style: &ComputedStyle,
282 x: f32,
283 measure: f32,
284 backdrop: Backdrop,
285 (offset, opacity): ((f32, f32), f32),
286) -> Decoration {
287 let (left, width) = style.border_box(x, measure);
288 let border = style.border.widths();
289 let ink = |edge: crate::style::Border| edge.color.unwrap_or(style.color);
290 Decoration {
291 node,
292 paints: decorated(style),
293 x: left,
294 width,
295 above: 0.0,
296 below: 0.0,
297 border,
298 colors: Edges {
299 top: ink(style.border.top),
300 right: ink(style.border.right),
301 bottom: ink(style.border.bottom),
302 left: ink(style.border.left),
303 },
304 radius: style.border_radius,
305 backdrop,
306 cloned: style.box_decoration_break == BoxDecorationBreak::Clone,
307 layer: style.z_index,
308 offset,
309 opacity,
310 }
311}