Improve performance of group bounds

This commit is contained in:
alonso.torres
2025-10-22 11:30:59 +02:00
parent d4b4d943c6
commit 59e745e9ab
2 changed files with 72 additions and 23 deletions

View File

@@ -719,8 +719,7 @@ impl Shape {
} }
pub fn bounds(&self) -> Bounds { pub fn bounds(&self) -> Bounds {
*self.bounds *self.bounds.get_or_init(|| self.calculate_bounds())
.get_or_init(|| self.calculate_bounds())
} }
pub fn selrect(&self) -> math::Rect { pub fn selrect(&self) -> math::Rect {
@@ -947,6 +946,24 @@ impl Shape {
} }
} }
pub fn children_ids_iter(&self, include_hidden: bool) -> Box<dyn Iterator<Item = &Uuid> + '_> {
if include_hidden {
return Box::new(self.children.iter().rev());
}
if let Type::Bool(_) = self.shape_type {
Box::new([].iter())
} else if let Type::Group(group) = self.shape_type {
if group.masked {
Box::new(self.children.iter().rev().take(self.children.len() - 1))
} else {
Box::new(self.children.iter().rev())
}
} else {
Box::new(self.children.iter().rev())
}
}
pub fn all_children( pub fn all_children(
&self, &self,
shapes: &ShapesPool, shapes: &ShapesPool,
@@ -1259,6 +1276,36 @@ impl Shape {
} }
} }
pub fn modified_children_ids_iter<'a>(
&'a self,
structure: Option<&'a Vec<StructureEntry>>,
include_hidden: bool,
) -> Box<dyn Iterator<Item = Cow<'a, Uuid>> + 'a> {
if let Some(structure) = structure {
let mut result: Vec<Cow<'a, Uuid>> = self
.children_ids_iter(include_hidden)
.map(Cow::Borrowed)
.collect();
let mut to_remove = HashSet::<Cow<'a, Uuid>>::new();
for st in structure {
match st.entry_type {
StructureEntryType::AddChild => {
result.insert(result.len() - st.index as usize, Cow::Owned(st.id));
}
StructureEntryType::RemoveChild => {
to_remove.insert(Cow::Owned(st.id));
}
_ => {}
}
}
Box::new(result.into_iter().filter(move |id| !to_remove.contains(id)))
} else {
Box::new(self.children_ids_iter(include_hidden).map(Cow::Borrowed))
}
}
pub fn drop_shadow_paints(&self) -> Vec<skia_safe::Paint> { pub fn drop_shadow_paints(&self) -> Vec<skia_safe::Paint> {
let drop_shadows: Vec<&Shadow> = self.drop_shadows_visible().collect(); let drop_shadows: Vec<&Shadow> = self.drop_shadows_visible().collect();

View File

@@ -88,7 +88,6 @@ fn propagate_children(
result result
} }
// FIXME: PERFORMANCE
fn calculate_group_bounds( fn calculate_group_bounds(
shape: &Shape, shape: &Shape,
shapes: &ShapesPool, shapes: &ShapesPool,
@@ -98,16 +97,14 @@ fn calculate_group_bounds(
let shape_bounds = bounds.find(shape); let shape_bounds = bounds.find(shape);
let mut result = Vec::<Point>::new(); let mut result = Vec::<Point>::new();
let children_ids = shape.modified_children_ids(structure.get(&shape.id), true); for child_id in shape.modified_children_ids_iter(structure.get(&shape.id), true) {
for child_id in children_ids.iter() { let Some(child) = shapes.get(&child_id) else {
let Some(child) = shapes.get(child_id) else {
continue; continue;
}; };
let child_bounds = bounds.find(child); let child_bounds = bounds.find(child);
result.append(&mut child_bounds.points()); result.append(&mut child_bounds.points());
} }
shape_bounds.with_points(result) shape_bounds.with_points(result)
} }
@@ -277,30 +274,32 @@ fn propagate_reflow(
let shapes = &state.shapes; let shapes = &state.shapes;
let mut reflow_parent = false; let mut reflow_parent = false;
if reflown.contains(&id) {
return;
}
match &shape.shape_type { match &shape.shape_type {
Type::Frame(Frame { Type::Frame(Frame {
layout: Some(_), .. layout: Some(_), ..
}) => { }) => {
if !reflown.contains(id) { let mut skip_reflow = false;
let mut skip_reflow = false; if shape.is_layout_horizontal_fill() || shape.is_layout_vertical_fill() {
if shape.is_layout_horizontal_fill() || shape.is_layout_vertical_fill() { if let Some(parent_id) = shape.parent_id {
if let Some(parent_id) = shape.parent_id { if !reflown.contains(&parent_id) {
if !reflown.contains(&parent_id) { // If this is a fill layout but the parent has not been reflown yet
// If this is a fill layout but the parent has not been reflown yet // we wait for the next iteration for reflow
// we wait for the next iteration for reflow skip_reflow = true;
skip_reflow = true; reflow_parent = true;
reflow_parent = true;
}
} }
} }
}
if shape.is_layout_vertical_auto() || shape.is_layout_horizontal_auto() { if shape.is_layout_vertical_auto() || shape.is_layout_horizontal_auto() {
reflow_parent = true; reflow_parent = true;
} }
if !skip_reflow { if !skip_reflow {
layout_reflows.push(*id); layout_reflows.push(*id);
}
} }
} }
Type::Group(Group { masked: true }) => { Type::Group(Group { masked: true }) => {
@@ -310,6 +309,7 @@ fn propagate_reflow(
bounds.insert(shape.id, child_bounds); bounds.insert(shape.id, child_bounds);
reflow_parent = true; reflow_parent = true;
} }
reflown.insert(*id);
} }
Type::Group(_) => { Type::Group(_) => {
if let Some(shape_bounds) = if let Some(shape_bounds) =
@@ -318,6 +318,7 @@ fn propagate_reflow(
bounds.insert(shape.id, shape_bounds); bounds.insert(shape.id, shape_bounds);
reflow_parent = true; reflow_parent = true;
} }
reflown.insert(*id);
} }
Type::Bool(_) => { Type::Bool(_) => {
if let Some(shape_bounds) = if let Some(shape_bounds) =
@@ -326,6 +327,7 @@ fn propagate_reflow(
bounds.insert(shape.id, shape_bounds); bounds.insert(shape.id, shape_bounds);
reflow_parent = true; reflow_parent = true;
} }
reflown.insert(*id);
} }
_ => { _ => {
// Other shapes don't have to be reflown // Other shapes don't have to be reflown