From 26fcb54001737cc96b20a0acd6820766f6971ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Thu, 26 Oct 2023 23:19:52 +0200 Subject: [PATCH] feat: Improve and optimize elements clipping (#353) * feat: WIP Enhanced alignments * improvements * tweak * remove display attribute, remove 'both' direction, fix tests, fix docs, fix examples, fix components * feat: Updated examples * tests * fixed tests * update table component and example * clean up * clean up * improvements * improvements * fixes * fix tests * tweak * tweaks * unsized alignment test * document code * tweak * rename attributes * fixes and cleanup * fixes and improvements * typo * feat: Improve and optimize elements clipping * improvements * fix --- crates/core/src/viewports.rs | 24 +++++++++++++++-------- crates/renderer/src/renderer.rs | 34 ++++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/crates/core/src/viewports.rs b/crates/core/src/viewports.rs index 3417314b1..51d5008ea 100644 --- a/crates/core/src/viewports.rs +++ b/crates/core/src/viewports.rs @@ -33,22 +33,30 @@ pub fn calculate_viewports( // Clip any overflow from it's children if style.overflow == OverflowMode::Clip { - viewports_collection + let viewport = viewports_collection .entry(*node_id) - .or_insert_with(|| (None, Vec::new())) - .0 = Some(node_areas.area); + .or_insert_with(|| (None, Vec::new())); + viewport.0 = Some(node_areas.visible_area()); } // Pass viewports to the children if let Some((_, mut inherited_viewports)) = viewports_collection.get(node_id).cloned() { - // Add the itself - inherited_viewports.push(*node_id); + // Only pass the inherited viewports if they are not empty + // or this same element has a clipped overflow + if !inherited_viewports.is_empty() || style.overflow == OverflowMode::Clip { + // Add itself + inherited_viewports.push(*node_id); - for child in node.children() { - viewports_collection - .insert(child.id(), (None, inherited_viewports.clone())); + for child in node.children() { + if let NodeType::Element(..) = *child.node_type() { + viewports_collection + .entry(child.id()) + .or_insert_with(|| (None, Vec::new())) + .1 = inherited_viewports.clone(); + } + } } } } diff --git a/crates/renderer/src/renderer.rs b/crates/renderer/src/renderer.rs index 6520e4b28..258d8d7a9 100644 --- a/crates/renderer/src/renderer.rs +++ b/crates/renderer/src/renderer.rs @@ -10,6 +10,19 @@ use torin::geometry::Area; use crate::elements::{render_image, render_label, render_paragraph, render_rect, render_svg}; +fn clip_viewport(canvas: &Canvas, viewport: &Area) { + canvas.clip_rect( + Rect::new( + viewport.min_x(), + viewport.min_y(), + viewport.max_x(), + viewport.max_y(), + ), + ClipOp::Intersect, + true, + ); +} + /// Render a node into the Skia canvas #[allow(clippy::too_many_arguments)] pub fn render_skia( @@ -53,20 +66,19 @@ pub fn render_skia( let viewports = viewports_collection.get(&dioxus_node.id()); // Clip all elements with their corresponding viewports - if let Some((_, viewports)) = viewports { + if let Some((element_viewport, viewports)) = viewports { + // Only clip the element iself when it's paragraph because + // it will render the inner text spans on it's own, so if these spans overflow the paragraph, + // It is the paragraph job to make sure they are clipped + if tag.as_str() == "paragraph" { + if let Some(element_viewport) = element_viewport { + clip_viewport(canvas, element_viewport); + } + } for viewport_id in viewports { let viewport = viewports_collection.get(viewport_id).unwrap().0; if let Some(viewport) = viewport { - canvas.clip_rect( - Rect::new( - viewport.min_x(), - viewport.min_y(), - viewport.max_x(), - viewport.max_y(), - ), - ClipOp::Intersect, - true, - ); + clip_viewport(canvas, &viewport); } } }