gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 709HTML 662Markdown 12TOML 62348 Definitions

⎇ daa07e0f4e3e009f5b0c11ada5df9785efd4b2c2 src/tree/layout.rs Rust · 187 lines · 7.5 KB History Who touched what raw

Remove `LayoutAlgorithm` trait (#562) daa07e0f4 · Nico Burns ·

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