Skip to main content

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}