⎇ 67f286f3666b621ef5ee2e1a1fbfb40a1084349e
src/tree/layout.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
Minor: changed docs for Layout::location (bottom-left -> top-left) & added test (#500)
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}