Skip to main content

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}