1use collections::{FxHashMap, FxHashSet};
10use gpui_engine::{BoxedMeasureFn, EngineLayoutStyle, LayoutEngine, LayoutId, MeasureContext};
11use gpui_types::{
12 AvailableSpace, Bounds, Pixels, Point, Size, ceil_to_device_pixel, round_half_toward_zero,
13 round_to_device_pixel, size,
14};
15use taffy::{TaffyTree, TraversePartialTree as _, tree::NodeId};
16
17#[cfg(feature = "stacker")]
18type StackSafe<T> = stacksafe::StackSafe<T>;
19#[cfg(not(feature = "stacker"))]
20type StackSafe<T> = T;
21
22type NodeMeasureFn = StackSafe<BoxedMeasureFn>;
23
24struct NodeContext {
25 measure: NodeMeasureFn,
26}
27
28pub struct TaffyLayoutEngine {
30 taffy: TaffyTree<NodeContext>,
31 absolute_layout_bounds: FxHashMap<LayoutId, Bounds<Pixels>>,
32 absolute_outer_origins: FxHashMap<LayoutId, Point<f32>>,
34 computed_layouts: FxHashSet<LayoutId>,
35 layout_bounds_scratch_space: Vec<LayoutId>,
36}
37
38const EXPECT_MESSAGE: &str = "we should avoid taffy layout errors by construction if possible";
39
40pub fn default_layout_engine() -> Box<dyn LayoutEngine> {
42 Box::new(TaffyLayoutEngine::new())
43}
44
45fn taffy_id(id: LayoutId) -> NodeId {
46 NodeId::new(id.0)
47}
48
49fn layout_id(node_id: NodeId) -> LayoutId {
50 LayoutId(u64::from(node_id))
51}
52
53impl TaffyLayoutEngine {
54 pub fn new() -> Self {
56 let mut taffy = TaffyTree::new();
57 taffy.disable_rounding();
58 TaffyLayoutEngine {
59 taffy,
60 absolute_layout_bounds: FxHashMap::default(),
61 absolute_outer_origins: FxHashMap::default(),
62 computed_layouts: FxHashSet::default(),
63 layout_bounds_scratch_space: Vec::new(),
64 }
65 }
66
67 pub fn clear(&mut self) {
69 self.taffy.clear();
70 self.absolute_layout_bounds.clear();
71 self.absolute_outer_origins.clear();
72 self.computed_layouts.clear();
73 }
74
75 fn request_layout_taffy(
77 &mut self,
78 taffy_style: taffy::style::Style,
79 children: &[LayoutId],
80 ) -> LayoutId {
81 if children.is_empty() {
82 let node = self.taffy.new_leaf(taffy_style).expect(EXPECT_MESSAGE);
83 layout_id(node)
84 } else {
85 let child_ids: Vec<NodeId> = children.iter().copied().map(taffy_id).collect();
86 let node = self
87 .taffy
88 .new_with_children(taffy_style, &child_ids)
89 .expect(EXPECT_MESSAGE);
90 layout_id(node)
91 }
92 }
93
94 fn request_measured_layout_taffy(
96 &mut self,
97 taffy_style: taffy::style::Style,
98 measure: BoxedMeasureFn,
99 ) -> LayoutId {
100 #[cfg(feature = "stacker")]
101 let measure = StackSafe::new(measure);
102
103 let node = self
104 .taffy
105 .new_leaf_with_context(taffy_style, NodeContext { measure })
106 .expect(EXPECT_MESSAGE);
107 layout_id(node)
108 }
109
110 pub fn stretch_auto_size_to_fill(
117 &mut self,
118 id: LayoutId,
119 size: Size<Pixels>,
120 scale_factor: f32,
121 ) {
122 let style = self.taffy.style(taffy_id(id)).expect(EXPECT_MESSAGE);
123 let stretch_width = style.size.width.is_auto();
124 let stretch_height = style.size.height.is_auto();
125 if !stretch_width && !stretch_height {
126 return;
127 }
128 let mut style = style.clone();
129 if stretch_width {
130 style.size.width =
131 taffy::style::Dimension::length(round_to_device_pixel(size.width.0, scale_factor));
132 }
133 if stretch_height {
134 style.size.height =
135 taffy::style::Dimension::length(round_to_device_pixel(size.height.0, scale_factor));
136 }
137 self.taffy
138 .set_style(taffy_id(id), style)
139 .expect(EXPECT_MESSAGE);
140 }
141
142 #[allow(dead_code)]
144 fn count_all_children(&self, parent: LayoutId) -> anyhow::Result<u32> {
145 let mut count = 0;
146
147 for child in self.taffy.children(taffy_id(parent))? {
148 count += 1;
150
151 count += self.count_all_children(layout_id(child))?
153 }
154
155 Ok(count)
156 }
157
158 #[allow(dead_code)]
160 fn max_depth(&self, depth: u32, parent: LayoutId) -> anyhow::Result<u32> {
161 println!(
162 "{parent:?} at depth {depth} has {} children",
163 self.taffy.child_count(taffy_id(parent))
164 );
165
166 let mut max_child_depth = 0;
167
168 for child in self.taffy.children(taffy_id(parent))? {
169 max_child_depth = std::cmp::max(max_child_depth, self.max_depth(0, layout_id(child))?);
170 }
171
172 Ok(depth + 1 + max_child_depth)
173 }
174
175 #[allow(dead_code)]
177 fn get_edges(&self, parent: LayoutId) -> anyhow::Result<Vec<(LayoutId, LayoutId)>> {
178 let mut edges = Vec::new();
179
180 for child in self.taffy.children(taffy_id(parent))? {
181 edges.push((parent, layout_id(child)));
182
183 edges.extend(self.get_edges(layout_id(child))?);
184 }
185
186 Ok(edges)
187 }
188
189 #[cfg_attr(feature = "stacker", stacksafe::stacksafe)]
192 pub fn compute_layout(
193 &mut self,
194 id: LayoutId,
195 available_space: Size<AvailableSpace>,
196 scale_factor: f32,
197 context: &mut dyn MeasureContext,
198 ) {
199 if !self.computed_layouts.insert(id) {
200 let stack = &mut self.layout_bounds_scratch_space;
201 stack.push(id);
202 while let Some(id) = stack.pop() {
203 self.absolute_layout_bounds.remove(&id);
204 self.absolute_outer_origins.remove(&id);
205 stack.extend(
206 self.taffy
207 .children(taffy_id(id))
208 .expect(EXPECT_MESSAGE)
209 .into_iter()
210 .map(layout_id),
211 );
212 }
213 }
214
215 let transform = |v: AvailableSpace| match v {
216 AvailableSpace::Definite(pixels) => {
217 AvailableSpace::Definite(Pixels(pixels.0 * scale_factor))
218 }
219 AvailableSpace::MinContent => AvailableSpace::MinContent,
220 AvailableSpace::MaxContent => AvailableSpace::MaxContent,
221 };
222 let available_space = size(
223 transform(available_space.width),
224 transform(available_space.height),
225 );
226
227 self.taffy
228 .compute_layout_with_measure(
229 taffy_id(id),
230 available_space.into(),
231 |known_dimensions, available_space, _id, node_context, _style| {
232 let Some(node_context) = node_context else {
233 return taffy::geometry::Size::default();
234 };
235
236 let known_dimensions = Size {
237 width: known_dimensions.width.map(|e| Pixels(e / scale_factor)),
238 height: known_dimensions.height.map(|e| Pixels(e / scale_factor)),
239 };
240
241 let available_space: Size<AvailableSpace> = available_space.into();
242 let untransform = |ev: AvailableSpace| match ev {
243 AvailableSpace::Definite(pixels) => {
244 AvailableSpace::Definite(Pixels(pixels.0 / scale_factor))
245 }
246 AvailableSpace::MinContent => AvailableSpace::MinContent,
247 AvailableSpace::MaxContent => AvailableSpace::MaxContent,
248 };
249 let available_space = size(
250 untransform(available_space.width),
251 untransform(available_space.height),
252 );
253
254 let measured_size: Size<Pixels> =
255 (node_context.measure)(known_dimensions, available_space, context);
256 snap_measured_size_to_device_pixels(measured_size, scale_factor).into()
257 },
258 )
259 .expect(EXPECT_MESSAGE);
260 }
261
262 pub fn layout_bounds(&mut self, id: LayoutId, scale_factor: f32) -> Bounds<Pixels> {
339 if let Some(layout) = self.absolute_layout_bounds.get(&id).cloned() {
340 return layout;
341 }
342
343 let layout = self.taffy.layout(taffy_id(id)).expect(EXPECT_MESSAGE);
344 let layout_location = layout.location;
345 let layout_size = layout.size;
346 let parent = self.taffy.parent(taffy_id(id));
347
348 let absolute_outer_origin = match parent {
349 Some(parent_id) => {
350 let parent_id = layout_id(parent_id);
351 self.layout_bounds(parent_id, scale_factor);
352 let parent_origin = *self
353 .absolute_outer_origins
354 .get(&parent_id)
355 .expect("parent absolute outer origin should be cached");
356 parent_origin + Point::from(layout_location)
357 }
358 None => Point::from(layout_location),
359 };
360 self.absolute_outer_origins
361 .insert(id, absolute_outer_origin);
362
363 let absolute_far = absolute_outer_origin + Point::from(Size::from(layout_size));
364 let snapped_bounds = Bounds::from_corners(
365 absolute_outer_origin.map(round_half_toward_zero),
366 absolute_far.map(round_half_toward_zero),
367 );
368
369 let bounds = (snapped_bounds / scale_factor).map(Pixels);
370 self.absolute_layout_bounds.insert(id, bounds);
371 bounds
372 }
373}
374
375impl LayoutEngine for TaffyLayoutEngine {
376 fn clear(&mut self) {
377 TaffyLayoutEngine::clear(self)
378 }
379
380 fn request_layout(
381 &mut self,
382 style: &EngineLayoutStyle,
383 rem_size: Pixels,
384 scale_factor: f32,
385 children: &[LayoutId],
386 ) -> LayoutId {
387 let taffy_style = crate::layout_style::to_taffy_style(style, rem_size, scale_factor);
388 TaffyLayoutEngine::request_layout_taffy(self, taffy_style, children)
389 }
390
391 fn request_measured_layout(
392 &mut self,
393 style: &EngineLayoutStyle,
394 rem_size: Pixels,
395 scale_factor: f32,
396 measure: BoxedMeasureFn,
397 ) -> LayoutId {
398 let taffy_style = crate::layout_style::to_taffy_style(style, rem_size, scale_factor);
399 TaffyLayoutEngine::request_measured_layout_taffy(self, taffy_style, measure)
400 }
401
402 fn stretch_auto_size_to_fill(&mut self, id: LayoutId, size: Size<Pixels>, scale_factor: f32) {
403 TaffyLayoutEngine::stretch_auto_size_to_fill(self, id, size, scale_factor)
404 }
405
406 fn compute_layout(
407 &mut self,
408 id: LayoutId,
409 available_space: Size<AvailableSpace>,
410 scale_factor: f32,
411 context: &mut dyn MeasureContext,
412 ) {
413 TaffyLayoutEngine::compute_layout(self, id, available_space, scale_factor, context)
414 }
415
416 fn layout_bounds(&mut self, id: LayoutId, scale_factor: f32) -> Bounds<Pixels> {
417 TaffyLayoutEngine::layout_bounds(self, id, scale_factor)
418 }
419}
420
421fn snap_measured_size_to_device_pixels(size: Size<Pixels>, scale_factor: f32) -> Size<f32> {
422 size.map(|d| ceil_to_device_pixel(d.0.max(0.0), scale_factor))
423}