Pass a `WindowContext` in `request_measured_layout`

Antonio Scandurra and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

crates/gpui2/src/elements/text.rs         |  6 ++--
crates/gpui2/src/elements/uniform_list.rs |  3 -
crates/gpui2/src/taffy.rs                 | 28 +++++++++++++++++-------
crates/gpui2/src/view.rs                  |  4 --
crates/gpui2/src/window.rs                | 27 +++++++++++++++--------
5 files changed, 42 insertions(+), 26 deletions(-)

Detailed changes

crates/gpui2/src/elements/text.rs 🔗

@@ -144,7 +144,6 @@ impl TextState {
         runs: Option<Vec<TextRun>>,
         cx: &mut WindowContext,
     ) -> LayoutId {
-        let text_system = cx.text_system().clone();
         let text_style = cx.text_style();
         let font_size = text_style.font_size.to_pixels(cx.rem_size());
         let line_height = text_style
@@ -161,7 +160,7 @@ impl TextState {
         let layout_id = cx.request_measured_layout(Default::default(), {
             let element_state = self.clone();
 
-            move |known_dimensions, available_space| {
+            move |known_dimensions, available_space, cx| {
                 let wrap_width = if text_style.white_space == WhiteSpace::Normal {
                     known_dimensions.width.or(match available_space.width {
                         crate::AvailableSpace::Definite(x) => Some(x),
@@ -179,7 +178,8 @@ impl TextState {
                     }
                 }
 
-                let Some(lines) = text_system
+                let Some(lines) = cx
+                    .text_system()
                     .shape_text(
                         &text, font_size, &runs, wrap_width, // Wrap if we know the width.
                     )

crates/gpui2/src/elements/uniform_list.rs 🔗

@@ -119,8 +119,7 @@ impl Element for UniformList {
                 .layout(state.map(|s| s.interactive), cx, |style, cx| {
                     cx.request_measured_layout(
                         style,
-                        move |known_dimensions: Size<Option<Pixels>>,
-                              available_space: Size<AvailableSpace>| {
+                        move |known_dimensions, available_space, _cx| {
                             let desired_height = item_size.height * max_items;
                             let width =
                                 known_dimensions

crates/gpui2/src/taffy.rs 🔗

@@ -1,4 +1,7 @@
-use super::{AbsoluteLength, Bounds, DefiniteLength, Edges, Length, Pixels, Point, Size, Style};
+use crate::{
+    AbsoluteLength, Bounds, DefiniteLength, Edges, Length, Pixels, Point, Size, Style,
+    WindowContext,
+};
 use collections::{HashMap, HashSet};
 use smallvec::SmallVec;
 use std::fmt::Debug;
@@ -16,7 +19,13 @@ pub struct TaffyLayoutEngine {
     computed_layouts: HashSet<LayoutId>,
     nodes_to_measure: HashMap<
         LayoutId,
-        Box<dyn FnMut(Size<Option<Pixels>>, Size<AvailableSpace>) -> Size<Pixels>>,
+        Box<
+            dyn FnMut(
+                Size<Option<Pixels>>,
+                Size<AvailableSpace>,
+                &mut WindowContext,
+            ) -> Size<Pixels>,
+        >,
     >,
 }
 
@@ -69,7 +78,8 @@ impl TaffyLayoutEngine {
         &mut self,
         style: Style,
         rem_size: Pixels,
-        measure: impl FnMut(Size<Option<Pixels>>, Size<AvailableSpace>) -> Size<Pixels> + 'static,
+        measure: impl FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut WindowContext) -> Size<Pixels>
+            + 'static,
     ) -> LayoutId {
         let style = style.to_taffy(rem_size);
 
@@ -129,7 +139,12 @@ impl TaffyLayoutEngine {
         Ok(edges)
     }
 
-    pub fn compute_layout(&mut self, id: LayoutId, available_space: Size<AvailableSpace>) {
+    pub fn compute_layout(
+        &mut self,
+        id: LayoutId,
+        available_space: Size<AvailableSpace>,
+        cx: &mut WindowContext,
+    ) {
         // Leaving this here until we have a better instrumentation approach.
         // println!("Laying out {} children", self.count_all_children(id)?);
         // println!("Max layout depth: {}", self.max_depth(0, id)?);
@@ -158,8 +173,6 @@ impl TaffyLayoutEngine {
         }
 
         // let started_at = std::time::Instant::now();
-        dbg!(">>>>>>>>>>>>>");
-
         self.taffy
             .compute_layout_with_measure(
                 id.into(),
@@ -174,12 +187,11 @@ impl TaffyLayoutEngine {
                         height: known_dimensions.height.map(Pixels),
                     };
 
-                    measure(known_dimensions, available_space.into()).into()
+                    measure(known_dimensions, available_space.into(), cx).into()
                 },
             )
             .expect(EXPECT_MESSAGE);
 
-        dbg!("<<<<<<");
         // println!("compute_layout took {:?}", started_at.elapsed());
     }
 

crates/gpui2/src/view.rs 🔗

@@ -209,9 +209,7 @@ impl AnyView {
     ) {
         cx.with_absolute_element_offset(origin, |cx| {
             let (layout_id, rendered_element) = (self.layout)(self, cx);
-            cx.window
-                .layout_engine
-                .compute_layout(layout_id, available_space);
+            cx.compute_layout(layout_id, available_space);
             (self.paint)(self, rendered_element, cx);
         })
     }

crates/gpui2/src/window.rs 🔗

@@ -209,7 +209,7 @@ pub struct Window {
     sprite_atlas: Arc<dyn PlatformAtlas>,
     rem_size: Pixels,
     viewport_size: Size<Pixels>,
-    pub(crate) layout_engine: TaffyLayoutEngine,
+    layout_engine: Option<TaffyLayoutEngine>,
     pub(crate) root_view: Option<AnyView>,
     pub(crate) element_id_stack: GlobalElementId,
     pub(crate) previous_frame: Frame,
@@ -327,7 +327,7 @@ impl Window {
             sprite_atlas,
             rem_size: px(16.),
             viewport_size: content_size,
-            layout_engine: TaffyLayoutEngine::new(),
+            layout_engine: Some(TaffyLayoutEngine::new()),
             root_view: None,
             element_id_stack: GlobalElementId::default(),
             previous_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
@@ -606,9 +606,11 @@ impl<'a> WindowContext<'a> {
         self.app.layout_id_buffer.extend(children.into_iter());
         let rem_size = self.rem_size();
 
-        self.window
-            .layout_engine
-            .request_layout(style, rem_size, &self.app.layout_id_buffer)
+        self.window.layout_engine.as_mut().unwrap().request_layout(
+            style,
+            rem_size,
+            &self.app.layout_id_buffer,
+        )
     }
 
     /// Add a node to the layout tree for the current frame. Instead of taking a `Style` and children,
@@ -618,7 +620,8 @@ impl<'a> WindowContext<'a> {
     /// The given closure is invoked at layout time with the known dimensions and available space and
     /// returns a `Size`.
     pub fn request_measured_layout<
-        F: FnMut(Size<Option<Pixels>>, Size<AvailableSpace>) -> Size<Pixels> + 'static,
+        F: FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut WindowContext) -> Size<Pixels>
+            + 'static,
     >(
         &mut self,
         style: Style,
@@ -627,13 +630,15 @@ impl<'a> WindowContext<'a> {
         let rem_size = self.rem_size();
         self.window
             .layout_engine
+            .as_mut()
+            .unwrap()
             .request_measured_layout(style, rem_size, measure)
     }
 
     pub fn compute_layout(&mut self, layout_id: LayoutId, available_space: Size<AvailableSpace>) {
-        self.window
-            .layout_engine
-            .compute_layout(layout_id, available_space)
+        let mut layout_engine = self.window.layout_engine.take().unwrap();
+        layout_engine.compute_layout(layout_id, available_space, self);
+        self.window.layout_engine = Some(layout_engine);
     }
 
     /// Obtain the bounds computed for the given LayoutId relative to the window. This method should not
@@ -643,6 +648,8 @@ impl<'a> WindowContext<'a> {
         let mut bounds = self
             .window
             .layout_engine
+            .as_mut()
+            .unwrap()
             .layout_bounds(layout_id)
             .map(Into::into);
         bounds.origin += self.element_offset();
@@ -1189,7 +1196,7 @@ impl<'a> WindowContext<'a> {
         self.text_system().start_frame();
 
         let window = &mut *self.window;
-        window.layout_engine.clear();
+        window.layout_engine.as_mut().unwrap().clear();
 
         mem::swap(&mut window.previous_frame, &mut window.current_frame);
         let frame = &mut window.current_frame;