Create a `SceneBuilder` and sort stacking contexts when calling `build`

Antonio Scandurra created

Change summary

crates/editor/src/element.rs |  8 ++--
crates/gpui/src/gpui.rs      |  2 
crates/gpui/src/presenter.rs | 21 +++++++-----
crates/gpui/src/scene.rs     | 61 ++++++++++++++++++++++++-------------
4 files changed, 57 insertions(+), 35 deletions(-)

Detailed changes

crates/editor/src/element.rs 🔗

@@ -31,7 +31,7 @@ use gpui::{
     text_layout::{self, Line, RunStyle, TextLayoutCache},
     AppContext, Axis, Border, CursorRegion, Element, ElementBox, EventContext, LayoutContext,
     Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent, MouseRegion, MutableAppContext,
-    PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
+    PaintContext, Quad, SceneBuilder, SizeConstraint, ViewContext, WeakViewHandle,
 };
 use json::json;
 use language::{Bias, CursorShape, DiagnosticSeverity, OffsetUtf16, Point, Selection};
@@ -2189,7 +2189,7 @@ pub struct HighlightedRangeLine {
 }
 
 impl HighlightedRange {
-    pub fn paint(&self, bounds: RectF, scene: &mut Scene) {
+    pub fn paint(&self, bounds: RectF, scene: &mut SceneBuilder) {
         if self.lines.len() >= 2 && self.lines[0].start_x > self.lines[1].end_x {
             self.paint_lines(self.start_y, &self.lines[0..1], bounds, scene);
             self.paint_lines(
@@ -2208,7 +2208,7 @@ impl HighlightedRange {
         start_y: f32,
         lines: &[HighlightedRangeLine],
         bounds: RectF,
-        scene: &mut Scene,
+        scene: &mut SceneBuilder,
     ) {
         if lines.is_empty() {
             return;
@@ -2375,7 +2375,7 @@ mod tests {
 
         let mut element = EditorElement::new(editor.downgrade(), editor.read(cx).style(cx));
 
-        let mut scene = Scene::new(1.0);
+        let mut scene = SceneBuilder::new(1.0);
         let mut presenter = cx.build_presenter(window_id, 30., Default::default());
         let mut layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx);
         let (size, mut state) = element.layout(

crates/gpui/src/gpui.rs 🔗

@@ -16,7 +16,7 @@ pub mod fonts;
 pub mod geometry;
 mod presenter;
 pub mod scene;
-pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene};
+pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder};
 pub mod text_layout;
 pub use text_layout::TextLayoutCache;
 mod util;

crates/gpui/src/presenter.rs 🔗

@@ -8,13 +8,14 @@ use crate::{
     platform::{CursorStyle, Event},
     scene::{
         CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover,
-        MouseMove, MouseScrollWheel, MouseUp, MouseUpOut,
+        MouseMove, MouseScrollWheel, MouseUp, MouseUpOut, Scene,
     },
     text_layout::TextLayoutCache,
     Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, Appearance,
     AssetCache, ElementBox, Entity, FontSystem, ModelHandle, MouseButton, MouseMovedEvent,
-    MouseRegion, MouseRegionId, ParentId, ReadModel, ReadView, RenderContext, RenderParams, Scene,
-    UpgradeModelHandle, UpgradeViewHandle, View, ViewHandle, WeakModelHandle, WeakViewHandle,
+    MouseRegion, MouseRegionId, ParentId, ReadModel, ReadView, RenderContext, RenderParams,
+    SceneBuilder, UpgradeModelHandle, UpgradeViewHandle, View, ViewHandle, WeakModelHandle,
+    WeakViewHandle,
 };
 use collections::{HashMap, HashSet};
 use pathfinder_geometry::vector::{vec2f, Vector2F};
@@ -135,17 +136,18 @@ impl Presenter {
         refreshing: bool,
         cx: &mut MutableAppContext,
     ) -> Scene {
-        let mut scene = Scene::new(scale_factor);
+        let mut scene_builder = SceneBuilder::new(scale_factor);
 
         if let Some(root_view_id) = cx.root_view_id(self.window_id) {
             self.layout(window_size, refreshing, cx);
-            let mut paint_cx = self.build_paint_context(&mut scene, window_size, cx);
+            let mut paint_cx = self.build_paint_context(&mut scene_builder, window_size, cx);
             paint_cx.paint(
                 root_view_id,
                 Vector2F::zero(),
                 RectF::new(Vector2F::zero(), window_size),
             );
             self.text_layout_cache.finish_frame();
+            let scene = scene_builder.build();
             self.cursor_regions = scene.cursor_regions();
             self.mouse_regions = scene.mouse_regions();
 
@@ -154,11 +156,12 @@ impl Presenter {
                     self.dispatch_event(event, true, cx);
                 }
             }
+
+            scene
         } else {
             log::error!("could not find root_view_id for window {}", self.window_id);
+            scene_builder.build()
         }
-
-        scene
     }
 
     fn layout(&mut self, window_size: Vector2F, refreshing: bool, cx: &mut MutableAppContext) {
@@ -196,7 +199,7 @@ impl Presenter {
 
     pub fn build_paint_context<'a>(
         &'a mut self,
-        scene: &'a mut Scene,
+        scene: &'a mut SceneBuilder,
         window_size: Vector2F,
         cx: &'a mut MutableAppContext,
     ) -> PaintContext {
@@ -689,7 +692,7 @@ pub struct PaintContext<'a> {
     rendered_views: &'a mut HashMap<usize, ElementBox>,
     view_stack: Vec<usize>,
     pub window_size: Vector2F,
-    pub scene: &'a mut Scene,
+    pub scene: &'a mut SceneBuilder,
     pub font_cache: &'a FontCache,
     pub text_layout_cache: &'a TextLayoutCache,
     pub app: &'a AppContext,

crates/gpui/src/scene.rs 🔗

@@ -18,7 +18,7 @@ use crate::{
 pub use mouse_event::*;
 pub use mouse_region::*;
 
-pub struct Scene {
+pub struct SceneBuilder {
     scale_factor: f32,
     stacking_contexts: Vec<StackingContext>,
     active_stacking_context_stack: Vec<usize>,
@@ -176,18 +176,12 @@ pub struct Image {
     pub data: Arc<ImageData>,
 }
 
-impl Scene {
-    pub fn new(scale_factor: f32) -> Self {
-        let stacking_context = StackingContext::new(0, None);
-        Scene {
-            scale_factor,
-            stacking_contexts: vec![stacking_context],
-            active_stacking_context_stack: vec![0],
-            #[cfg(debug_assertions)]
-            mouse_region_ids: Default::default(),
-        }
-    }
+pub struct Scene {
+    scale_factor: f32,
+    stacking_contexts: Vec<StackingContext>,
+}
 
+impl Scene {
     pub fn scale_factor(&self) -> f32 {
         self.scale_factor
     }
@@ -204,16 +198,41 @@ impl Scene {
     }
 
     pub fn mouse_regions(&self) -> Vec<(MouseRegion, usize)> {
-        let mut regions = Vec::new();
-        for stacking_context in self.stacking_contexts.iter() {
-            for layer in &stacking_context.layers {
-                for mouse_region in &layer.mouse_regions {
-                    regions.push((mouse_region.clone(), stacking_context.depth));
-                }
-            }
+        self.stacking_contexts
+            .iter()
+            .flat_map(|context| {
+                context
+                    .layers
+                    .iter()
+                    .flat_map(|layer| &layer.mouse_regions)
+                    .map(|region| (region.clone(), context.depth))
+            })
+            .collect()
+    }
+}
+
+impl SceneBuilder {
+    pub fn new(scale_factor: f32) -> Self {
+        let stacking_context = StackingContext::new(0, None);
+        SceneBuilder {
+            scale_factor,
+            stacking_contexts: vec![stacking_context],
+            active_stacking_context_stack: vec![0],
+            #[cfg(debug_assertions)]
+            mouse_region_ids: Default::default(),
+        }
+    }
+
+    pub fn build(mut self) -> Scene {
+        self.stacking_contexts.sort_by_key(|context| context.depth);
+        Scene {
+            scale_factor: self.scale_factor,
+            stacking_contexts: self.stacking_contexts,
         }
-        regions.sort_by_key(|(_, depth)| *depth);
-        regions
+    }
+
+    pub fn scale_factor(&self) -> f32 {
+        self.scale_factor
     }
 
     pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>) {