rustyfi_backend/vbox.rs
1use crate::hbox::{DecoId, HookId, PureHorzBox};
2use crate::length::Length;
3
4/// A milestone-1 subset of `vert_box`: a typeset line or vertical space.
5///
6/// See [`crate::hbox::PureHorzBox`] for what the `#[subast]` list means and
7/// what checks it.
8#[derive(Clone, Debug, PartialEq, syan::visit::Ast)]
9#[subast(crate::hbox::PureHorzBox)]
10pub enum VertBox {
11 /// One typeset line: boxes with their x offsets from the line start.
12 Line {
13 height: Length,
14 depth: Length,
15 /// Baseline-to-baseline distance to the *next* line: the `leading`
16 /// a `context` was set to when this line was assembled. `page-break`
17 /// takes no context, so the property rides the line itself, set by
18 /// `break_into_lines` from `ctx.leading`.
19 leading: Length,
20 contents: Vec<(Length, PureHorzBox)>,
21 },
22 /// Fixed vertical space (`block-skip`, frame padding, a paragraph's
23 /// *bottom* margin) — NOT padded by `min_first_line_ascender`.
24 Skip(Length),
25 /// A paragraph's TOP margin (`prim_line_break` prepends this from
26 /// `ctx.paragraph_top`). Distinguished from `Skip` because SATySFi pads
27 /// only the paragraph `margin_top` up to `min_first_line_ascender`
28 /// (`lineBreak.ml:857`) — `block-skip`s and frame pads get no such pad.
29 /// Accumulates into `pending_skip` exactly like `Skip`; the difference is
30 /// only that its presence enables the ascender pad on the following line.
31 ParagTop(Length),
32 /// A `block-frame-breakable` frame's internal top/bottom padding. Unlike
33 /// `Skip` (a margin, which max-COLLAPSES with adjacent margins), frame
34 /// padding is ADDITIVE — SATySFi adds it to the running height inside the
35 /// frame (`pageBreak.ml:323` `hgttotal +% pads.paddingT`, `:380`
36 /// `+% pads.paddingB`), so it stacks ON TOP of the surrounding
37 /// paragraph margin rather than being absorbed by it.
38 FramePad(Length),
39 /// `clear-page`'s marker (`primitives.cppo.ml`'s `VertClearPage`,
40 /// `horzBox.ml:346`) — forces the current page to end right here:
41 /// `chop_page` closes the page as soon as at least one real `Line` has
42 /// been placed, leaving everything from this marker onward for the next
43 /// page. Contributes zero height (`measure_block`), mirroring
44 /// `pageBreak.ml`'s `PBClearPage` (`solidify`'s
45 /// `ImVertFixedEmpty(Fixed, Length.zero)`).
46 ClearPage,
47 /// `hook-page-break-block`'s marker (`vminst.ml:632`
48 /// `BackendHookPageBreakBlock` / `horzBox.ml:347`'s `VertHookPageBreak`)
49 /// — the block-level analog of `PureHorzBox::HookPageBreak`: an opaque
50 /// index into a lang-side hook table, fired by `fire_hooks` with the
51 /// page's `pbinfo` and the point where it sits in the flow. Contributes
52 /// zero height, same as `ClearPage`.
53 HookPageBreak(HookId),
54 /// `block-frame-breakable`'s frame-extent markers: the frame's
55 /// indented contents sit between a `FrameStart(id)`/`FrameEnd(id)` pair;
56 /// `chop_page`/`place_block_at` place each as a zero-height marker
57 /// `PlacedLine` (the `HookPageBreak` pattern) and `fire_hooks` derives
58 /// each page fragment's rect from the real lines between them. The
59 /// frame's pads/width/deco-set live lang-side (`DecoEntry::Block`).
60 FrameStart(DecoId),
61 FrameEnd(DecoId),
62 /// an INERT reflow marker for list (`itemize`/`enumerate`) structure,
63 /// emitted by the `list-mark` primitive from
64 /// `lib-rustyfi/dist-v01/packages/itemize.satyh`'s
65 /// `listing`/`listing-item`/`listing-item-breakable`/`enumerate`/
66 /// `enumerate-item`. Zero height/depth, contributes nothing to any
67 /// measurement (`measure_block`) or placement (`chop_page`/
68 /// `place_block_at`) — it never reaches a `PlacedLine`, so PDF and
69 /// faithful HTML are byte-identical whether or not a document's stdlib
70 /// emits these. Read only by the reflow HTML walker (the `html-support`
71 /// branch's `rustyfi-html/src/reflow/block.rs`'s `walk_vboxes`), which
72 /// uses the Start/End nesting to rebuild real `<ul>`/`<ol>`/`<li>`
73 /// structure.
74 ListMark(ListMarkKind),
75}
76
77/// The marker kind a `VertBox::ListMark` carries. `ordered` on `ListStart`
78/// is the ONE piece of real data these markers carry (`listing` vs
79/// `enumerate` are distinct stdlib commands, so this is an exact bit, not a
80/// heuristic); nesting depth is recovered structurally by the reflow
81/// walker's stack from how markers are nested in the flat box stream, not
82/// stored here.
83#[derive(Clone, Copy, Debug, PartialEq, Eq)]
84pub enum ListMarkKind {
85 /// Opens a `<ul>` (`ordered = false`) or `<ol>` (`ordered = true`).
86 ListStart { ordered: bool },
87 /// Closes the innermost open list.
88 ListEnd,
89 /// Opens one `<li>`.
90 ItemStart,
91 /// Closes the innermost open `<li>`.
92 ItemEnd,
93}