Put a Taffy layout engine on window

Nathan Sobo created

Change summary

Cargo.lock                        | 29 +++++++++++++++++++++++++++++
crates/editor/src/element.rs      |  6 +++---
crates/gpui/Cargo.toml            |  1 +
crates/gpui/playground/Cargo.toml |  1 +
crates/gpui/src/app/window.rs     |  7 +++++++
crates/gpui/src/elements.rs       | 10 ++++++----
6 files changed, 47 insertions(+), 7 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -3160,6 +3160,7 @@ dependencies = [
  "smol",
  "sqlez",
  "sum_tree",
+ "taffy",
  "time 0.3.24",
  "tiny-skia",
  "usvg",
@@ -3178,6 +3179,15 @@ dependencies = [
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "grid"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0634107a3a005070dd73e27e74ecb691a94e9e5ba7829f434db7fbf73a6b5c47"
+dependencies = [
+ "no-std-compat",
+]
+
 [[package]]
 name = "h2"
 version = "0.3.20"
@@ -4598,6 +4608,12 @@ dependencies = [
  "static_assertions",
 ]
 
+[[package]]
+name = "no-std-compat"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
+
 [[package]]
 name = "node_runtime"
 version = "0.1.0"
@@ -5299,6 +5315,7 @@ dependencies = [
  "serde",
  "simplelog",
  "smallvec",
+ "taffy",
  "util",
 ]
 
@@ -7643,6 +7660,18 @@ dependencies = [
  "winx",
 ]
 
+[[package]]
+name = "taffy"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3540ec65df399929a04a485feb50144475735920cc47eaf8eba09c70b1df4055"
+dependencies = [
+ "arrayvec 0.7.4",
+ "grid",
+ "num-traits",
+ "slotmap",
+]
+
 [[package]]
 name = "take-until"
 version = "0.2.0"

crates/editor/src/element.rs 🔗

@@ -585,7 +585,7 @@ impl EditorElement {
         visible_bounds: RectF,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut ViewContext<Editor>,
+        cx: &mut PaintContext<Editor>,
     ) {
         let line_height = layout.position_map.line_height;
 
@@ -740,7 +740,7 @@ impl EditorElement {
         visible_bounds: RectF,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut ViewContext<Editor>,
+        cx: &mut PaintContext<Editor>,
     ) {
         let style = &self.style;
         let local_replica_id = editor.replica_id(cx);
@@ -1317,7 +1317,7 @@ impl EditorElement {
         visible_bounds: RectF,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut ViewContext<Editor>,
+        cx: &mut PaintContext<Editor>,
     ) {
         let scroll_position = layout.position_map.snapshot.scroll_position();
         let scroll_left = scroll_position.x() * layout.position_map.em_width;

crates/gpui/Cargo.toml 🔗

@@ -52,6 +52,7 @@ tiny-skia = "0.5"
 usvg = { version = "0.14", features = [] }
 uuid = { version = "1.1.2", features = ["v4"] }
 waker-fn = "1.1.0"
+taffy = "0.3.12"
 
 [build-dependencies]
 bindgen = "0.65.1"

crates/gpui/playground/Cargo.toml 🔗

@@ -16,6 +16,7 @@ optional_struct = "0.3.1"
 serde.workspace = true
 simplelog = "0.9"
 smallvec.workspace = true
+taffy = "0.3.12"
 util = { path = "../../util" }
 
 [dev-dependencies]

crates/gpui/src/app/window.rs 🔗

@@ -33,12 +33,14 @@ use std::{
     mem,
     ops::{Deref, DerefMut, Range, Sub},
 };
+use taffy::Taffy;
 use util::ResultExt;
 use uuid::Uuid;
 
 use super::{Reference, ViewMetadata};
 
 pub struct Window {
+    layout_engine: Taffy,
     pub(crate) root_view: Option<AnyViewHandle>,
     pub(crate) focused_view_id: Option<usize>,
     pub(crate) parents: HashMap<usize, usize>,
@@ -73,6 +75,7 @@ impl Window {
         let titlebar_height = platform_window.titlebar_height();
         let appearance = platform_window.appearance();
         let mut window = Self {
+            layout_engine: Taffy::new(),
             root_view: None,
             focused_view_id: None,
             parents: Default::default(),
@@ -207,6 +210,10 @@ impl<'a> WindowContext<'a> {
         }
     }
 
+    pub fn layout_engine(&mut self) -> &mut Taffy {
+        &mut self.window.layout_engine
+    }
+
     pub fn remove_window(&mut self) {
         self.removed = true;
     }

crates/gpui/src/elements.rs 🔗

@@ -215,7 +215,7 @@ trait AnyElementState<V> {
         origin: Vector2F,
         visible_bounds: RectF,
         view: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut PaintContext<V>,
     );
 
     fn rect_for_text_range(
@@ -288,7 +288,7 @@ impl<V, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
         origin: Vector2F,
         visible_bounds: RectF,
         view: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut PaintContext<V>,
     ) {
         *self = match mem::take(self) {
             ElementState::PostLayout {
@@ -464,7 +464,7 @@ impl<V> AnyElement<V> {
         origin: Vector2F,
         visible_bounds: RectF,
         view: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut PaintContext<V>,
     ) {
         self.state.paint(scene, origin, visible_bounds, view, cx);
     }
@@ -637,7 +637,9 @@ impl<V: View> AnyRootElement for RootElement<V> {
             .ok_or_else(|| anyhow!("paint called on a root element for a dropped view"))?;
 
         view.update(cx, |view, cx| {
-            self.element.paint(scene, origin, visible_bounds, view, cx);
+            let mut cx = PaintContext::new(cx);
+            self.element
+                .paint(scene, origin, visible_bounds, view, &mut cx);
             Ok(())
         })
     }