Skip to main content

gpui_core/
taffy.rs

1use crate::{
2    AbsoluteLength, App, Bounds, DefiniteLength, Edges, GridTemplate, Length, Pixels, Point, Size,
3    Style, Window, point, size,
4    util::{
5        ceil_to_device_pixel, round_half_toward_zero, round_stroke_to_device_pixel,
6        round_to_device_pixel,
7    },
8};
9use collections::{FxHashMap, FxHashSet};
10use smallvec::SmallVec;
11use stacksafe::{StackSafe, stacksafe};
12use std::{fmt::Debug, ops::Range};
13use taffy::{
14    TaffyTree, TraversePartialTree as _,
15    geometry::{Point as TaffyPoint, Rect as TaffyRect, Size as TaffySize},
16    prelude::{max_content, min_content},
17    style::AvailableSpace as TaffyAvailableSpace,
18    tree::{LayoutInput, NodeId},
19};
20
21type NodeMeasureFn = StackSafe<
22    Box<
23        dyn FnMut(
24            Size<Option<Pixels>>,
25            Size<AvailableSpace>,
26            &mut Window,
27            &mut App,
28        ) -> Size<Pixels>,
29    >,
30>;
31
32struct NodeContext {
33    measure: NodeMeasureFn,
34}
35pub struct TaffyLayoutEngine {
36    taffy: TaffyTree<NodeContext>,
37    absolute_layout_bounds: FxHashMap<LayoutId, Bounds<Pixels>>,
38    absolute_outer_origins: FxHashMap<LayoutId, Point<f32>>,
39    computed_layouts: FxHashSet<LayoutId>,
40}
41
42const EXPECT_MESSAGE: &str = "we should avoid taffy layout errors by construction if possible";
43
44impl TaffyLayoutEngine {
45    pub fn new() -> Self {
46        let mut taffy = TaffyTree::new();
47        taffy.disable_rounding();
48        TaffyLayoutEngine {
49            taffy,
50            absolute_layout_bounds: FxHashMap::default(),
51            absolute_outer_origins: FxHashMap::default(),
52            computed_layouts: FxHashSet::default(),
53        }
54    }
55
56    pub fn clear(&mut self) {
57        self.taffy.clear();
58        self.absolute_layout_bounds.clear();
59        self.absolute_outer_origins.clear();
60        self.computed_layouts.clear();
61    }
62
63    pub fn request_layout(
64        &mut self,
65        style: Style,
66        rem_size: Pixels,
67        scale_factor: f32,
68        children: &[LayoutId],
69    ) -> LayoutId {
70        let taffy_style = style.to_taffy(rem_size, scale_factor);
71
72        if children.is_empty() {
73            self.taffy
74                .new_leaf(taffy_style)
75                .expect(EXPECT_MESSAGE)
76                .into()
77        } else {
78            self.taffy
79                // This is safe because LayoutId is repr(transparent) to taffy::tree::NodeId.
80                .new_with_children(taffy_style, unsafe {
81                    std::mem::transmute::<&[LayoutId], &[taffy::NodeId]>(children)
82                })
83                .expect(EXPECT_MESSAGE)
84                .into()
85        }
86    }
87
88    pub fn request_measured_layout(
89        &mut self,
90        style: Style,
91        rem_size: Pixels,
92        scale_factor: f32,
93        measure: impl FnMut(
94            Size<Option<Pixels>>,
95            Size<AvailableSpace>,
96            &mut Window,
97            &mut App,
98        ) -> Size<Pixels>
99        + 'static,
100    ) -> LayoutId {
101        let taffy_style = style.to_taffy(rem_size, scale_factor);
102
103        self.taffy
104            .new_leaf_with_context(
105                taffy_style,
106                NodeContext {
107                    measure: StackSafe::new(Box::new(measure)),
108                },
109            )
110            .expect(EXPECT_MESSAGE)
111            .into()
112    }
113
114    /// Treats auto dimensions of a root node as filling the viewport while
115    /// preserving dimensions explicitly supplied by the element.
116    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(id.0).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
129        let mut style = style.clone();
130        if stretch_width {
131            style.size.width =
132                taffy::style::Dimension::length(round_to_device_pixel(size.width.0, scale_factor));
133        }
134        if stretch_height {
135            style.size.height =
136                taffy::style::Dimension::length(round_to_device_pixel(size.height.0, scale_factor));
137        }
138        self.taffy.set_style(id.0, style).expect(EXPECT_MESSAGE);
139    }
140
141    // Used to understand performance
142    #[allow(dead_code)]
143    fn count_all_children(&self, parent: LayoutId) -> anyhow::Result<u32> {
144        let mut count = 0;
145
146        for child in self.taffy.children(parent.0)? {
147            // Count this child.
148            count += 1;
149
150            // Count all of this child's children.
151            count += self.count_all_children(LayoutId(child))?
152        }
153
154        Ok(count)
155    }
156
157    // Used to understand performance
158    #[allow(dead_code)]
159    fn max_depth(&self, depth: u32, parent: LayoutId) -> anyhow::Result<u32> {
160        println!(
161            "{parent:?} at depth {depth} has {} children",
162            self.taffy.child_count(parent.0)
163        );
164
165        let mut max_child_depth = 0;
166
167        for child in self.taffy.children(parent.0)? {
168            max_child_depth = std::cmp::max(max_child_depth, self.max_depth(0, LayoutId(child))?);
169        }
170
171        Ok(depth + 1 + max_child_depth)
172    }
173
174    // Used to understand performance
175    #[allow(dead_code)]
176    fn get_edges(&self, parent: LayoutId) -> anyhow::Result<Vec<(LayoutId, LayoutId)>> {
177        let mut edges = Vec::new();
178
179        for child in self.taffy.children(parent.0)? {
180            edges.push((parent, LayoutId(child)));
181
182            edges.extend(self.get_edges(LayoutId(child))?);
183        }
184
185        Ok(edges)
186    }
187
188    #[stacksafe]
189    pub fn compute_layout(
190        &mut self,
191        id: LayoutId,
192        available_space: Size<AvailableSpace>,
193        window: &mut Window,
194        cx: &mut App,
195    ) {
196        // Leaving this here until we have a better instrumentation approach.
197        // println!("Laying out {} children", self.count_all_children(id)?);
198        // println!("Max layout depth: {}", self.max_depth(0, id)?);
199
200        // Output the edges (branches) of the tree in Mermaid format for visualization.
201        // println!("Edges:");
202        // for (a, b) in self.get_edges(id)? {
203        //     println!("N{} --> N{}", u64::from(a), u64::from(b));
204        // }
205        //
206
207        if !self.computed_layouts.insert(id) {
208            let mut stack = SmallVec::<[LayoutId; 64]>::new();
209            stack.push(id);
210            while let Some(id) = stack.pop() {
211                self.absolute_layout_bounds.remove(&id);
212                self.absolute_outer_origins.remove(&id);
213                stack.extend(
214                    self.taffy
215                        .children(id.into())
216                        .expect(EXPECT_MESSAGE)
217                        .into_iter()
218                        .map(Into::into),
219                );
220            }
221        }
222
223        let scale_factor = window.scale_factor();
224
225        let transform = |v: AvailableSpace| match v {
226            AvailableSpace::Definite(pixels) => {
227                AvailableSpace::Definite(Pixels(pixels.0 * scale_factor))
228            }
229            AvailableSpace::MinContent => AvailableSpace::MinContent,
230            AvailableSpace::MaxContent => AvailableSpace::MaxContent,
231        };
232        let available_space = size(
233            transform(available_space.width),
234            transform(available_space.height),
235        );
236
237        self.taffy
238            .compute_layout_with_measure(
239                id.into(),
240                available_space.into(),
241                |inputs: LayoutInput, _id, node_context, style| {
242                    taffy::compute_leaf_layout(
243                        inputs,
244                        style,
245                        |_, _| 0.0,
246                        |known_dimensions, available_space| {
247                            let Some(node_context) = node_context else {
248                                return TaffySize::ZERO;
249                            };
250
251                            let known_dimensions = Size {
252                                width: known_dimensions.width.map(|e| Pixels(e / scale_factor)),
253                                height: known_dimensions.height.map(|e| Pixels(e / scale_factor)),
254                            };
255
256                            let available_space: Size<AvailableSpace> = available_space.into();
257                            let untransform = |ev: AvailableSpace| match ev {
258                                AvailableSpace::Definite(pixels) => {
259                                    AvailableSpace::Definite(Pixels(pixels.0 / scale_factor))
260                                }
261                                AvailableSpace::MinContent => AvailableSpace::MinContent,
262                                AvailableSpace::MaxContent => AvailableSpace::MaxContent,
263                            };
264                            let available_space = size(
265                                untransform(available_space.width),
266                                untransform(available_space.height),
267                            );
268
269                            let measured_size: Size<Pixels> = (node_context.measure)(
270                                known_dimensions,
271                                available_space,
272                                window,
273                                cx,
274                            );
275                            snap_measured_size_to_device_pixels(measured_size, scale_factor).into()
276                        },
277                    )
278                },
279            )
280            .expect(EXPECT_MESSAGE);
281    }
282
283    // Pixel snapping converts layout coordinates into integer device-pixel
284    // coordinates so painted edges land on physical pixel boundaries. Absolute
285    // edge snapping preserves closure for coincident layout edges; pre-layout
286    // metric snapping keeps fixed lengths such as borders and gaps stable.
287    pub fn layout_bounds(&mut self, id: LayoutId, scale_factor: f32) -> Bounds<Pixels> {
288        if let Some(layout) = self.absolute_layout_bounds.get(&id).cloned() {
289            return layout;
290        }
291
292        let layout = self.taffy.layout(id.into()).expect(EXPECT_MESSAGE);
293        let layout_location = layout.location;
294        let layout_size = layout.size;
295        let parent = self.taffy.parent(id.0);
296
297        let absolute_outer_origin = match parent {
298            Some(parent_id) => {
299                let parent_id = LayoutId::from(parent_id);
300                self.layout_bounds(parent_id, scale_factor);
301                let parent_origin = *self
302                    .absolute_outer_origins
303                    .get(&parent_id)
304                    .expect("parent absolute outer origin should be cached");
305                parent_origin + Point::from(layout_location)
306            }
307            None => Point::from(layout_location),
308        };
309        self.absolute_outer_origins
310            .insert(id, absolute_outer_origin);
311
312        let layout_size = Size::from(layout_size);
313        let absolute_far = absolute_outer_origin + point(layout_size.width, layout_size.height);
314        let snapped_bounds = Bounds::from_corners(
315            absolute_outer_origin.map(round_half_toward_zero),
316            absolute_far.map(round_half_toward_zero),
317        );
318
319        let bounds = (snapped_bounds / scale_factor).map(Pixels);
320        self.absolute_layout_bounds.insert(id, bounds);
321
322        bounds
323    }
324}
325
326/// A unique identifier for a layout node, generated when requesting a layout from Taffy
327#[derive(Copy, Clone, Eq, PartialEq, Debug)]
328#[repr(transparent)]
329pub struct LayoutId(NodeId);
330
331impl std::hash::Hash for LayoutId {
332    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
333        u64::from(self.0).hash(state);
334    }
335}
336
337impl From<NodeId> for LayoutId {
338    fn from(node_id: NodeId) -> Self {
339        Self(node_id)
340    }
341}
342
343impl From<LayoutId> for NodeId {
344    fn from(layout_id: LayoutId) -> NodeId {
345        layout_id.0
346    }
347}
348
349trait ToTaffy<Output> {
350    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> Output;
351}
352
353fn snap_measured_size_to_device_pixels(size: Size<Pixels>, scale_factor: f32) -> Size<f32> {
354    size.map(|d| ceil_to_device_pixel(d.0.max(0.0), scale_factor))
355}
356
357fn border_widths_to_taffy(
358    widths: &Edges<AbsoluteLength>,
359    rem_size: Pixels,
360    scale_factor: f32,
361) -> TaffyRect<taffy::style::LengthPercentage> {
362    let snap = |w: &AbsoluteLength| {
363        taffy::style::LengthPercentage::length(round_stroke_to_device_pixel(
364            w.to_pixels(rem_size).0,
365            scale_factor,
366        ))
367    };
368    TaffyRect {
369        top: snap(&widths.top),
370        right: snap(&widths.right),
371        bottom: snap(&widths.bottom),
372        left: snap(&widths.left),
373    }
374}
375
376impl ToTaffy<taffy::style::Style> for Style {
377    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::Style {
378        use taffy::style_helpers::{fr, length, minmax, repeat};
379
380        fn to_grid_line(
381            placement: &Range<crate::GridPlacement>,
382        ) -> taffy::Line<taffy::GridPlacement> {
383            taffy::Line {
384                start: placement.start.into(),
385                end: placement.end.into(),
386            }
387        }
388
389        fn to_grid_repeat<T: taffy::style::CheapCloneStr>(
390            unit: &Option<GridTemplate>,
391        ) -> Vec<taffy::GridTemplateComponent<T>> {
392            unit.map(|template| match template.min_size {
393                crate::TemplateColumnMinSize::Zero => {
394                    vec![repeat(
395                        template.repeat,
396                        vec![minmax(length(0.0_f32), fr(1.0_f32))],
397                    )]
398                }
399                crate::TemplateColumnMinSize::MinContent => {
400                    vec![repeat(
401                        template.repeat,
402                        vec![minmax(min_content(), fr(1.0_f32))],
403                    )]
404                }
405                crate::TemplateColumnMinSize::MaxContent => {
406                    vec![repeat(
407                        template.repeat,
408                        vec![minmax(length(0.0_f32), max_content())],
409                    )]
410                }
411            })
412            .unwrap_or_default()
413        }
414
415        taffy::style::Style {
416            display: self.display.into(),
417            overflow: self.overflow.into(),
418            scrollbar_width: self.scrollbar_width.to_taffy(rem_size, scale_factor),
419            position: self.position.into(),
420            inset: self.inset.to_taffy(rem_size, scale_factor),
421            size: self.size.to_taffy(rem_size, scale_factor),
422            min_size: self.min_size.to_taffy(rem_size, scale_factor),
423            max_size: self.max_size.to_taffy(rem_size, scale_factor),
424            aspect_ratio: self.aspect_ratio,
425            margin: self.margin.to_taffy(rem_size, scale_factor),
426            padding: self.padding.to_taffy(rem_size, scale_factor),
427            border: border_widths_to_taffy(&self.border_widths, rem_size, scale_factor),
428            align_items: self.align_items.map(Into::into).unwrap_or_default(),
429            align_self: self.align_self.map(|x| x.into()),
430            align_content: self.align_content.map(Into::into).unwrap_or_default(),
431            justify_content: self.justify_content.map(Into::into).unwrap_or_default(),
432            gap: self.gap.to_taffy(rem_size, scale_factor),
433            flex_direction: self.flex_direction.into(),
434            flex_wrap: self.flex_wrap.into(),
435            flex_basis: self.flex_basis.to_taffy(rem_size, scale_factor),
436            flex_grow: self.flex_grow,
437            flex_shrink: self.flex_shrink,
438            grid_template_rows: to_grid_repeat(&self.grid_rows),
439            grid_template_columns: to_grid_repeat(&self.grid_cols),
440            grid_row: self
441                .grid_location
442                .as_ref()
443                .map(|location| to_grid_line(&location.row))
444                .unwrap_or_default(),
445            grid_column: self
446                .grid_location
447                .as_ref()
448                .map(|location| to_grid_line(&location.column))
449                .unwrap_or_default(),
450            ..Default::default()
451        }
452    }
453}
454
455impl ToTaffy<f32> for AbsoluteLength {
456    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> f32 {
457        round_to_device_pixel(self.to_pixels(rem_size).0, scale_factor)
458    }
459}
460
461impl ToTaffy<taffy::style::LengthPercentageAuto> for Length {
462    fn to_taffy(
463        &self,
464        rem_size: Pixels,
465        scale_factor: f32,
466    ) -> taffy::prelude::LengthPercentageAuto {
467        match self {
468            Length::Definite(length) => length.to_taffy(rem_size, scale_factor),
469            Length::Auto => taffy::prelude::LengthPercentageAuto::auto(),
470        }
471    }
472}
473
474impl ToTaffy<taffy::style::Dimension> for Length {
475    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::prelude::Dimension {
476        match self {
477            Length::Definite(length) => length.to_taffy(rem_size, scale_factor),
478            Length::Auto => taffy::prelude::Dimension::auto(),
479        }
480    }
481}
482
483impl ToTaffy<taffy::style::LengthPercentage> for DefiniteLength {
484    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentage {
485        match self {
486            DefiniteLength::Absolute(length) => length.to_taffy(rem_size, scale_factor),
487            DefiniteLength::Fraction(fraction) => {
488                taffy::style::LengthPercentage::percent(*fraction)
489            }
490        }
491    }
492}
493
494impl ToTaffy<taffy::style::LengthPercentageAuto> for DefiniteLength {
495    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentageAuto {
496        match self {
497            DefiniteLength::Absolute(length) => length.to_taffy(rem_size, scale_factor),
498            DefiniteLength::Fraction(fraction) => {
499                taffy::style::LengthPercentageAuto::percent(*fraction)
500            }
501        }
502    }
503}
504
505impl ToTaffy<taffy::style::Dimension> for DefiniteLength {
506    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::Dimension {
507        match self {
508            DefiniteLength::Absolute(length) => length.to_taffy(rem_size, scale_factor),
509            DefiniteLength::Fraction(fraction) => taffy::style::Dimension::percent(*fraction),
510        }
511    }
512}
513
514impl ToTaffy<taffy::style::LengthPercentage> for AbsoluteLength {
515    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentage {
516        taffy::style::LengthPercentage::length(self.to_taffy(rem_size, scale_factor))
517    }
518}
519
520impl ToTaffy<taffy::style::LengthPercentageAuto> for AbsoluteLength {
521    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentageAuto {
522        taffy::style::LengthPercentageAuto::length(self.to_taffy(rem_size, scale_factor))
523    }
524}
525
526impl ToTaffy<taffy::style::Dimension> for AbsoluteLength {
527    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::Dimension {
528        taffy::style::Dimension::length(self.to_taffy(rem_size, scale_factor))
529    }
530}
531
532impl<T, T2> From<TaffyPoint<T>> for Point<T2>
533where
534    T: Into<T2>,
535    T2: Clone + Debug + Default + PartialEq,
536{
537    fn from(point: TaffyPoint<T>) -> Point<T2> {
538        Point {
539            x: point.x.into(),
540            y: point.y.into(),
541        }
542    }
543}
544
545impl<T, T2> From<Point<T>> for TaffyPoint<T2>
546where
547    T: Into<T2> + Clone + Debug + Default + PartialEq,
548{
549    fn from(val: Point<T>) -> Self {
550        TaffyPoint {
551            x: val.x.into(),
552            y: val.y.into(),
553        }
554    }
555}
556
557impl<T, U> ToTaffy<TaffySize<U>> for Size<T>
558where
559    T: ToTaffy<U> + Clone + Debug + Default + PartialEq,
560{
561    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> TaffySize<U> {
562        TaffySize {
563            width: self.width.to_taffy(rem_size, scale_factor),
564            height: self.height.to_taffy(rem_size, scale_factor),
565        }
566    }
567}
568
569impl<T, U> ToTaffy<TaffyRect<U>> for Edges<T>
570where
571    T: ToTaffy<U> + Clone + Debug + Default + PartialEq,
572{
573    fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> TaffyRect<U> {
574        TaffyRect {
575            top: self.top.to_taffy(rem_size, scale_factor),
576            right: self.right.to_taffy(rem_size, scale_factor),
577            bottom: self.bottom.to_taffy(rem_size, scale_factor),
578            left: self.left.to_taffy(rem_size, scale_factor),
579        }
580    }
581}
582
583impl<T, U> From<TaffySize<T>> for Size<U>
584where
585    T: Into<U>,
586    U: Clone + Debug + Default + PartialEq,
587{
588    fn from(taffy_size: TaffySize<T>) -> Self {
589        Size {
590            width: taffy_size.width.into(),
591            height: taffy_size.height.into(),
592        }
593    }
594}
595
596impl<T, U> From<Size<T>> for TaffySize<U>
597where
598    T: Into<U> + Clone + Debug + Default + PartialEq,
599{
600    fn from(size: Size<T>) -> Self {
601        TaffySize {
602            width: size.width.into(),
603            height: size.height.into(),
604        }
605    }
606}
607
608/// The space available for an element to be laid out in
609#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
610pub enum AvailableSpace {
611    /// The amount of space available is the specified number of pixels
612    Definite(Pixels),
613    /// The amount of space available is indefinite and the node should be laid out under a min-content constraint
614    #[default]
615    MinContent,
616    /// The amount of space available is indefinite and the node should be laid out under a max-content constraint
617    MaxContent,
618}
619
620pub(crate) fn available_space_for_optional_width(width: Option<Pixels>) -> AvailableSpace {
621    width.map_or(AvailableSpace::MaxContent, AvailableSpace::Definite)
622}
623
624impl AvailableSpace {
625    /// Returns a `Size` with both width and height set to `AvailableSpace::MinContent`.
626    ///
627    /// This function is useful when you want to create a `Size` with the minimum content constraints
628    /// for both dimensions.
629    ///
630    /// # Examples
631    ///
632    /// ```
633    /// use gpui::AvailableSpace;
634    /// let min_content_size = AvailableSpace::min_size();
635    /// assert_eq!(min_content_size.width, AvailableSpace::MinContent);
636    /// assert_eq!(min_content_size.height, AvailableSpace::MinContent);
637    /// ```
638    pub const fn min_size() -> Size<Self> {
639        Size {
640            width: Self::MinContent,
641            height: Self::MinContent,
642        }
643    }
644}
645
646impl From<AvailableSpace> for TaffyAvailableSpace {
647    fn from(space: AvailableSpace) -> TaffyAvailableSpace {
648        match space {
649            AvailableSpace::Definite(Pixels(value)) => TaffyAvailableSpace::Definite(value),
650            AvailableSpace::MinContent => TaffyAvailableSpace::MinContent,
651            AvailableSpace::MaxContent => TaffyAvailableSpace::MaxContent,
652        }
653    }
654}
655
656impl From<TaffyAvailableSpace> for AvailableSpace {
657    fn from(space: TaffyAvailableSpace) -> AvailableSpace {
658        match space {
659            TaffyAvailableSpace::Definite(value) => AvailableSpace::Definite(Pixels(value)),
660            TaffyAvailableSpace::MinContent => AvailableSpace::MinContent,
661            TaffyAvailableSpace::MaxContent => AvailableSpace::MaxContent,
662        }
663    }
664}
665
666impl From<Pixels> for AvailableSpace {
667    fn from(pixels: Pixels) -> Self {
668        AvailableSpace::Definite(pixels)
669    }
670}
671
672impl From<Size<Pixels>> for Size<AvailableSpace> {
673    fn from(size: Size<Pixels>) -> Self {
674        Size {
675            width: AvailableSpace::Definite(size.width),
676            height: AvailableSpace::Definite(size.height),
677        }
678    }
679}
680
681#[cfg(test)]
682mod tests {
683    use super::*;
684    use crate::px;
685
686    #[test]
687    fn optional_width_uses_max_content_when_unbounded() {
688        assert_eq!(
689            available_space_for_optional_width(None),
690            AvailableSpace::MaxContent
691        );
692        assert_eq!(
693            available_space_for_optional_width(Some(px(320.0))),
694            AvailableSpace::Definite(px(320.0))
695        );
696    }
697}