⎇ df46fcf3630e2e8f4ea2c99bbe261154383a4aab
tests/hand_written/float_clearance.rs
Historia
Quién tocó qué
crudo
Fix clearance calculation and its interaction with margin collapsing
1//! Regression tests for clearance calculation and its interaction with margin collapsing.
2//!
3//! Scenarios are reduced from WPT tests in css/CSS2/floats-clear and css/CSS2/floats.
4use taffy::prelude::*;
5use taffy::{Clear, Float, Overflow, Point};
6
7fn block(tree: &mut TaffyTree<()>, style: Style, children: &[NodeId]) -> NodeId {
8 tree.new_with_children(Style { display: Display::Block, ..style }, children).unwrap()
9}
10
11fn assert_layout(tree: &TaffyTree<()>, node: NodeId, x: f32, y: f32, width: f32, height: f32) {
12 let layout = tree.layout(node).unwrap();
13 assert_eq!(layout.location.x, x, "x of {node:?}");
14 assert_eq!(layout.location.y, y, "y of {node:?}");
15 assert_eq!(layout.size.width, width, "width of {node:?}");
16 assert_eq!(layout.size.height, height, "height of {node:?}");
17}
18
19/// Reduced from WPT css/CSS2/floats-clear/clear-002.xht
20///
21/// A cleared float should clear past prior floats, but `clear` on the first float
22/// (with no prior floats on the relevant side) should not move it down.
23#[test]
24fn clear_on_float_with_and_without_preceding_float() {
25 let t = &mut TaffyTree::new();
26 let f1 = block(
27 t,
28 Style { float: Float::Right, size: Size { width: length(96.0), height: length(96.0) }, ..Default::default() },
29 &[],
30 );
31 let f2 = block(
32 t,
33 Style {
34 float: Float::Right,
35 clear: Clear::Right,
36 size: Size { width: length(96.0), height: length(96.0) },
37 ..Default::default()
38 },
39 &[],
40 );
41 let container =
42 block(t, Style { size: Size { width: length(500.0), height: auto() }, ..Default::default() }, &[f1, f2]);
43 t.compute_layout(container, Size::MAX_CONTENT).unwrap();
44
45 assert_layout(t, f1, 404.0, 0.0, 96.0, 96.0);
46 assert_layout(t, f2, 404.0, 96.0, 96.0, 96.0);
47}
48
49/// Reduced from WPT css/CSS2/floats-clear/clear-clearance-calculation-004.xht
50///
51/// When the hypothetical position of a cleared block (with its top margin) is already
52/// past the bottom of the float, negative clearance keeps it at the float's bottom edge.
53#[test]
54fn negative_clearance_from_large_top_margin() {
55 let t = &mut TaffyTree::new();
56 let first = block(
57 t,
58 Style {
59 size: Size { width: auto(), height: length(25.0) },
60 margin: Rect { bottom: length(25.0), ..Rect::zero() },
61 ..Default::default()
62 },
63 &[],
64 );
65 let float = block(
66 t,
67 Style { float: Float::Left, size: Size { width: length(50.0), height: length(50.0) }, ..Default::default() },
68 &[],
69 );
70 let last = block(
71 t,
72 Style {
73 clear: Clear::Left,
74 margin: Rect { top: length(75.0), ..Rect::zero() },
75 size: Size { width: auto(), height: length(50.0) },
76 ..Default::default()
77 },
78 &[],
79 );
80 let container = block(
81 t,
82 Style { size: Size { width: length(300.0), height: auto() }, ..Default::default() },
83 &[first, float, last],
84 );
85 t.compute_layout(container, Size::MAX_CONTENT).unwrap();
86
87 assert_layout(t, float, 0.0, 50.0, 50.0, 50.0);
88 assert_layout(t, last, 0.0, 100.0, 300.0, 50.0);
89 assert_layout(t, container, 0.0, 0.0, 300.0, 150.0);
90}
91
92/// Reduced from WPT css/CSS2/floats-clear/clear-with-top-margin-after-cleared-empty-block.html
93///
94/// Clearance on a self-collapsing block suppresses margin collapsing with following
95/// siblings, and a following cleared sibling with a large top margin gets no clearance.
96#[test]
97fn clear_with_top_margin_after_cleared_empty_block() {
98 let t = &mut TaffyTree::new();
99 let float = block(
100 t,
101 Style { float: Float::Left, size: Size { width: length(100.0), height: length(20.0) }, ..Default::default() },
102 &[],
103 );
104 let c1 = block(t, Style { clear: Clear::Both, ..Default::default() }, &[]);
105 let c2 = block(
106 t,
107 Style {
108 clear: Clear::Both,
109 margin: Rect { top: length(100.0), ..Rect::zero() },
110 size: Size { width: auto(), height: length(20.0) },
111 ..Default::default()
112 },
113 &[],
114 );
115 let container = block(
116 t,
117 Style {
118 size: Size { width: length(100.0), height: auto() },
119 border: Rect { top: length(1.0), ..Rect::zero() },
120 ..Default::default()
121 },
122 &[float, c1, c2],
123 );
124 t.compute_layout(container, Size::MAX_CONTENT).unwrap();
125
126 assert_layout(t, c1, 0.0, 21.0, 100.0, 0.0);
127 assert_layout(t, c2, 0.0, 121.0, 100.0, 20.0);
128 assert_layout(t, container, 0.0, 0.0, 100.0, 141.0);
129}
130
131/// Reduced from WPT css/CSS2/floats/new-fc-separates-from-float.html
132///
133/// A block establishing a new formatting context that does not fit beside a float is
134/// pushed below it, and its top margin no longer collapses with preceding margins
135/// (so the float, which adjoins the unresolved margin strut, does not move down).
136#[test]
137fn new_fc_separates_from_float() {
138 let t = &mut TaffyTree::new();
139 let float = block(
140 t,
141 Style { float: Float::Left, size: Size { width: length(200.0), height: length(200.0) }, ..Default::default() },
142 &[],
143 );
144 let inner = block(t, Style::default(), &[float]);
145 let bfc = block(
146 t,
147 Style {
148 overflow: Point { x: Overflow::Hidden, y: Overflow::Hidden },
149 margin: Rect { top: length(200.0), ..Rect::zero() },
150 size: Size { width: length(200.0), height: length(1.0) },
151 ..Default::default()
152 },
153 &[],
154 );
155 let mid = block(t, Style::default(), &[inner, bfc]);
156 let container = block(
157 t,
158 Style {
159 overflow: Point { x: Overflow::Hidden, y: Overflow::Hidden },
160 size: Size { width: length(200.0), height: auto() },
161 ..Default::default()
162 },
163 &[mid],
164 );
165 t.compute_layout(container, Size::MAX_CONTENT).unwrap();
166
167 assert_layout(t, mid, 0.0, 0.0, 200.0, 201.0);
168 assert_layout(t, float, 0.0, 0.0, 200.0, 200.0);
169 assert_layout(t, bfc, 0.0, 200.0, 200.0, 1.0);
170 assert_layout(t, container, 0.0, 0.0, 200.0, 201.0);
171}
172
173/// Reduced from WPT css/CSS2/floats-clear/margin-collapse-clear-013.xht
174///
175/// The top and bottom margins of a self-collapsing block with clearance collapse with
176/// each other and are applied inside the parent (they do not collapse with the parent's
177/// bottom margin).
178#[test]
179fn self_collapsing_block_with_clearance_margins() {
180 let t = &mut TaffyTree::new();
181 let float = block(
182 t,
183 Style { float: Float::Left, size: Size { width: length(100.0), height: length(100.0) }, ..Default::default() },
184 &[],
185 );
186 let cleared = block(
187 t,
188 Style {
189 clear: Clear::Left,
190 margin: Rect { top: length(40.0), bottom: length(140.0), ..Rect::zero() },
191 ..Default::default()
192 },
193 &[],
194 );
195 let parent = block(t, Style::default(), &[float, cleared]);
196 let next = block(t, Style { size: Size { width: auto(), height: length(100.0) }, ..Default::default() }, &[]);
197 let root =
198 block(t, Style { size: Size { width: length(300.0), height: auto() }, ..Default::default() }, &[parent, next]);
199 t.compute_layout(root, Size::MAX_CONTENT).unwrap();
200
201 assert_layout(t, cleared, 0.0, 100.0, 300.0, 0.0);
202 assert_layout(t, parent, 0.0, 0.0, 300.0, 200.0);
203 assert_layout(t, next, 0.0, 200.0, 300.0, 100.0);
204}