From bdced12376b44b38a8d67c3652c00d03b4cc0f6a Mon Sep 17 00:00:00 2001 From: marc2332 Date: Fri, 23 Aug 2024 21:35:16 +0200 Subject: [PATCH] feat: consider viewports when expanding the dirty area --- crates/core/src/elements/utils.rs | 40 +++++++++++++++++++++++----- crates/core/src/render/compositor.rs | 11 ++++++-- crates/native-core/src/real_dom.rs | 3 ++- crates/torin/src/geometry.rs | 9 +++++++ examples/floating_editors.rs | 4 ++- 5 files changed, 57 insertions(+), 10 deletions(-) diff --git a/crates/core/src/elements/utils.rs b/crates/core/src/elements/utils.rs index 83aaf3041..9d3d8e446 100644 --- a/crates/core/src/elements/utils.rs +++ b/crates/core/src/elements/utils.rs @@ -6,13 +6,20 @@ use freya_engine::prelude::{ use freya_native_core::{ prelude::NodeImmutable, tags::TagName, + NodeId, }; -use freya_node_state::TransformState; -use torin::prelude::{ - Area, - AreaModel, - CursorPoint, - LayoutNode, +use freya_node_state::{ + TransformState, + ViewportState, +}; +use torin::{ + prelude::{ + Area, + AreaModel, + CursorPoint, + LayoutNode, + }, + torin::Torin, }; use super::*; @@ -60,6 +67,27 @@ pub trait ElementUtils { layout_node.visible_area() } + fn drawing_area_with_viewports( + &self, + layout_node: &LayoutNode, + node_ref: &DioxusNode, + layout: &Torin, + scale_factor: f32, + ) -> Option { + let mut drawing_area = self.drawing_area(layout_node, node_ref, scale_factor); + let node_viewports = node_ref.get::().unwrap(); + + for viewport_id in &node_viewports.viewports { + let viewport = layout.get(*viewport_id).unwrap().visible_area(); + drawing_area.clip(&viewport); + if !viewport.intersects(&drawing_area) { + return None; + } + } + + Some(drawing_area) + } + /// Measure the area for this element considering other /// factors like shadows or borders, which are not part of the layout. fn drawing_area( diff --git a/crates/core/src/render/compositor.rs b/crates/core/src/render/compositor.rs index f603c65a8..8f0ab9c9d 100644 --- a/crates/core/src/render/compositor.rs +++ b/crates/core/src/render/compositor.rs @@ -117,7 +117,7 @@ impl Compositor { let node = rdom.get(node_id)?; let utils = node.node_type().tag()?.utils()?; - Some(utils.drawing_area(layout_node, &node, scale_factor)) + utils.drawing_area_with_viewports(layout_node, &node, layout, scale_factor) } #[inline] @@ -182,7 +182,14 @@ impl Compositor { let cached_area = cache.get(node_id); let needs_cached_area = utils.needs_cached_area(&node_ref); - let area = utils.drawing_area(layout_node, &node_ref, scale_factor); + let Some(area) = utils.drawing_area_with_viewports( + layout_node, + &node_ref, + layout, + scale_factor, + ) else { + return false; + }; let is_dirty = dirty_nodes.remove(node_id); let cached_area_is_invalidated = cached_area diff --git a/crates/native-core/src/real_dom.rs b/crates/native-core/src/real_dom.rs index fe37e8421..996b1b7c6 100644 --- a/crates/native-core/src/real_dom.rs +++ b/crates/native-core/src/real_dom.rs @@ -316,6 +316,7 @@ impl RealDom { } /// Borrow a component from the world without updating the dirty nodes. + #[inline(always)] fn borrow_raw<'a, B: IntoBorrow>(&'a self) -> Result where B::Borrow: shipyard::Borrow<'a, View = B>, @@ -458,7 +459,7 @@ pub trait NodeImmutable: Sized { } /// Get a component from the current node - #[inline] + #[inline(always)] fn get<'a, T: Component + Sync + Send>(&'a self) -> Option> { // self.real_dom().tree.get(self.id()) let view: View<'a, T> = self.real_dom().borrow_raw().ok()?; diff --git a/crates/torin/src/geometry.rs b/crates/torin/src/geometry.rs index 8b93a17b7..848097b0c 100644 --- a/crates/torin/src/geometry.rs +++ b/crates/torin/src/geometry.rs @@ -54,6 +54,8 @@ pub trait AreaModel { fn expand(&mut self, size: &Size2D); fn max_area_when_rotated(&self, center: Point2D) -> Area; + + fn clip(&mut self, other: &Self); } impl AreaModel for Area { @@ -202,6 +204,13 @@ impl AreaModel for Area { ), ) } + + fn clip(&mut self, other: &Self) { + self.origin.x = self.origin.x.max(other.origin.x); + self.origin.y = self.origin.y.max(other.origin.y); + self.size.width = self.size.width.min(other.size.width); + self.size.height = self.size.height.min(other.size.height); + } } pub fn get_align_axis( diff --git a/examples/floating_editors.rs b/examples/floating_editors.rs index b73b082c9..3523d2522 100644 --- a/examples/floating_editors.rs +++ b/examples/floating_editors.rs @@ -87,6 +87,8 @@ fn app() -> Element { rect { key: "{id}", direction: "horizontal", + width: "0", + height: "0", rect { offset_x: "{node.0}", offset_y: "{node.1}", @@ -336,7 +338,7 @@ fn Editor() -> Element { } paragraph { height: "100%", - width: "100%", + width: "fill", main_align: "center", cursor_index: "{character_index}", cursor_color: "white",