tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 231Rust 8TOML 3CSS 1317 Sutichaykuna

⎇ cbd5d1dc7ea905f0672192f034a7793c66529448 src/tree/layout.rs Rust · 163 siq'ikuna · 6.1 KB Ñawpa willay Pi imata llamkarqan ch'uya

Minor: changed docs for Layout::location (bottom-left -> top-left) & added test (#500) cbd5d1dc7 · Yurii Nakonechnyi ·

1//! Final data structures that represent the high-level UI layout
2
3use crate::{
4    geometry::{Point, Size},
5    util::sys::{f32_max, f32_min},
6};
7
8/// Whether we are performing a full layout, or we merely need to size the node
9#[derive(Copy, Clone, Debug, PartialEq, Eq)]
10pub enum RunMode {
11    /// A full layout for this node and all children should be computed
12    PerformLayout,
13    /// The layout algorithm should be executed such that an accurate container size for the node can be determined.
14    /// Layout steps that aren't necessary for determining the container size of the current node can be skipped.
15    ComputeSize,
16}
17
18/// Whether styles should be taken into account when computing size
19#[derive(Copy, Clone, Debug, PartialEq, Eq)]
20pub enum SizingMode {
21    /// Only content contributions should be taken into account
22    ContentSize,
23    /// Inherent size styles should be taken into account in addition to content contributions
24    InherentSize,
25}
26
27/// A set of margins that are available for collapsing with for block layout's margin collapsing
28#[derive(Copy, Clone, Debug, PartialEq)]
29pub struct CollapsibleMarginSet {
30    /// The largest positive margin
31    positive: f32,
32    /// The smallest negative margin (with largest absolute value)
33    negative: f32,
34}
35
36impl CollapsibleMarginSet {
37    /// A default margin set with no collapsible margins
38    pub const ZERO: Self = Self { positive: 0.0, negative: 0.0 };
39
40    /// Create a set from a single margin
41    pub fn from_margin(margin: f32) -> Self {
42        if margin >= 0.0 {
43            Self { positive: margin, negative: 0.0 }
44        } else {
45            Self { positive: 0.0, negative: margin }
46        }
47    }
48
49    /// Collapse a single margin with this set
50    pub fn collapse_with_margin(mut self, margin: f32) -> Self {
51        if margin >= 0.0 {
52            self.positive = f32_max(self.positive, margin);
53        } else {
54            self.negative = f32_min(self.negative, margin);
55        }
56        self
57    }
58
59    /// Collapse another margin set with this set
60    pub fn collapse_with_set(mut self, other: CollapsibleMarginSet) -> Self {
61        self.positive = f32_max(self.positive, other.positive);
62        self.negative = f32_min(self.negative, other.negative);
63        self
64    }
65
66    /// Resolve the resultant margin from this set once all collapsible margins
67    /// have been collapsed into it
68    pub fn resolve(&self) -> f32 {
69        self.positive + self.negative
70    }
71}
72
73/// A struct containing both the size of a node and it's first baseline in each dimension (if it has any)
74///
75/// A baseline is the line on which text sits. Your node likely has a baseline if it is a text node, or contains
76/// children that may be text nodes. See <https://www.w3.org/TR/css-writing-modes-3/#intro-baselines> for details.
77/// If your node does not have a baseline (or you are unsure how to compute it), then simply return `Point::NONE`
78/// for the first_baselines field
79#[derive(Debug, Copy, Clone)]
80pub struct SizeBaselinesAndMargins {
81    /// The size of the node
82    pub size: Size<f32>,
83    /// The first baseline of the node in each dimension, if any
84    pub first_baselines: Point<Option<f32>>,
85    /// Top margin that can be collapsed with. This is used for CSS block layout and can be set to
86    /// `CollapsibleMarginSet::ZERO` for other layout modes that don't support margin collapsing
87    pub top_margin: CollapsibleMarginSet,
88    /// Bottom margin that can be collapsed with. This is used for CSS block layout and can be set to
89    /// `CollapsibleMarginSet::ZERO` for other layout modes that don't support margin collapsing
90    pub bottom_margin: CollapsibleMarginSet,
91    /// Whether margins can be collapsed through this node. This is used for CSS block layout and can
92    /// be set to `false` for other layout modes that don't support margin collapsing
93    pub margins_can_collapse_through: bool,
94}
95
96impl SizeBaselinesAndMargins {
97    /// An all-zero `SizeBaselinesAndMargins` for hidden nodes
98    pub const HIDDEN: Self = Self {
99        size: Size::ZERO,
100        first_baselines: Point::NONE,
101        top_margin: CollapsibleMarginSet::ZERO,
102        bottom_margin: CollapsibleMarginSet::ZERO,
103        margins_can_collapse_through: false,
104    };
105
106    /// Constructor to create a `SizeBaselinesAndMargins` from just the size and baselines
107    pub fn from_size_and_baselines(size: Size<f32>, first_baselines: Point<Option<f32>>) -> Self {
108        Self {
109            size,
110            first_baselines,
111            top_margin: CollapsibleMarginSet::ZERO,
112            bottom_margin: CollapsibleMarginSet::ZERO,
113            margins_can_collapse_through: false,
114        }
115    }
116}
117
118impl From<Size<f32>> for SizeBaselinesAndMargins {
119    fn from(size: Size<f32>) -> Self {
120        Self {
121            size,
122            first_baselines: Point::NONE,
123            top_margin: CollapsibleMarginSet::ZERO,
124            bottom_margin: CollapsibleMarginSet::ZERO,
125            margins_can_collapse_through: false,
126        }
127    }
128}
129
130/// The final result of a layout algorithm for a single node.
131#[derive(Debug, Copy, Clone)]
132pub struct Layout {
133    /// The relative ordering of the node
134    ///
135    /// Nodes with a higher order should be rendered on top of those with a lower order.
136    /// This is effectively a topological sort of each tree.
137    pub order: u32,
138    /// The width and height of the node
139    pub size: Size<f32>,
140    /// The top-left corner of the node
141    pub location: Point<f32>,
142}
143
144impl Layout {
145    /// Creates a new zero-[`Layout`].
146    ///
147    /// The Zero-layout has size and location set to ZERO.
148    /// The `order` value of this layout is set to the minimum value of 0.
149    /// This means it should be rendered below all other [`Layout`]s.
150    #[must_use]
151    pub const fn new() -> Self {
152        Self { order: 0, size: Size::zero(), location: Point::ZERO }
153    }
154
155    /// Creates a new zero-[`Layout`] with the supplied `order` value.
156    ///
157    /// Nodes with a higher order should be rendered on top of those with a lower order.
158    /// The Zero-layout has size and location set to ZERO.
159    #[must_use]
160    pub const fn with_order(order: u32) -> Self {
161        Self { order, size: Size::zero(), location: Point::ZERO }
162    }
163}