Skip to main content

gpui/
taffy.rs

1use crate::{
2    AbsoluteLength, App, Bounds, DefiniteLength, Display, Edges, GridTemplate, InlineContent,
3    LayoutDirection, Length, Pixels, Point, Position, ResolvedDirection, SharedString, Size, Style,
4    UnicodeBidi, VerticalAlign, Window, size,
5    util::{
6        ceil_to_device_pixel, round_half_toward_zero, round_stroke_to_device_pixel,
7        round_to_device_pixel,
8    },
9};
10use std::{
11    any::Any,
12    cell::{Cell, OnceCell, RefCell},
13    fmt::Debug,
14    ops::Range,
15    rc::Rc,
16    sync::Arc,
17};
18use taffy::{
19    BlockContext, Cache, CacheTree, Layout, LayoutBlockContainer, LayoutFlexboxContainer,
20    LayoutGridContainer, LayoutInput, LayoutOutput, LayoutPartialTree, RunMode,
21    TraversePartialTree, compute_block_layout, compute_cached_layout, compute_flexbox_layout,
22    compute_grid_layout, compute_hidden_layout, compute_leaf_layout, compute_root_layout,
23    geometry::{Point as TaffyPoint, Rect as TaffyRect, Size as TaffySize},
24    prelude::{max_content, min_content},
25    style::AvailableSpace as TaffyAvailableSpace,
26    tree::NodeId,
27};
28
29#[cfg(feature = "stacker")]
30type StackSafe<T> = stacksafe::StackSafe<T>;
31#[cfg(not(feature = "stacker"))]
32type StackSafe<T> = T;
33
34type MeasureFn =
35    dyn FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>;
36type NodeMeasureFn = StackSafe<Box<MeasureFn>>;
37
38/// What a measured node's size depends on, besides the space it's measured in. When a view
39/// renders again, a measured node whose key matches the one its predecessor had keeps that node's
40/// layout, so it isn't measured again.
41pub(crate) trait MeasureKey: Any {
42    /// Whether a node with this key measures the same as the node that had `previous`.
43    fn same(&self, previous: &dyn MeasureKey) -> bool;
44
45    /// Takes over what the element of the node with `previous` measured, since this node won't be
46    /// measured. Without it, the element's measure function runs once, with the last sizes.
47    fn inherit(&self, _previous: &dyn MeasureKey) -> bool {
48        false
49    }
50
51    fn as_any(&self) -> &dyn Any;
52}
53
54#[derive(Clone)]
55pub(crate) struct LayoutDirectionHandle(Rc<Cell<ResolvedDirection>>);
56
57impl LayoutDirectionHandle {
58    pub(crate) fn get(&self) -> ResolvedDirection {
59        self.0.get()
60    }
61}
62
63struct DirectionMetadata {
64    authored: LayoutDirection,
65    unicode_bidi: UnicodeBidi,
66    source_direction: Option<ResolvedDirection>,
67    auto_direction_hint: Option<ResolvedDirection>,
68    logical_children: Option<Vec<LayoutId>>,
69    resolved: ResolvedDirection,
70    /// Shared with [`LayoutDirectionHandle`]s, made when the first one is requested.
71    handle: OnceCell<Rc<Cell<ResolvedDirection>>>,
72}
73
74enum NodeKind {
75    Plain,
76    Measured(NodeMeasureFn),
77    /// Stands in for another view's island. Layout delegates to the island's root, and the
78    /// island hangs off this node when positions are read.
79    Proxy {
80        island: IslandId,
81        style: Option<Box<taffy::Style>>,
82    },
83}
84
85struct Node {
86    style: taffy::Style,
87    children: Vec<NodeId>,
88    parent: Option<LayoutId>,
89    cache: Cache,
90    layout: Layout,
91    kind: NodeKind,
92    vertical_align: VerticalAlign,
93    display: Display,
94    position: Position,
95    direction: DirectionMetadata,
96    inline_content: Option<Arc<InlineContent>>,
97    inline_fragments: Option<Arc<[Bounds<Pixels>]>>,
98    /// An absolute position assigned by an inline formatting context instead of by Taffy.
99    placed: Option<(Point<f32>, Bounds<Pixels>)>,
100    /// Absolute outer origin in device pixels and snapped bounds, valid for `bounds_epoch`.
101    bounds: Option<(u64, Point<f32>, Bounds<Pixels>)>,
102    /// Whether the node kept the layout of the node at its place in the view's previous render,
103    /// because nothing that affects its layout changed.
104    inherited: bool,
105    /// The key of a measured node. Measured nodes without one are always measured again.
106    measure_key: Option<Box<dyn MeasureKey>>,
107    /// The known and available sizes of the last measurement.
108    last_measure: Option<(Size<Option<Pixels>>, Size<AvailableSpace>)>,
109    /// Whether the node's measure function ran since the node was created.
110    measured: bool,
111}
112
113/// The id of a layout island: the nodes one view (or the window itself) requested.
114pub(crate) type IslandId = u32;
115
116/// The window's own island, for nodes requested outside any view. Cleared every frame.
117const WINDOW_ISLAND: IslandId = 0;
118
119#[derive(Default)]
120struct Island {
121    nodes: Vec<Node>,
122    /// The nodes of the render before the one in progress, which new nodes inherit layout from.
123    previous: Vec<Node>,
124    /// Whether the island rendered this frame into a layout different from the last one.
125    changed: bool,
126    root: Option<LayoutId>,
127    /// The node in the parent island whose position this island's root takes.
128    anchor: Option<LayoutId>,
129    /// The inherited direction this island was last resolved with.
130    resolved_with: Option<ResolvedDirection>,
131}
132
133/// Keeps a view's island alive. Dropping it (with the view's element state) frees the island
134/// at the end of the frame.
135pub(crate) struct LayoutIsland {
136    id: IslandId,
137    released: Rc<RefCell<Vec<IslandId>>>,
138}
139
140impl LayoutIsland {
141    pub(crate) fn id(&self) -> IslandId {
142        self.id
143    }
144}
145
146impl Drop for LayoutIsland {
147    fn drop(&mut self) {
148        self.released.borrow_mut().push(self.id);
149    }
150}
151
152/// Computes element layout with Taffy, a flexbox and grid engine.
153///
154/// Nodes live in islands. Each view keeps its own island across frames, so a view that didn't
155/// change keeps its laid-out nodes, and its parent reaches it through a single proxy node. Nodes
156/// requested outside any view live in the window's island, which is cleared every frame. Window
157/// code creates nodes with [`Self::request_layout`] or [`Self::request_measured_layout`], calls
158/// [`Self::compute_layout`] on a root and reads positions with [`Self::layout_bounds`].
159pub struct TaffyLayoutEngine {
160    islands: Vec<Island>,
161    free_islands: Vec<IslandId>,
162    released: Rc<RefCell<Vec<IslandId>>>,
163    current: Vec<IslandId>,
164    computed_available_spaces: Vec<(LayoutId, Size<AvailableSpace>)>,
165    bounds_epoch: u64,
166    /// Islands rendered this frame.
167    rendered: Vec<IslandId>,
168    /// Measured nodes that inherited a layout, which must give their elements the measurement
169    /// they would have made.
170    replays: Vec<LayoutId>,
171}
172
173impl TaffyLayoutEngine {
174    /// Creates an engine with no nodes.
175    pub fn new() -> Self {
176        TaffyLayoutEngine {
177            islands: vec![Island::default()],
178            free_islands: Vec::new(),
179            released: Rc::default(),
180            current: vec![WINDOW_ISLAND],
181            computed_available_spaces: Vec::new(),
182            bounds_epoch: 0,
183            rendered: Vec::new(),
184            replays: Vec::new(),
185        }
186    }
187
188    /// Ends a frame: clears the window's island and frees the islands of views that were dropped.
189    ///
190    /// Ids of nodes in the window's island are invalid afterwards. View islands persist.
191    pub fn clear(&mut self) {
192        self.islands[WINDOW_ISLAND as usize] = Island::default();
193        for id in self.released.borrow_mut().drain(..) {
194            self.islands[id as usize] = Island::default();
195            self.free_islands.push(id);
196        }
197        debug_assert_eq!(self.current, [WINDOW_ISLAND]);
198        for island in self.rendered.drain(..) {
199            self.islands[island as usize].changed = false;
200        }
201        self.replays.clear();
202        self.computed_available_spaces.clear();
203        self.bounds_epoch += 1;
204    }
205
206    /// Creates an empty island for a view.
207    pub(crate) fn create_island(&mut self) -> LayoutIsland {
208        let id = self.free_islands.pop().unwrap_or_else(|| {
209            self.islands.push(Island::default());
210            (self.islands.len() - 1) as IslandId
211        });
212        LayoutIsland {
213            id,
214            released: self.released.clone(),
215        }
216    }
217
218    /// Clears `island` and sends node requests into it until [`Self::end_island`]. Nodes that
219    /// match the island's previous nodes keep their layout.
220    pub(crate) fn begin_island(&mut self, island: IslandId) {
221        let island_state = &mut self.islands[island as usize];
222        // Swap the buffers so both keep their capacity across renders.
223        std::mem::swap(&mut island_state.previous, &mut island_state.nodes);
224        island_state.nodes.clear();
225        island_state.root = None;
226        island_state.resolved_with = None;
227        island_state.changed = true;
228        self.rendered.push(island);
229        self.current.push(island);
230    }
231
232    pub(crate) fn end_island(&mut self) {
233        if let Some(island) = self.current.pop() {
234            self.islands[island as usize].previous.clear();
235        }
236    }
237
238    pub(crate) fn set_island_root(&mut self, island: IslandId, root: LayoutId) {
239        debug_assert_eq!(root.island(), island);
240        let inherited = self.node(root).inherited;
241        let island = &mut self.islands[island as usize];
242        island.root = Some(root);
243        island.changed = !inherited;
244    }
245
246    /// Adds a node to the current island that lays out `island`'s root in its place.
247    pub(crate) fn request_island(&mut self, island: IslandId) -> LayoutId {
248        let id = self.push_node(
249            taffy::Style::default(),
250            &[],
251            NodeKind::Proxy {
252                island,
253                style: None,
254            },
255            None,
256            &Style::default(),
257        );
258        self.islands[island as usize].anchor = Some(id);
259        id
260    }
261
262    /// Hangs `island` off `anchor`, a node laid out at the island root's position and size.
263    pub(crate) fn anchor_island(&mut self, island: IslandId, anchor: LayoutId) {
264        self.islands[island as usize].anchor = Some(anchor);
265    }
266
267    fn root_style(&self, island: IslandId) -> Option<&taffy::Style> {
268        let root = self.islands[island as usize].root?;
269        Some(&self.node(root).style)
270    }
271
272    fn current_island(&self) -> IslandId {
273        *self.current.last().unwrap()
274    }
275
276    fn node(&self, id: LayoutId) -> &Node {
277        &self.islands[id.island() as usize].nodes[id.index()]
278    }
279
280    fn node_mut(&mut self, id: LayoutId) -> &mut Node {
281        &mut self.islands[id.island() as usize].nodes[id.index()]
282    }
283
284    fn push_node(
285        &mut self,
286        style: taffy::Style,
287        children: &[LayoutId],
288        kind: NodeKind,
289        measure_key: Option<Box<dyn MeasureKey>>,
290        source: &Style,
291    ) -> LayoutId {
292        let island = self.current_island();
293        let index = self.islands[island as usize].nodes.len();
294        let id = LayoutId::new(island, index);
295        for child in children {
296            self.node_mut(*child).parent = Some(id);
297        }
298        self.islands[island as usize].nodes.push(Node {
299            style,
300            children: children.iter().map(|child| NodeId::from(child.0)).collect(),
301            parent: None,
302            cache: Cache::new(),
303            layout: Layout::new(),
304            kind,
305            vertical_align: source.vertical_align,
306            display: source.display,
307            position: source.position,
308            direction: DirectionMetadata {
309                authored: source.direction,
310                unicode_bidi: source.effective_unicode_bidi(),
311                source_direction: None,
312                auto_direction_hint: None,
313                logical_children: None,
314                resolved: ResolvedDirection::LeftToRight,
315                handle: OnceCell::new(),
316            },
317            inline_content: None,
318            inline_fragments: None,
319            placed: None,
320            bounds: None,
321            inherited: false,
322            measure_key,
323            last_measure: None,
324            measured: false,
325        });
326        if let Some(previous) = self.islands[island as usize].previous.get(index)
327            && self.can_inherit(self.node(id), previous)
328        {
329            let island = &mut self.islands[id.island() as usize];
330            let (node, previous) = (&mut island.nodes[index], &mut island.previous[index]);
331            node.inherited = true;
332            std::mem::swap(&mut node.cache, &mut previous.cache);
333            node.layout = previous.layout;
334            node.style.direction = previous.style.direction;
335            node.direction.resolved = previous.direction.resolved;
336            node.last_measure = previous.last_measure;
337            let measured = match (&node.measure_key, &previous.measure_key) {
338                (Some(key), Some(previous_key)) => key.inherit(previous_key.as_ref()),
339                _ => false,
340            };
341            if matches!(node.kind, NodeKind::Measured(_)) && !measured {
342                self.replays.push(id);
343            }
344        }
345        id
346    }
347
348    /// Whether `node` can keep the layout of `previous`, the node at its place in the last render,
349    /// because nothing that affects its layout changed.
350    fn can_inherit(&self, node: &Node, previous: &Node) -> bool {
351        let same_kind = match (&node.kind, &previous.kind) {
352            (NodeKind::Plain, NodeKind::Plain) => true,
353            (NodeKind::Measured(_), NodeKind::Measured(_)) => {
354                match (&node.measure_key, &previous.measure_key) {
355                    (Some(key), Some(previous_key)) => key.same(previous_key.as_ref()),
356                    _ => false,
357                }
358            }
359            (
360                NodeKind::Proxy { island, .. },
361                NodeKind::Proxy {
362                    island: previous_island,
363                    ..
364                },
365            ) => island == previous_island && !self.islands[*island as usize].changed,
366            _ => false,
367        };
368        let same = same_kind
369            && node.children == previous.children
370            && node
371                .children
372                .iter()
373                .all(|child| self.node(LayoutId(u64::from(*child))).inherited)
374            && node.vertical_align == previous.vertical_align
375            && node.display == previous.display
376            && node.position == previous.position
377            && node.direction.authored == previous.direction.authored
378            && node.direction.unicode_bidi == previous.direction.unicode_bidi;
379        // Directions are resolved after nodes are created, so compare with the one resolved last.
380        same && if node.style.direction == previous.style.direction {
381            node.style == previous.style
382        } else {
383            taffy::Style {
384                direction: previous.style.direction,
385                ..node.style.clone()
386            } == previous.style
387        }
388    }
389
390    /// Adds a node styled by `style`, with `children` as its child nodes, and returns its id.
391    ///
392    /// `rem_size` and `scale_factor` resolve the style's lengths. Lengths in `rem` use
393    /// `rem_size`; layout is snapped to device pixels using `scale_factor`.
394    pub fn request_layout(
395        &mut self,
396        style: Style,
397        rem_size: Pixels,
398        scale_factor: f32,
399        children: &[LayoutId],
400    ) -> LayoutId {
401        let taffy_style = style.to_taffy(rem_size, scale_factor);
402        self.push_node(taffy_style, children, NodeKind::Plain, None, &style)
403    }
404
405    /// Adds a leaf node whose size comes from `measure`, and returns its id.
406    ///
407    /// Use it for content whose size depends on the space it gets, such as text. Taffy calls
408    /// `measure` during [`Self::compute_layout`] with the known width and height, if any, and
409    /// the available space along each axis. `measure` returns the content's size in logical
410    /// pixels.
411    pub fn request_measured_layout(
412        &mut self,
413        style: Style,
414        rem_size: Pixels,
415        scale_factor: f32,
416        measure: impl FnMut(
417            Size<Option<Pixels>>,
418            Size<AvailableSpace>,
419            &mut Window,
420            &mut App,
421        ) -> Size<Pixels>
422        + 'static,
423    ) -> LayoutId {
424        self.request_keyed_measured_layout(style, rem_size, scale_factor, None, measure)
425    }
426
427    /// [`Self::request_measured_layout`] for a node whose size depends only on `key` and the
428    /// space it's measured in. See [`MeasureKey`].
429    pub(crate) fn request_keyed_measured_layout(
430        &mut self,
431        style: Style,
432        rem_size: Pixels,
433        scale_factor: f32,
434        key: Option<Box<dyn MeasureKey>>,
435        measure: impl FnMut(
436            Size<Option<Pixels>>,
437            Size<AvailableSpace>,
438            &mut Window,
439            &mut App,
440        ) -> Size<Pixels>
441        + 'static,
442    ) -> LayoutId {
443        let taffy_style = style.to_taffy(rem_size, scale_factor);
444        let measure = Box::new(measure) as Box<MeasureFn>;
445        #[cfg(feature = "stacker")]
446        let measure = StackSafe::new(measure);
447        self.push_node(taffy_style, &[], NodeKind::Measured(measure), key, &style)
448    }
449
450    pub(crate) fn set_logical_children(&mut self, node_id: LayoutId, children: &[LayoutId]) {
451        let node = self.node_mut(node_id);
452        let same = node.children.len() == children.len()
453            && node
454                .children
455                .iter()
456                .zip(children)
457                .all(|(actual, logical)| u64::from(*actual) == logical.0);
458        node.direction.logical_children = (!same).then(|| children.to_vec());
459    }
460
461    pub(crate) fn set_direction_text(&mut self, node_id: LayoutId, text: SharedString) {
462        self.node_mut(node_id).direction.source_direction =
463            ResolvedDirection::from_first_strong(&text);
464    }
465
466    pub(crate) fn set_auto_direction_hint(
467        &mut self,
468        node_id: LayoutId,
469        direction: Option<ResolvedDirection>,
470    ) {
471        self.node_mut(node_id).direction.auto_direction_hint = direction;
472    }
473
474    pub(crate) fn island_direction_contribution(
475        &self,
476        island: IslandId,
477    ) -> Option<ResolvedDirection> {
478        self.auto_direction_contribution(self.islands[island as usize].root?)
479    }
480
481    pub(crate) fn auto_direction_contribution(
482        &self,
483        node_id: LayoutId,
484    ) -> Option<ResolvedDirection> {
485        let node_id = self.through_proxy(node_id)?;
486        (self.node(node_id).direction.authored == LayoutDirection::Inherit)
487            .then(|| self.auto_direction(node_id))
488            .flatten()
489    }
490
491    pub(crate) fn direction_handle(&self, node_id: LayoutId) -> LayoutDirectionHandle {
492        let direction = &self.node(node_id).direction;
493        LayoutDirectionHandle(
494            direction
495                .handle
496                .get_or_init(|| Rc::new(Cell::new(direction.resolved)))
497                .clone(),
498        )
499    }
500
501    pub(crate) fn directionality(&self, node_id: LayoutId) -> (ResolvedDirection, UnicodeBidi) {
502        let direction = &self.node(node_id).direction;
503        (direction.resolved, direction.unicode_bidi)
504    }
505
506    /// Resolves a proxy to the root of the island it stands for.
507    fn through_proxy(&self, node_id: LayoutId) -> Option<LayoutId> {
508        match &self.node(node_id).kind {
509            NodeKind::Proxy { island, .. } => self.islands[*island as usize].root,
510            _ => Some(node_id),
511        }
512    }
513
514    fn children_of(&self, node_id: LayoutId) -> impl Iterator<Item = LayoutId> + '_ {
515        let node = self.node(node_id);
516        let logical = node.direction.logical_children.as_deref();
517        let actual = logical
518            .is_none()
519            .then(|| node.children.iter().map(|id| LayoutId(u64::from(*id))))
520            .into_iter()
521            .flatten();
522        logical.into_iter().flatten().copied().chain(actual)
523    }
524
525    fn auto_direction(&self, node_id: LayoutId) -> Option<ResolvedDirection> {
526        let direction = &self.node(node_id).direction;
527        if let Some(direction) = direction.source_direction.or(direction.auto_direction_hint) {
528            return Some(direction);
529        }
530        self.children_of(node_id)
531            .find_map(|child| self.auto_direction_contribution(child))
532    }
533
534    fn resolve_directions(
535        &mut self,
536        root_id: LayoutId,
537        inherited: ResolvedDirection,
538    ) -> Vec<LayoutId> {
539        let mut changed = Vec::new();
540        self.resolve_direction_subtree(root_id, inherited, &mut changed);
541        changed
542    }
543
544    fn resolve_direction_subtree(
545        &mut self,
546        node_id: LayoutId,
547        inherited: ResolvedDirection,
548        changed: &mut Vec<LayoutId>,
549    ) {
550        if let NodeKind::Proxy { island, .. } = self.node(node_id).kind {
551            let island = &mut self.islands[island as usize];
552            if island.resolved_with == Some(inherited) {
553                return;
554            }
555            island.resolved_with = Some(inherited);
556            if let Some(root) = island.root {
557                self.resolve_direction_subtree(root, inherited, changed);
558            }
559            return;
560        }
561
562        let resolved = match self.node(node_id).direction.authored {
563            LayoutDirection::Inherit => inherited,
564            LayoutDirection::LeftToRight => ResolvedDirection::LeftToRight,
565            LayoutDirection::RightToLeft => ResolvedDirection::RightToLeft,
566            LayoutDirection::Auto => self
567                .auto_direction(node_id)
568                .unwrap_or(ResolvedDirection::LeftToRight),
569        };
570        let taffy_direction = match resolved {
571            ResolvedDirection::LeftToRight => taffy::style::Direction::Ltr,
572            ResolvedDirection::RightToLeft => taffy::style::Direction::Rtl,
573        };
574        let node = self.node_mut(node_id);
575        if node.direction.resolved != resolved {
576            changed.push(node_id);
577            node.direction.resolved = resolved;
578            if let Some(handle) = node.direction.handle.get() {
579                handle.set(resolved);
580            }
581        }
582        if node.style.direction != taffy_direction {
583            node.style.direction = taffy_direction;
584            self.mark_dirty(node_id);
585        }
586
587        let children: smallvec::SmallVec<[LayoutId; 8]> = self.children_of(node_id).collect();
588        for child_id in children {
589            self.resolve_direction_subtree(child_id, resolved, changed);
590        }
591    }
592
593    /// Clears cached layout of `node_id` and of its ancestors, including through island anchors.
594    fn mark_dirty(&mut self, mut node_id: LayoutId) {
595        loop {
596            let node = self.node_mut(node_id);
597            node.cache.clear();
598            match node.parent {
599                Some(parent) => node_id = parent,
600                None => match self.anchor_of_root(node_id) {
601                    Some(anchor) => node_id = anchor,
602                    None => return,
603                },
604            }
605        }
606    }
607
608    fn anchor_of_root(&self, node_id: LayoutId) -> Option<LayoutId> {
609        let island = &self.islands[node_id.island() as usize];
610        (island.root == Some(node_id))
611            .then_some(island.anchor)
612            .flatten()
613    }
614
615    pub(crate) fn vertical_align(&self, node_id: LayoutId) -> VerticalAlign {
616        self.node(node_id).vertical_align
617    }
618
619    /// Whether the node kept the layout it had in the view's previous render.
620    pub(crate) fn inherited(&self, node_id: LayoutId) -> bool {
621        self.node(node_id).inherited
622    }
623
624    pub(crate) fn display_and_position(&self, node_id: LayoutId) -> (Display, Position) {
625        let node = self.node(node_id);
626        (node.display, node.position)
627    }
628
629    pub(crate) fn inline_content(&self, node_id: LayoutId) -> Option<Arc<InlineContent>> {
630        self.node(node_id).inline_content.clone()
631    }
632
633    pub(crate) fn set_inline_content(&mut self, node_id: LayoutId, content: InlineContent) {
634        self.node_mut(node_id).inline_content = Some(Arc::new(content));
635    }
636
637    pub(crate) fn inline_fragments(&self, node_id: LayoutId) -> Option<Arc<[Bounds<Pixels>]>> {
638        self.node(node_id).inline_fragments.clone()
639    }
640
641    pub(crate) fn set_inline_fragments(
642        &mut self,
643        node_id: LayoutId,
644        fragments: Arc<[Bounds<Pixels>]>,
645    ) {
646        self.node_mut(node_id).inline_fragments = Some(fragments);
647    }
648
649    /// Places a detached inline box, invalidating cached positions of its descendants.
650    pub(crate) fn place_inline(&mut self, node_id: LayoutId, bounds: Bounds<Pixels>, scale: f32) {
651        self.bounds_epoch += 1;
652        self.node_mut(node_id).placed = Some((
653            bounds.origin.map(|position| f32::from(position) * scale),
654            bounds,
655        ));
656    }
657
658    /// Treats any `auto` dimension of the given node's style as filling `size`.
659    ///
660    /// This is applied to window roots before layout so they behave like the
661    /// root element on the web, which stretches to fill the initial containing
662    /// block (the viewport) unless given an explicit size. Explicitly styled
663    /// dimensions are preserved.
664    pub fn stretch_auto_size_to_fill(
665        &mut self,
666        id: LayoutId,
667        size: Size<Pixels>,
668        scale_factor: f32,
669    ) {
670        let style = match &self.node(id).kind {
671            NodeKind::Proxy { island, .. } => self.root_style(*island),
672            _ => Some(&self.node(id).style),
673        };
674        let Some(style) = style else { return };
675        let stretch_width = style.size.width.is_auto();
676        let stretch_height = style.size.height.is_auto();
677        if !stretch_width && !stretch_height {
678            return;
679        }
680        let mut style = style.clone();
681        if stretch_width {
682            style.size.width =
683                taffy::style::Dimension::length(round_to_device_pixel(size.width.0, scale_factor));
684        }
685        if stretch_height {
686            style.size.height =
687                taffy::style::Dimension::length(round_to_device_pixel(size.height.0, scale_factor));
688        }
689        let node = self.node_mut(id);
690        match &mut node.kind {
691            NodeKind::Proxy {
692                style: stretched, ..
693            } => *stretched = Some(Box::new(style)),
694            _ => node.style = style,
695        }
696        node.cache.clear();
697    }
698
699    /// Lays out the subtree under `id` for the given available space.
700    ///
701    /// Call it on the root node with the space the window offers. It calls each measured node's
702    /// `measure` closure as needed. Read the results with [`Self::layout_bounds`] afterwards.
703    /// Calling it again with a different available space recomputes the subtree.
704    #[cfg_attr(feature = "stacker", stacksafe::stacksafe)]
705    pub fn compute_layout(
706        &mut self,
707        id: LayoutId,
708        available_space: Size<AvailableSpace>,
709        inherited_direction: ResolvedDirection,
710        window: &mut Window,
711        cx: &mut App,
712    ) {
713        let changed_ids = self.resolve_directions(id, inherited_direction);
714        for changed_id in changed_ids {
715            if changed_id == id {
716                continue;
717            }
718            let Some(&(_, available_space)) = self
719                .computed_available_spaces
720                .iter()
721                .find(|(computed, _)| *computed == changed_id)
722            else {
723                continue;
724            };
725            self.compute_resolved_layout(changed_id, available_space, None, window, cx);
726        }
727
728        match self
729            .computed_available_spaces
730            .iter_mut()
731            .find(|(computed, _)| *computed == id)
732        {
733            Some(entry) => entry.1 = available_space,
734            None => self.computed_available_spaces.push((id, available_space)),
735        }
736        self.compute_resolved_layout(id, available_space, None, window, cx);
737    }
738
739    /// Lays out `island`'s root at exactly `size`, where its anchor already sits.
740    pub(crate) fn layout_island(
741        &mut self,
742        island: IslandId,
743        size: Size<Pixels>,
744        inherited_direction: ResolvedDirection,
745        window: &mut Window,
746        cx: &mut App,
747    ) {
748        let Some(root) = self.islands[island as usize].root else {
749            return;
750        };
751        self.islands[island as usize].resolved_with = None;
752        self.resolve_directions(root, inherited_direction);
753        let available_space = size.map(AvailableSpace::Definite);
754        self.compute_resolved_layout(root, available_space, Some(size), window, cx);
755    }
756
757    fn compute_resolved_layout(
758        &mut self,
759        id: LayoutId,
760        available_space: Size<AvailableSpace>,
761        known_size: Option<Size<Pixels>>,
762        window: &mut Window,
763        cx: &mut App,
764    ) {
765        let scale_factor = window.scale_factor();
766        let to_device = |space: AvailableSpace| match space {
767            AvailableSpace::Definite(pixels) => AvailableSpace::Definite(pixels * scale_factor),
768            other => other,
769        };
770        let available_space: TaffySize<TaffyAvailableSpace> = size(
771            to_device(available_space.width),
772            to_device(available_space.height),
773        )
774        .into();
775        self.bounds_epoch += 1;
776
777        let mut tree = LayoutTree {
778            islands: &mut self.islands,
779            window,
780            cx,
781            scale_factor,
782        };
783        match known_size {
784            None => compute_root_layout(&mut tree, id.into(), available_space),
785            Some(known) => {
786                let known = TaffySize {
787                    width: Some(known.width.0 * scale_factor),
788                    height: Some(known.height.0 * scale_factor),
789                };
790                let output = tree.compute_child_layout(
791                    id.into(),
792                    LayoutInput {
793                        known_dimensions: known,
794                        known_dimensions_are_definite: TaffySize {
795                            width: true,
796                            height: true,
797                        },
798                        parent_size: known,
799                        available_space,
800                        run_mode: RunMode::PerformLayout,
801                        sizing_mode: taffy::SizingMode::InherentSize,
802                        axis: taffy::RequestedAxis::Both,
803                        vertical_margins_are_collapsible: taffy::Line::FALSE,
804                    },
805                );
806                let node = tree.node_mut(id.into());
807                node.layout.size = output.size;
808                node.layout.location = TaffyPoint::ZERO;
809            }
810        }
811        tree.replay_measurements(&mut self.replays);
812    }
813
814    // Pixel snapping
815    //
816    // Painting primitives at non-integer pixel coordinates produces blurry
817    // output. Pixel snapping converts layout coordinates into integer
818    // device-pixel coordinates so painted edges land exactly on physical
819    // pixel boundaries.
820    //
821    // Non-integer coordinates can arise for several reasons, including:
822    //   - flex distribution, percentages, centering, and text measurement
823    //     can produce fractional element sizes and positions;
824    //   - at fractional scale factors (for example 125% or 150%), integer
825    //     logical-pixel values can map to non-integer device-pixel values.
826    //
827    // We pixel-snap by rounding in device-pixel space, after multiplying
828    // by `scale_factor`, so that snapping targets physical pixels. Bounds
829    // are divided by `scale_factor` before being returned to GPUI.
830    //
831    // Midpoints are rounded toward zero. This is a stylistic choice: a
832    // 1-logical-pixel line at 150% scale should render as 1 dp rather than
833    // 2 dp.
834    //
835    // Pixel snapping is done in two phases:
836    //
837    //  1. Pre-layout metric snapping. Before Taffy computes layout, all
838    //     authored absolute lengths are rounded in `to_taffy`. This
839    //     includes borders, padding, gaps, and explicit sizes.
840    //     Custom-measured leaf nodes have their measured sizes rounded up
841    //     to integer device-pixel lengths.
842    //
843    //  2. Post-layout edge snapping. After Taffy resolves the tree, layout
844    //     relationships such as flex shares, grid tracks, percentages, and
845    //     centering can produce new fractional edge positions. Boxes now
846    //     have edges in absolute coordinates, and snapping must decide
847    //     where those edges land on the device-pixel grid.
848    //
849    // Ideally, post-layout snapping would satisfy:
850    //
851    //  - Edge closure. Two raw layout edges at the same absolute position
852    //    should snap to the same pixel column.
853    //  - Translation stability. A component's internal geometry should not
854    //    change when it moves to a new absolute position.
855    //
856    // These goals are in tension because rounding is not associative.
857    // The simple local schemes make different tradeoffs:
858    //
859    //  - Absolute edge rounding gives each window coordinate one answer,
860    //    so coincident edges always close globally. But a span's snapped
861    //    length is `round(far) - round(near)`, which may change by 1 dp
862    //    as its absolute origin moves.
863    //
864    //  - Parent-relative edge rounding rounds each child inside its
865    //    parent's coordinate space. This guarantees translation stability,
866    //    but a shared edge reached through different parents can
867    //    accumulate different rounding, causing non-closure between
868    //    cousins.
869    //
870    //  - Length rounding rounds each width, height, and thickness
871    //    independently and then places boxes from those rounded lengths.
872    //    Sizes stay stable under translation, but neighboring boxes derive
873    //    their shared boundary from different sources, so closure is not
874    //    guaranteed.
875    //
876    // We apply absolute edge rounding for each element's outer box in
877    // post-layout rounding to preserve closure. Border and padding widths
878    // are not touched by post-layout rounding; they keep their pre-layout
879    // rounded value so that they remain stable under translation.
880    //
881    // This gives both closure and translation stability in the case that
882    // all local metrics are integer device-pixel lengths. Pre-layout
883    // rounding covers that in most cases. The exception is metrics
884    // resolved by layout relationships, such as percentages. Outer box
885    // edges will still close globally, and painted border widths are still
886    // snapped independently, but the raw content-box origin can carry a
887    // 1dp residual into descendants.
888
889    /// Returns the node's bounds in logical pixels, relative to the window.
890    ///
891    /// Call [`Self::compute_layout`] first. The result is cached until the next layout and is
892    /// returned in logical pixels after device-pixel snapping, so neighboring boxes meet exactly.
893    pub fn layout_bounds(&mut self, id: LayoutId, scale_factor: f32) -> Bounds<Pixels> {
894        self.absolute_layout(id, scale_factor).1
895    }
896
897    fn absolute_layout(&mut self, id: LayoutId, scale_factor: f32) -> (Point<f32>, Bounds<Pixels>) {
898        let node = self.node(id);
899        if let Some(placed) = node.placed {
900            return placed;
901        }
902        if let Some((epoch, origin, bounds)) = node.bounds
903            && epoch == self.bounds_epoch
904        {
905            return (origin, bounds);
906        }
907        let location = Point::from(node.layout.location);
908        let layout_size = node.layout.size;
909        let parent = node.parent.or_else(|| self.anchor_of_root(id));
910        let origin = match parent {
911            Some(parent) => self.absolute_layout(parent, scale_factor).0 + location,
912            None => location,
913        };
914        let far = origin + Point::from(Size::from(layout_size));
915        let snapped = Bounds::from_corners(
916            origin.map(round_half_toward_zero),
917            far.map(round_half_toward_zero),
918        );
919        let bounds = (snapped / scale_factor).map(Pixels);
920        let epoch = self.bounds_epoch;
921        self.node_mut(id).bounds = Some((epoch, origin, bounds));
922        (origin, bounds)
923    }
924
925    /// Returns bounds whose origin and size are snapped in the coordinate space of the parent.
926    ///
927    /// Text uses this placement so its offset within a containing element remains stable when the
928    /// element moves across the device-pixel grid. Other layout boxes continue to use absolute edge
929    /// snapping through [`Self::layout_bounds`] so coincident edges still close.
930    pub(crate) fn parent_relative_layout_bounds(
931        &mut self,
932        node_id: LayoutId,
933        scale_factor: f32,
934    ) -> Bounds<Pixels> {
935        let node = self.node(node_id);
936        if node.inline_fragments.is_some() {
937            return self.layout_bounds(node_id, scale_factor);
938        }
939        let Some(parent_id) = node.parent else {
940            return self.layout_bounds(node_id, scale_factor);
941        };
942        let local_origin = Point::from(node.layout.location).map(round_half_toward_zero);
943        let local_size = Size::from(node.layout.size).map(round_half_toward_zero);
944        let parent_bounds = self.layout_bounds(parent_id, scale_factor);
945        Bounds::new(
946            parent_bounds.origin + (local_origin / scale_factor).map(Pixels),
947            (local_size / scale_factor).map(Pixels),
948        )
949    }
950}
951
952/// Taffy's view of every island while a layout computes. Measured leaves get the window and app.
953struct LayoutTree<'a> {
954    islands: &'a mut [Island],
955    window: &'a mut Window,
956    cx: &'a mut App,
957    scale_factor: f32,
958}
959
960impl LayoutTree<'_> {
961    fn node(&self, id: NodeId) -> &Node {
962        let id = LayoutId(u64::from(id));
963        &self.islands[id.island() as usize].nodes[id.index()]
964    }
965
966    fn node_mut(&mut self, id: NodeId) -> &mut Node {
967        let id = LayoutId(u64::from(id));
968        &mut self.islands[id.island() as usize].nodes[id.index()]
969    }
970
971    fn style(&self, id: NodeId) -> &taffy::Style {
972        match &self.node(id).kind {
973            NodeKind::Proxy {
974                style: Some(style), ..
975            } => style,
976            NodeKind::Proxy { island, .. } => match self.islands[*island as usize].root {
977                Some(root) => &self.node(root.into()).style,
978                None => &self.node(id).style,
979            },
980            _ => &self.node(id).style,
981        }
982    }
983
984    fn compute_node(
985        &mut self,
986        node_id: NodeId,
987        inputs: LayoutInput,
988        block_ctx: Option<&mut BlockContext<'_>>,
989    ) -> LayoutOutput {
990        if inputs.run_mode == RunMode::PerformHiddenLayout {
991            return compute_hidden_layout(self, node_id);
992        }
993        if let NodeKind::Proxy { island, style } = &self.node(node_id).kind {
994            let Some(root) = self.islands[*island as usize].root else {
995                return LayoutOutput::HIDDEN;
996            };
997            // A stretched window root carries its size on the proxy.
998            let mut inputs = inputs;
999            if let Some(style) = style {
1000                let size = TaffySize {
1001                    width: style.size.width.into_option(),
1002                    height: style.size.height.into_option(),
1003                };
1004                inputs.known_dimensions = inputs.known_dimensions.or(size);
1005            }
1006            return self.compute_node(root.into(), inputs, block_ctx);
1007        }
1008        compute_cached_layout(self, node_id, inputs, |tree, node_id, inputs| {
1009            let node = tree.node(node_id);
1010            match (node.style.display, !node.children.is_empty()) {
1011                (taffy::Display::None, _) => compute_hidden_layout(tree, node_id),
1012                (taffy::Display::Block, true) => {
1013                    compute_block_layout(tree, node_id, inputs, block_ctx)
1014                }
1015                (taffy::Display::FlowRoot, true) => {
1016                    compute_block_layout(tree, node_id, inputs, None)
1017                }
1018                (taffy::Display::Flex, true) => compute_flexbox_layout(tree, node_id, inputs),
1019                (taffy::Display::Grid, true) => compute_grid_layout(tree, node_id, inputs),
1020                (_, false) => tree.compute_leaf(node_id, inputs),
1021            }
1022        })
1023    }
1024
1025    fn compute_leaf(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
1026        let scale_factor = self.scale_factor;
1027        let id = LayoutId(u64::from(node_id));
1028        let Node {
1029            style,
1030            kind,
1031            direction,
1032            last_measure,
1033            measured,
1034            ..
1035        } = &mut self.islands[id.island() as usize].nodes[id.index()];
1036        let NodeKind::Measured(measure) = kind else {
1037            return compute_leaf_layout(inputs, style, |_, _| 0.0, |_, _| TaffySize::ZERO);
1038        };
1039        let unicode_bidi = direction.unicode_bidi;
1040        let window = &mut *self.window;
1041        let cx = &mut *self.cx;
1042        compute_leaf_layout(
1043            inputs,
1044            style,
1045            |_, _| 0.0,
1046            |known, available| {
1047                let known = Size {
1048                    width: known.width.map(|e| Pixels(e / scale_factor)),
1049                    height: known.height.map(|e| Pixels(e / scale_factor)),
1050                };
1051                let from_device = |space: AvailableSpace| match space {
1052                    AvailableSpace::Definite(pixels) => {
1053                        AvailableSpace::Definite(Pixels(pixels.0 / scale_factor))
1054                    }
1055                    other => other,
1056                };
1057                let available: Size<AvailableSpace> = available.into();
1058                let available = size(from_device(available.width), from_device(available.height));
1059                *last_measure = Some((known, available));
1060                *measured = true;
1061                let size = call_measure(
1062                    measure,
1063                    style.direction,
1064                    unicode_bidi,
1065                    known,
1066                    available,
1067                    window,
1068                    cx,
1069                );
1070                snap_measured_size_to_device_pixels(size, scale_factor).into()
1071            },
1072        )
1073    }
1074}
1075
1076/// Calls a measure function in the direction its node lays out in.
1077fn call_measure(
1078    measure: &mut NodeMeasureFn,
1079    direction: taffy::style::Direction,
1080    unicode_bidi: UnicodeBidi,
1081    known: Size<Option<Pixels>>,
1082    available: Size<AvailableSpace>,
1083    window: &mut Window,
1084    cx: &mut App,
1085) -> Size<Pixels> {
1086    let direction = match direction {
1087        taffy::style::Direction::Ltr => ResolvedDirection::LeftToRight,
1088        taffy::style::Direction::Rtl => ResolvedDirection::RightToLeft,
1089    };
1090    let previous_direction = std::mem::replace(&mut window.measurement_direction, direction);
1091    let previous_unicode_bidi =
1092        std::mem::replace(&mut window.measurement_unicode_bidi, unicode_bidi);
1093    let size = measure(known, available, window, cx);
1094    window.measurement_direction = previous_direction;
1095    window.measurement_unicode_bidi = previous_unicode_bidi;
1096    size
1097}
1098
1099impl LayoutTree<'_> {
1100    /// Gives the elements of measured nodes that kept their layout, and weren't measured since,
1101    /// the measurement they made last time.
1102    fn replay_measurements(&mut self, replays: &mut Vec<LayoutId>) {
1103        for id in replays.drain(..) {
1104            let Some(Node {
1105                style,
1106                kind: NodeKind::Measured(measure),
1107                direction,
1108                last_measure: Some((known, available)),
1109                measured,
1110                inherited: true,
1111                ..
1112            }) = self.islands[id.island() as usize].nodes.get_mut(id.index())
1113            else {
1114                continue;
1115            };
1116            if *measured {
1117                continue;
1118            }
1119            *measured = true;
1120            call_measure(
1121                measure,
1122                style.direction,
1123                direction.unicode_bidi,
1124                *known,
1125                *available,
1126                self.window,
1127                self.cx,
1128            );
1129        }
1130    }
1131}
1132
1133impl TraversePartialTree for LayoutTree<'_> {
1134    type ChildIter<'a>
1135        = std::iter::Copied<std::slice::Iter<'a, NodeId>>
1136    where
1137        Self: 'a;
1138
1139    fn child_ids(&self, parent: NodeId) -> Self::ChildIter<'_> {
1140        self.node(parent).children.iter().copied()
1141    }
1142
1143    fn child_count(&self, parent: NodeId) -> usize {
1144        self.node(parent).children.len()
1145    }
1146
1147    fn get_child_id(&self, parent: NodeId, index: usize) -> NodeId {
1148        self.node(parent).children[index]
1149    }
1150}
1151
1152impl LayoutPartialTree for LayoutTree<'_> {
1153    type CoreContainerStyle<'a>
1154        = &'a taffy::Style
1155    where
1156        Self: 'a;
1157
1158    type CustomIdent = String;
1159
1160    fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> {
1161        self.style(node_id)
1162    }
1163
1164    fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout) {
1165        self.node_mut(node_id).layout = *layout;
1166        if let NodeKind::Proxy { island, .. } = self.node(node_id).kind
1167            && let Some(root) = self.islands[island as usize].root
1168        {
1169            self.node_mut(root.into()).layout = Layout {
1170                location: TaffyPoint::ZERO,
1171                ..*layout
1172            };
1173        }
1174    }
1175
1176    fn resolve_calc_value(&self, _val: *const (), _basis: f32) -> f32 {
1177        0.0
1178    }
1179
1180    fn compute_child_layout(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
1181        self.compute_node(node_id, inputs, None)
1182    }
1183}
1184
1185impl CacheTree for LayoutTree<'_> {
1186    fn cache_get(&mut self, node_id: NodeId, input: &LayoutInput) -> Option<LayoutOutput> {
1187        self.node_mut(node_id).cache.get(input)
1188    }
1189
1190    fn cache_store(&mut self, node_id: NodeId, input: &LayoutInput, output: LayoutOutput) {
1191        self.node_mut(node_id).cache.store(input, output)
1192    }
1193
1194    fn cache_clear(&mut self, node_id: NodeId) {
1195        self.node_mut(node_id).cache.clear();
1196    }
1197}
1198
1199impl LayoutBlockContainer for LayoutTree<'_> {
1200    type BlockContainerStyle<'a>
1201        = &'a taffy::Style
1202    where
1203        Self: 'a;
1204    type BlockItemStyle<'a>
1205        = &'a taffy::Style
1206    where
1207        Self: 'a;
1208
1209    fn get_block_container_style(&self, node_id: NodeId) -> Self::BlockContainerStyle<'_> {
1210        self.style(node_id)
1211    }
1212
1213    fn get_block_child_style(&self, child_node_id: NodeId) -> Self::BlockItemStyle<'_> {
1214        self.style(child_node_id)
1215    }
1216
1217    fn compute_block_child_layout(
1218        &mut self,
1219        node_id: NodeId,
1220        inputs: LayoutInput,
1221        block_ctx: Option<&mut BlockContext<'_>>,
1222    ) -> LayoutOutput {
1223        self.compute_node(node_id, inputs, block_ctx)
1224    }
1225}
1226
1227impl LayoutFlexboxContainer for LayoutTree<'_> {
1228    type FlexboxContainerStyle<'a>
1229        = &'a taffy::Style
1230    where
1231        Self: 'a;
1232    type FlexboxItemStyle<'a>
1233        = &'a taffy::Style
1234    where
1235        Self: 'a;
1236
1237    fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> {
1238        self.style(node_id)
1239    }
1240
1241    fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> {
1242        self.style(child_node_id)
1243    }
1244}
1245
1246impl LayoutGridContainer for LayoutTree<'_> {
1247    type GridContainerStyle<'a>
1248        = &'a taffy::Style
1249    where
1250        Self: 'a;
1251    type GridItemStyle<'a>
1252        = &'a taffy::Style
1253    where
1254        Self: 'a;
1255
1256    fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> {
1257        self.style(node_id)
1258    }
1259
1260    fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> {
1261        self.style(child_node_id)
1262    }
1263}
1264
1265/// An id for a node in the layout tree.
1266///
1267/// [`Window::request_layout`](crate::Window::request_layout) returns one for each element. Pass
1268/// the ids of an element's children when you request its layout, and read a node's position
1269/// with the window's layout bounds methods. An id is valid only in the frame that created it.
1270#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
1271pub struct LayoutId(u64);
1272
1273impl LayoutId {
1274    fn new(island: IslandId, index: usize) -> Self {
1275        Self((u64::from(island) << 32) | index as u64)
1276    }
1277
1278    pub(crate) fn island(self) -> IslandId {
1279        (self.0 >> 32) as IslandId
1280    }
1281
1282    fn index(self) -> usize {
1283        self.0 as u32 as usize
1284    }
1285}
1286
1287impl From<LayoutId> for NodeId {
1288    fn from(layout_id: LayoutId) -> NodeId {
1289        NodeId::from(layout_id.0)
1290    }
1291}
1292
1293fn snap_measured_size_to_device_pixels(size: Size<Pixels>, scale_factor: f32) -> Size<f32> {
1294    size.map(|d| ceil_to_device_pixel(d.0.max(0.0), scale_factor))
1295}
1296
1297fn border_widths_to_taffy(
1298    widths: &Edges<AbsoluteLength>,
1299    rem_size: Pixels,
1300    scale_factor: f32,
1301) -> TaffyRect<taffy::style::LengthPercentage> {
1302    let snap = |w: &AbsoluteLength| {
1303        taffy::style::LengthPercentage::length(round_stroke_to_device_pixel(
1304            w.to_pixels(rem_size).0,
1305            scale_factor,
1306        ))
1307    };
1308    TaffyRect {
1309        top: snap(&widths.top),
1310        right: snap(&widths.right),
1311        bottom: snap(&widths.bottom),
1312        left: snap(&widths.left),
1313    }
1314}
1315
1316// Converts padding, snapping each auto-sized axis as a proportional pair.
1317fn padding_to_taffy(
1318    padding: &Edges<DefiniteLength>,
1319    rem_size: Pixels,
1320    scale_factor: f32,
1321    proportional_horizontal: bool,
1322    proportional_vertical: bool,
1323) -> TaffyRect<taffy::style::LengthPercentage> {
1324    // Snaps the combined length, then divides it by the authored ratio.
1325    fn snap_absolute_pair(
1326        first: AbsoluteLength,
1327        second: AbsoluteLength,
1328        rem_size: Pixels,
1329        scale_factor: f32,
1330    ) -> (f32, f32) {
1331        let first = first.to_pixels(rem_size).0;
1332        let second = second.to_pixels(rem_size).0;
1333        let total = first + second;
1334
1335        if first < 0.0 || second < 0.0 || total == 0.0 {
1336            return (
1337                round_to_device_pixel(first, scale_factor),
1338                round_to_device_pixel(second, scale_factor),
1339            );
1340        }
1341
1342        let snapped_total = round_to_device_pixel(total, scale_factor);
1343        let snapped_first = snapped_total * (first / total);
1344
1345        (snapped_first, snapped_total - snapped_first)
1346    }
1347
1348    // Keeps normal per-edge conversion for explicit axes and percentage padding.
1349    fn convert_pair(
1350        first: &DefiniteLength,
1351        second: &DefiniteLength,
1352        rem_size: Pixels,
1353        scale_factor: f32,
1354        proportional: bool,
1355    ) -> (
1356        taffy::style::LengthPercentage,
1357        taffy::style::LengthPercentage,
1358    ) {
1359        if proportional
1360            && let (DefiniteLength::Absolute(first), DefiniteLength::Absolute(second)) =
1361                (*first, *second)
1362        {
1363            let (first, second) = snap_absolute_pair(first, second, rem_size, scale_factor);
1364
1365            (
1366                taffy::style::LengthPercentage::length(first),
1367                taffy::style::LengthPercentage::length(second),
1368            )
1369        } else {
1370            (
1371                first.to_taffy(rem_size, scale_factor),
1372                second.to_taffy(rem_size, scale_factor),
1373            )
1374        }
1375    }
1376
1377    let (left, right) = convert_pair(
1378        &padding.left,
1379        &padding.right,
1380        rem_size,
1381        scale_factor,
1382        proportional_horizontal,
1383    );
1384    let (top, bottom) = convert_pair(
1385        &padding.top,
1386        &padding.bottom,
1387        rem_size,
1388        scale_factor,
1389        proportional_vertical,
1390    );
1391
1392    TaffyRect {
1393        top,
1394        right,
1395        bottom,
1396        left,
1397    }
1398}
1399
1400trait ToTaffy<Output> {
1401    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> Output;
1402}
1403
1404impl ToTaffy<taffy::style::Style> for Style {
1405    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::Style {
1406        use taffy::style_helpers::{fr, length, minmax, repeat};
1407
1408        fn to_grid_line(
1409            placement: &Range<crate::GridPlacement>,
1410        ) -> taffy::Line<taffy::GridPlacement> {
1411            taffy::Line {
1412                start: placement.start.into(),
1413                end: placement.end.into(),
1414            }
1415        }
1416
1417        fn to_grid_repeat<T: taffy::style::CheapCloneStr>(
1418            unit: &Option<GridTemplate>,
1419        ) -> Vec<taffy::GridTemplateComponent<T>> {
1420            unit.map(|template| {
1421                match template.min_size {
1422                    // grid-template-*: repeat(<number>, minmax(0, 1fr));
1423                    crate::GridTemplateMinSize::Zero => {
1424                        vec![repeat(
1425                            template.repeat,
1426                            vec![minmax(length(0.0_f32), fr(1.0_f32))],
1427                        )]
1428                    }
1429                    // grid-template-*: repeat(<number>, minmax(min-content, 1fr));
1430                    crate::GridTemplateMinSize::MinContent => {
1431                        vec![repeat(
1432                            template.repeat,
1433                            vec![minmax(min_content(), fr(1.0_f32))],
1434                        )]
1435                    }
1436                    // grid-template-*: repeat(<number>, minmax(0, max-content))
1437                    crate::GridTemplateMinSize::MaxContent => {
1438                        vec![repeat(
1439                            template.repeat,
1440                            vec![minmax(length(0.0_f32), max_content())],
1441                        )]
1442                    }
1443                }
1444            })
1445            .unwrap_or_default()
1446        }
1447
1448        taffy::style::Style {
1449            display: self.display.into(),
1450            direction: taffy::style::Direction::Ltr,
1451            overflow: self.overflow.into(),
1452            scrollbar_width: self.scrollbar_width.to_taffy(rem_size, scale_factor),
1453            position: self.position.into(),
1454            inset: self.inset.to_taffy(rem_size, scale_factor),
1455            size: self.size.to_taffy(rem_size, scale_factor),
1456            min_size: self.min_size.to_taffy(rem_size, scale_factor),
1457            max_size: self.max_size.to_taffy(rem_size, scale_factor),
1458            aspect_ratio: self.aspect_ratio,
1459            margin: self.margin.to_taffy(rem_size, scale_factor),
1460            padding: padding_to_taffy(
1461                &self.padding,
1462                rem_size,
1463                scale_factor,
1464                self.size.width == Length::Auto,
1465                self.size.height == Length::Auto,
1466            ),
1467            border: border_widths_to_taffy(&self.border_widths, rem_size, scale_factor),
1468            align_items: self.align_items.map(|x| x.into()),
1469            align_self: self.align_self.map(|x| x.into()),
1470            align_content: self.align_content.map(|x| x.into()),
1471            justify_content: self.justify_content.map(|x| x.into()),
1472            gap: self.gap.to_taffy(rem_size, scale_factor),
1473            flex_direction: self.flex_direction.into(),
1474            flex_wrap: self.flex_wrap.into(),
1475            flex_basis: self.flex_basis.to_taffy(rem_size, scale_factor),
1476            flex_grow: self.flex_grow,
1477            flex_shrink: self.flex_shrink,
1478            grid_template_rows: to_grid_repeat(&self.grid_rows),
1479            grid_template_columns: to_grid_repeat(&self.grid_cols),
1480            grid_row: self
1481                .grid_location
1482                .as_ref()
1483                .map(|location| to_grid_line(&location.row))
1484                .unwrap_or_default(),
1485            grid_column: self
1486                .grid_location
1487                .as_ref()
1488                .map(|location| to_grid_line(&location.column))
1489                .unwrap_or_default(),
1490            ..Default::default()
1491        }
1492    }
1493}
1494
1495impl ToTaffy<f32> for AbsoluteLength {
1496    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> f32 {
1497        round_to_device_pixel(self.to_pixels(rem_size).0, scale_factor)
1498    }
1499}
1500
1501impl ToTaffy<taffy::style::LengthPercentageAuto> for Length {
1502    fn to_taffy(
1503        &self,
1504        rem_size: Pixels,
1505        scale_factor: f32,
1506    ) -> taffy::prelude::LengthPercentageAuto {
1507        match self {
1508            Length::Definite(length) => length.to_taffy(rem_size, scale_factor),
1509            Length::Auto => taffy::prelude::LengthPercentageAuto::auto(),
1510        }
1511    }
1512}
1513
1514impl ToTaffy<taffy::style::Dimension> for Length {
1515    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::prelude::Dimension {
1516        match self {
1517            Length::Definite(length) => length.to_taffy(rem_size, scale_factor),
1518            Length::Auto => taffy::prelude::Dimension::auto(),
1519        }
1520    }
1521}
1522
1523impl ToTaffy<taffy::style::LengthPercentage> for DefiniteLength {
1524    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentage {
1525        match self {
1526            DefiniteLength::Absolute(length) => length.to_taffy(rem_size, scale_factor),
1527            DefiniteLength::Relative(relative) => {
1528                taffy::style::LengthPercentage::percent(relative.0)
1529            }
1530        }
1531    }
1532}
1533
1534impl ToTaffy<taffy::style::LengthPercentageAuto> for DefiniteLength {
1535    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentageAuto {
1536        match self {
1537            DefiniteLength::Absolute(length) => length.to_taffy(rem_size, scale_factor),
1538            DefiniteLength::Relative(relative) => {
1539                taffy::style::LengthPercentageAuto::percent(relative.0)
1540            }
1541        }
1542    }
1543}
1544
1545impl ToTaffy<taffy::style::Dimension> for DefiniteLength {
1546    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::Dimension {
1547        match self {
1548            DefiniteLength::Absolute(length) => length.to_taffy(rem_size, scale_factor),
1549            DefiniteLength::Relative(relative) => taffy::style::Dimension::percent(relative.0),
1550        }
1551    }
1552}
1553
1554impl ToTaffy<taffy::style::LengthPercentage> for AbsoluteLength {
1555    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentage {
1556        taffy::style::LengthPercentage::length(self.to_taffy(rem_size, scale_factor))
1557    }
1558}
1559
1560impl ToTaffy<taffy::style::LengthPercentageAuto> for AbsoluteLength {
1561    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentageAuto {
1562        taffy::style::LengthPercentageAuto::length(self.to_taffy(rem_size, scale_factor))
1563    }
1564}
1565
1566impl ToTaffy<taffy::style::Dimension> for AbsoluteLength {
1567    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::Dimension {
1568        taffy::style::Dimension::length(self.to_taffy(rem_size, scale_factor))
1569    }
1570}
1571
1572impl<T, T2> From<TaffyPoint<T>> for Point<T2>
1573where
1574    T: Into<T2>,
1575    T2: Clone + Debug + Default + PartialEq,
1576{
1577    fn from(point: TaffyPoint<T>) -> Point<T2> {
1578        Point {
1579            x: point.x.into(),
1580            y: point.y.into(),
1581        }
1582    }
1583}
1584
1585impl<T, T2> From<Point<T>> for TaffyPoint<T2>
1586where
1587    T: Into<T2> + Clone + Debug + Default + PartialEq,
1588{
1589    fn from(val: Point<T>) -> Self {
1590        TaffyPoint {
1591            x: val.x.into(),
1592            y: val.y.into(),
1593        }
1594    }
1595}
1596
1597impl<T, U> ToTaffy<TaffySize<U>> for Size<T>
1598where
1599    T: ToTaffy<U> + Clone + Debug + Default + PartialEq,
1600{
1601    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> TaffySize<U> {
1602        TaffySize {
1603            width: self.width.to_taffy(rem_size, scale_factor),
1604            height: self.height.to_taffy(rem_size, scale_factor),
1605        }
1606    }
1607}
1608
1609impl<T, U> ToTaffy<TaffyRect<U>> for Edges<T>
1610where
1611    T: ToTaffy<U> + Clone + Debug + Default + PartialEq,
1612{
1613    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> TaffyRect<U> {
1614        TaffyRect {
1615            top: self.top.to_taffy(rem_size, scale_factor),
1616            right: self.right.to_taffy(rem_size, scale_factor),
1617            bottom: self.bottom.to_taffy(rem_size, scale_factor),
1618            left: self.left.to_taffy(rem_size, scale_factor),
1619        }
1620    }
1621}
1622
1623impl<T, U> From<TaffySize<T>> for Size<U>
1624where
1625    T: Into<U>,
1626    U: Clone + Debug + Default + PartialEq,
1627{
1628    fn from(taffy_size: TaffySize<T>) -> Self {
1629        Size {
1630            width: taffy_size.width.into(),
1631            height: taffy_size.height.into(),
1632        }
1633    }
1634}
1635
1636impl<T, U> From<Size<T>> for TaffySize<U>
1637where
1638    T: Into<U> + Clone + Debug + Default + PartialEq,
1639{
1640    fn from(size: Size<T>) -> Self {
1641        TaffySize {
1642            width: size.width.into(),
1643            height: size.height.into(),
1644        }
1645    }
1646}
1647
1648/// How much space an element is given along one axis when it is laid out.
1649///
1650/// Measured elements receive one of these in their `measure` closure. A
1651/// [`Definite`](Self::Definite) amount is a fixed width or height. The other two ask for the
1652/// element's natural size, as CSS `min-content` and `max-content` do.
1653#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
1654pub enum AvailableSpace {
1655    /// The element has exactly this many logical pixels of space.
1656    Definite(Pixels),
1657    /// The element is sized to its smallest possible content, as with CSS `min-content`.
1658    #[default]
1659    MinContent,
1660    /// The element is sized to its largest natural content, as with CSS `max-content`.
1661    MaxContent,
1662}
1663
1664impl AvailableSpace {
1665    /// Returns a `Size` with both width and height set to `AvailableSpace::MinContent`.
1666    ///
1667    /// Use it when an element should be measured at its smallest content size on both axes.
1668    ///
1669    /// # Examples
1670    ///
1671    /// ```
1672    /// use gpui::AvailableSpace;
1673    /// let min_content_size = AvailableSpace::min_size();
1674    /// assert_eq!(min_content_size.width, AvailableSpace::MinContent);
1675    /// assert_eq!(min_content_size.height, AvailableSpace::MinContent);
1676    /// ```
1677    pub const fn min_size() -> Size<Self> {
1678        Size {
1679            width: Self::MinContent,
1680            height: Self::MinContent,
1681        }
1682    }
1683}
1684
1685impl From<AvailableSpace> for TaffyAvailableSpace {
1686    fn from(space: AvailableSpace) -> TaffyAvailableSpace {
1687        match space {
1688            AvailableSpace::Definite(Pixels(value)) => TaffyAvailableSpace::Definite(value),
1689            AvailableSpace::MinContent => TaffyAvailableSpace::MinContent,
1690            AvailableSpace::MaxContent => TaffyAvailableSpace::MaxContent,
1691        }
1692    }
1693}
1694
1695impl From<TaffyAvailableSpace> for AvailableSpace {
1696    fn from(space: TaffyAvailableSpace) -> AvailableSpace {
1697        match space {
1698            TaffyAvailableSpace::Definite(value) => AvailableSpace::Definite(Pixels(value)),
1699            TaffyAvailableSpace::MinContent => AvailableSpace::MinContent,
1700            TaffyAvailableSpace::MaxContent => AvailableSpace::MaxContent,
1701        }
1702    }
1703}
1704
1705impl From<Pixels> for AvailableSpace {
1706    fn from(pixels: Pixels) -> Self {
1707        AvailableSpace::Definite(pixels)
1708    }
1709}
1710
1711impl From<Size<Pixels>> for Size<AvailableSpace> {
1712    fn from(size: Size<Pixels>) -> Self {
1713        Size {
1714            width: AvailableSpace::Definite(size.width),
1715            height: AvailableSpace::Definite(size.height),
1716        }
1717    }
1718}
1719
1720#[cfg(test)]
1721mod tests {
1722    use super::*;
1723    use crate::px;
1724
1725    fn direction_style(direction: LayoutDirection) -> Style {
1726        Style {
1727            direction,
1728            ..Default::default()
1729        }
1730    }
1731
1732    #[test]
1733    fn direction_defaults_to_ltr_and_inherits_through_overrides() {
1734        let mut engine = TaffyLayoutEngine::new();
1735        let inherited_grandchild = engine.request_layout(
1736            direction_style(LayoutDirection::Inherit),
1737            px(16.0),
1738            1.0,
1739            &[],
1740        );
1741        let rtl_child = engine.request_layout(
1742            direction_style(LayoutDirection::RightToLeft),
1743            px(16.0),
1744            1.0,
1745            &[inherited_grandchild],
1746        );
1747        let root = engine.request_layout(
1748            direction_style(LayoutDirection::Inherit),
1749            px(16.0),
1750            1.0,
1751            &[rtl_child],
1752        );
1753
1754        let _ = engine.resolve_directions(root, ResolvedDirection::LeftToRight);
1755
1756        assert_eq!(
1757            engine.direction_handle(root).get(),
1758            ResolvedDirection::LeftToRight
1759        );
1760        assert_eq!(
1761            engine.direction_handle(rtl_child).get(),
1762            ResolvedDirection::RightToLeft
1763        );
1764        assert_eq!(
1765            engine.node(rtl_child).style.direction,
1766            taffy::style::Direction::Rtl
1767        );
1768        assert_eq!(
1769            engine.direction_handle(inherited_grandchild).get(),
1770            ResolvedDirection::RightToLeft
1771        );
1772    }
1773
1774    #[test]
1775    fn auto_direction_uses_first_eligible_strong_descendant() {
1776        let mut engine = TaffyLayoutEngine::new();
1777        let neutral = engine.request_layout(
1778            direction_style(LayoutDirection::Inherit),
1779            px(16.0),
1780            1.0,
1781            &[],
1782        );
1783        engine.set_direction_text(neutral, "123 …".into());
1784        let arabic = engine.request_layout(
1785            direction_style(LayoutDirection::Inherit),
1786            px(16.0),
1787            1.0,
1788            &[],
1789        );
1790        engine.set_direction_text(arabic, "مرحبا".into());
1791        let root = engine.request_layout(
1792            direction_style(LayoutDirection::Auto),
1793            px(16.0),
1794            1.0,
1795            &[neutral, arabic],
1796        );
1797
1798        let _ = engine.resolve_directions(root, ResolvedDirection::LeftToRight);
1799
1800        assert_eq!(
1801            engine.direction_handle(root).get(),
1802            ResolvedDirection::RightToLeft
1803        );
1804        assert_eq!(
1805            engine.direction_handle(neutral).get(),
1806            ResolvedDirection::RightToLeft
1807        );
1808    }
1809
1810    #[test]
1811    fn auto_direction_excludes_directional_subtrees_and_falls_back_to_ltr() {
1812        let mut engine = TaffyLayoutEngine::new();
1813        let explicit_child = engine.request_layout(
1814            direction_style(LayoutDirection::RightToLeft),
1815            px(16.0),
1816            1.0,
1817            &[],
1818        );
1819        engine.set_direction_text(explicit_child, "مرحبا".into());
1820        let root = engine.request_layout(
1821            direction_style(LayoutDirection::Auto),
1822            px(16.0),
1823            1.0,
1824            &[explicit_child],
1825        );
1826
1827        let _ = engine.resolve_directions(root, ResolvedDirection::LeftToRight);
1828
1829        assert_eq!(
1830            engine.direction_handle(root).get(),
1831            ResolvedDirection::LeftToRight
1832        );
1833        assert_eq!(
1834            engine.direction_handle(explicit_child).get(),
1835            ResolvedDirection::RightToLeft
1836        );
1837    }
1838
1839    #[test]
1840    fn auto_direction_updates_when_source_text_changes() {
1841        let mut engine = TaffyLayoutEngine::new();
1842        let text = engine.request_layout(
1843            direction_style(LayoutDirection::Inherit),
1844            px(16.0),
1845            1.0,
1846            &[],
1847        );
1848        let root = engine.request_layout(
1849            direction_style(LayoutDirection::Auto),
1850            px(16.0),
1851            1.0,
1852            &[text],
1853        );
1854        engine.set_direction_text(text, "English".into());
1855        let _ = engine.resolve_directions(root, ResolvedDirection::LeftToRight);
1856        assert_eq!(
1857            engine.direction_handle(root).get(),
1858            ResolvedDirection::LeftToRight
1859        );
1860
1861        engine.set_direction_text(text, "مرحبا".into());
1862        let changed = engine.resolve_directions(root, ResolvedDirection::LeftToRight);
1863        assert!(changed.contains(&root));
1864        assert_eq!(
1865            engine.direction_handle(root).get(),
1866            ResolvedDirection::RightToLeft
1867        );
1868    }
1869
1870    #[test]
1871    fn auto_sized_axes_snap_padding_proportionally() {
1872        use taffy::style::LengthPercentage;
1873
1874        let mut style = Style {
1875            padding: Edges {
1876                top: Pixels(6.5).into(),
1877                right: Pixels(5.0).into(),
1878                bottom: Pixels(6.5).into(),
1879                left: Pixels(2.5).into(),
1880            },
1881            ..Default::default()
1882        };
1883
1884        let padding = style.to_taffy(Pixels(16.0), 1.0).padding;
1885        let expected_left = 7.0 * (2.5 / 7.5);
1886        assert_eq!(padding.left, LengthPercentage::length(expected_left));
1887        assert_eq!(padding.right, LengthPercentage::length(7.0 - expected_left));
1888        assert_eq!(padding.top, LengthPercentage::length(6.5));
1889        assert_eq!(padding.bottom, LengthPercentage::length(6.5));
1890
1891        style.size.width = Length::Definite(Pixels(100.0).into());
1892        let padding = style.to_taffy(Pixels(16.0), 1.0).padding;
1893        assert_eq!(padding.left, LengthPercentage::length(2.0));
1894        assert_eq!(padding.right, LengthPercentage::length(5.0));
1895        assert_eq!(padding.top, LengthPercentage::length(6.5));
1896        assert_eq!(padding.bottom, LengthPercentage::length(6.5));
1897
1898        style.size.width = Length::Auto;
1899        style.padding.top = Pixels(6.75).into();
1900        style.padding.bottom = Pixels(6.75).into();
1901        let padding = style.to_taffy(Pixels(16.0), 2.0).padding;
1902        assert_eq!(padding.top, LengthPercentage::length(13.5));
1903        assert_eq!(padding.bottom, LengthPercentage::length(13.5));
1904    }
1905
1906    #[test]
1907    fn border_widths_to_taffy_use_stroke_snapping() {
1908        let border_widths = Edges {
1909            top: Pixels(0.0).into(),
1910            right: Pixels(0.4).into(),
1911            bottom: Pixels(0.5).into(),
1912            left: Pixels(1.6).into(),
1913        };
1914        let taffy_border = border_widths_to_taffy(&border_widths, Pixels(16.0), 1.0);
1915
1916        assert_eq!(
1917            taffy_border.top,
1918            taffy::style::LengthPercentage::length(0.0)
1919        );
1920        assert_eq!(
1921            taffy_border.right,
1922            taffy::style::LengthPercentage::length(1.0)
1923        );
1924        assert_eq!(
1925            taffy_border.bottom,
1926            taffy::style::LengthPercentage::length(1.0)
1927        );
1928        assert_eq!(
1929            taffy_border.left,
1930            taffy::style::LengthPercentage::length(2.0)
1931        );
1932    }
1933
1934    struct Measured {
1935        key: u32,
1936        calls: Rc<Cell<usize>>,
1937    }
1938
1939    impl MeasureKey for u32 {
1940        fn same(&self, previous: &dyn MeasureKey) -> bool {
1941            previous.as_any().downcast_ref::<u32>() == Some(self)
1942        }
1943
1944        fn as_any(&self) -> &dyn Any {
1945            self
1946        }
1947    }
1948
1949    impl crate::IntoElement for Measured {
1950        type Element = Self;
1951
1952        fn into_element(self) -> Self {
1953            self
1954        }
1955    }
1956
1957    impl crate::Element for Measured {
1958        type RequestLayoutState = ();
1959        type PrepaintState = ();
1960
1961        fn id(&self) -> Option<crate::ElementId> {
1962            None
1963        }
1964
1965        fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
1966            None
1967        }
1968
1969        fn request_layout(
1970            &mut self,
1971            _: Option<&crate::GlobalElementId>,
1972            _: Option<&crate::InspectorElementId>,
1973            window: &mut Window,
1974            _: &mut App,
1975        ) -> (LayoutId, ()) {
1976            let calls = self.calls.clone();
1977            let layout_id = window.request_keyed_measured_layout(
1978                Style::default(),
1979                self.key,
1980                move |_, _, _, _| {
1981                    calls.set(calls.get() + 1);
1982                    crate::size(px(10.), px(10.))
1983                },
1984            );
1985            (layout_id, ())
1986        }
1987
1988        fn prepaint(
1989            &mut self,
1990            _: Option<&crate::GlobalElementId>,
1991            _: Option<&crate::InspectorElementId>,
1992            _: crate::Bounds<Pixels>,
1993            _: &mut (),
1994            _: &mut Window,
1995            _: &mut App,
1996        ) {
1997        }
1998
1999        fn paint(
2000            &mut self,
2001            _: Option<&crate::GlobalElementId>,
2002            _: Option<&crate::InspectorElementId>,
2003            _: crate::Bounds<Pixels>,
2004            _: &mut (),
2005            _: &mut (),
2006            _: &mut Window,
2007            _: &mut App,
2008        ) {
2009        }
2010    }
2011
2012    struct Row {
2013        keys: Vec<u32>,
2014        calls: Rc<Cell<usize>>,
2015    }
2016
2017    impl crate::Render for Row {
2018        fn render(
2019            &mut self,
2020            _: &mut Window,
2021            _: &mut crate::Context<Self>,
2022        ) -> impl crate::IntoElement {
2023            use crate::{ParentElement as _, Styled as _};
2024            crate::div()
2025                .flex()
2026                .flex_wrap()
2027                .w(px(25.))
2028                .children(self.keys.iter().map(|key| Measured {
2029                    key: *key,
2030                    calls: self.calls.clone(),
2031                }))
2032        }
2033    }
2034
2035    #[crate::test]
2036    fn unchanged_nodes_keep_their_layout_when_their_view_renders_again(
2037        cx: &mut crate::TestAppContext,
2038    ) {
2039        let calls = Rc::new(Cell::new(0));
2040        let window = cx.add_window({
2041            let calls = calls.clone();
2042            move |_, _| Row {
2043                keys: vec![1, 2, 3],
2044                calls,
2045            }
2046        });
2047        let measured_first = calls.get();
2048        assert!(measured_first >= 3);
2049
2050        // Render again without changes: each node only replays its last measurement.
2051        calls.set(0);
2052        window.update(cx, |_, _, cx| cx.notify()).unwrap();
2053        cx.run_until_parked();
2054        assert_eq!(calls.get(), 3);
2055
2056        // A changed key measures that node like a new one, and its siblings still replay.
2057        calls.set(0);
2058        window
2059            .update(cx, |row, _, cx| {
2060                row.keys[1] = 20;
2061                cx.notify();
2062            })
2063            .unwrap();
2064        cx.run_until_parked();
2065        assert!(
2066            calls.get() > 3,
2067            "the changed node is measured again: {}",
2068            calls.get()
2069        );
2070    }
2071}