Skip to main content

kozan_core/layout/inline/
item.rs

1//! Inline item — the atomic unit of inline layout.
2//!
3//! Chrome equivalent: `NGInlineItem`. A flat list of items representing
4//! the inline content of a block container.
5//!
6//! The flat list is a deliberate Chrome optimization — not a tree.
7//! It's cache-friendly and fast to iterate during line breaking.
8
9use std::sync::Arc;
10use style::properties::ComputedValues;
11
12/// Stylo Arc for computed styles.
13type StyleArc<T> = servo_arc::Arc<T>;
14
15/// An item in the inline formatting context.
16///
17/// Chrome equivalent: `NGInlineItem` with its type.
18#[derive(Debug, Clone)]
19pub enum InlineItem {
20    /// A text run — a segment of text with uniform style.
21    /// The text will be shaped (future: via Parley/harfrust).
22    Text {
23        /// The text content.
24        content: Arc<str>,
25        /// Style for this text (font, color, etc.).
26        style: StyleArc<ComputedValues>,
27        /// Measured width (set during shaping/measurement).
28        measured_width: f32,
29        /// Measured height (ascent + descent).
30        measured_height: f32,
31        /// Baseline offset from top.
32        baseline: f32,
33    },
34
35    /// Open tag — start of an inline element (e.g., `<span>`).
36    /// Chrome: `kOpenTag`.
37    OpenTag {
38        style: StyleArc<ComputedValues>,
39        /// Inline margin/border/padding on the start side.
40        margin_inline_start: f32,
41        border_inline_start: f32,
42        padding_inline_start: f32,
43    },
44
45    /// Close tag — end of an inline element.
46    /// Chrome: `kCloseTag`.
47    CloseTag {
48        /// Inline margin/border/padding on the end side.
49        margin_inline_end: f32,
50        border_inline_end: f32,
51        padding_inline_end: f32,
52    },
53
54    /// An atomic inline — an inline-block, replaced element (img), etc.
55    /// These are measured as a single unit and cannot be broken across lines.
56    AtomicInline {
57        /// The fragment produced by laying out this atomic inline.
58        width: f32,
59        height: f32,
60        baseline: f32,
61        /// Index into the layout tree.
62        layout_id: u32,
63        /// Style for this atomic inline (vertical-align, etc.).
64        style: StyleArc<ComputedValues>,
65    },
66
67    /// A forced line break (`<br>`).
68    ForcedBreak,
69}
70
71impl InlineItem {
72    /// Get the inline size (width) of this item.
73    #[must_use]
74    pub fn inline_size(&self) -> f32 {
75        match self {
76            InlineItem::Text { measured_width, .. } => *measured_width,
77            InlineItem::OpenTag {
78                margin_inline_start,
79                border_inline_start,
80                padding_inline_start,
81                ..
82            } => margin_inline_start + border_inline_start + padding_inline_start,
83            InlineItem::CloseTag {
84                margin_inline_end,
85                border_inline_end,
86                padding_inline_end,
87                ..
88            } => margin_inline_end + border_inline_end + padding_inline_end,
89            InlineItem::AtomicInline { width, .. } => *width,
90            InlineItem::ForcedBreak => 0.0,
91        }
92    }
93
94    /// Whether this item forces a line break.
95    #[must_use]
96    pub fn is_forced_break(&self) -> bool {
97        matches!(self, InlineItem::ForcedBreak)
98    }
99
100    /// Whether this item is breakable (text can be split across lines).
101    #[must_use]
102    pub fn is_breakable(&self) -> bool {
103        matches!(self, InlineItem::Text { .. })
104    }
105}