♻️ Refactor modifiers methods

This commit is contained in:
alonso.torres 2025-06-20 12:39:06 +02:00 committed by Alonso Torres
parent afec3b9bc1
commit 36b6f6323a

View file

@ -150,44 +150,21 @@ fn set_pixel_precision(transform: &mut Matrix, bounds: &mut Bounds) {
} }
} }
pub fn propagate_modifiers( fn propagate_transform(
state: &State, entry: TransformEntry,
modifiers: &[TransformEntry],
pixel_precision: bool, pixel_precision: bool,
) -> Vec<TransformEntry> { state: &State,
let shapes = &state.shapes; entries: &mut VecDeque<Modifier>,
bounds: &mut HashMap<Uuid, Bounds>,
let font_col = state.render_state.fonts.font_collection(); modifiers: &mut HashMap<Uuid, Matrix>,
let mut entries: VecDeque<_> = modifiers ) {
.iter()
.map(|entry| Modifier::Transform(entry.clone()))
.collect();
for id in state.structure.keys() {
if id != &Uuid::nil() {
entries.push_back(Modifier::Reflow(*id));
}
}
let mut modifiers = HashMap::<Uuid, Matrix>::new();
let mut bounds = HashMap::<Uuid, Bounds>::new();
let mut reflown = HashSet::<Uuid>::new();
let mut layout_reflows = Vec::<Uuid>::new();
// We first propagate the transforms to the children and then after
// recalculate the layouts. The layout can create further transforms that
// we need to re-propagate.
// In order for loop to eventualy finish, we limit the flex reflow to just
// one (the reflown set).
while !entries.is_empty() {
while let Some(modifier) = entries.pop_front() {
match modifier {
Modifier::Transform(entry) => {
let Some(shape) = state.shapes.get(&entry.id) else { let Some(shape) = state.shapes.get(&entry.id) else {
continue; return;
}; };
let shapes = &state.shapes;
let font_col = state.render_state.fonts.font_collection();
let shape_bounds_before = bounds.find(shape); let shape_bounds_before = bounds.find(shape);
let mut shape_bounds_after = shape_bounds_before.transform(&entry.transform); let mut shape_bounds_after = shape_bounds_before.transform(&entry.transform);
@ -220,7 +197,7 @@ pub fn propagate_modifiers(
&shape_bounds_before, &shape_bounds_before,
&shape_bounds_after, &shape_bounds_after,
transform, transform,
&bounds, bounds,
&state.structure, &state.structure,
&state.scale_content, &state.scale_content,
); );
@ -242,24 +219,30 @@ pub fn propagate_modifiers(
entries.push_back(Modifier::reflow(parent.id)); entries.push_back(Modifier::reflow(parent.id));
} }
} }
} }
Modifier::Reflow(id) => { fn propagate_reflow(
let Some(shape) = state.shapes.get(&id) else { id: &Uuid,
continue; state: &State,
entries: &mut VecDeque<Modifier>,
bounds: &mut HashMap<Uuid, Bounds>,
layout_reflows: &mut Vec<Uuid>,
reflown: &mut HashSet<Uuid>,
) {
let Some(shape) = state.shapes.get(id) else {
return;
}; };
let shapes = &state.shapes;
let mut reflow_parent = false; let mut reflow_parent = false;
match &shape.shape_type { match &shape.shape_type {
Type::Frame(Frame { Type::Frame(Frame {
layout: Some(_), .. layout: Some(_), ..
}) => { }) => {
if !reflown.contains(&id) { if !reflown.contains(id) {
let mut skip_reflow = false; let mut skip_reflow = false;
if shape.is_layout_horizontal_fill() if shape.is_layout_horizontal_fill() || shape.is_layout_vertical_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
@ -270,20 +253,17 @@ pub fn propagate_modifiers(
} }
} }
if shape.is_layout_vertical_auto() if shape.is_layout_vertical_auto() || shape.is_layout_horizontal_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 }) => {
let children_ids = let children_ids = modified_children_ids(shape, state.structure.get(&shape.id), true);
modified_children_ids(shape, state.structure.get(&shape.id), true);
if let Some(child) = shapes.get(&children_ids[0]) { if let Some(child) = shapes.get(&children_ids[0]) {
let child_bounds = bounds.find(child); let child_bounds = bounds.find(child);
bounds.insert(shape.id, child_bounds); bounds.insert(shape.id, child_bounds);
@ -292,7 +272,7 @@ pub fn propagate_modifiers(
} }
Type::Group(_) => { Type::Group(_) => {
if let Some(shape_bounds) = if let Some(shape_bounds) =
calculate_group_bounds(shape, shapes, &bounds, &state.structure) calculate_group_bounds(shape, shapes, bounds, &state.structure)
{ {
bounds.insert(shape.id, shape_bounds); bounds.insert(shape.id, shape_bounds);
reflow_parent = true; reflow_parent = true;
@ -303,7 +283,7 @@ pub fn propagate_modifiers(
// new path... impossible right now. I'm going to use for the moment the group // new path... impossible right now. I'm going to use for the moment the group
// calculation // calculation
if let Some(shape_bounds) = if let Some(shape_bounds) =
calculate_group_bounds(shape, shapes, &bounds, &state.structure) calculate_group_bounds(shape, shapes, bounds, &state.structure)
{ {
bounds.insert(shape.id, shape_bounds); bounds.insert(shape.id, shape_bounds);
reflow_parent = true; reflow_parent = true;
@ -319,19 +299,21 @@ pub fn propagate_modifiers(
entries.push_back(Modifier::reflow(parent.id)); entries.push_back(Modifier::reflow(parent.id));
} }
} }
} }
}
}
for id in layout_reflows.iter() {
if reflown.contains(id) {
continue;
}
fn reflow_shape(
id: &Uuid,
state: &State,
reflown: &mut HashSet<Uuid>,
entries: &mut VecDeque<Modifier>,
bounds: &mut HashMap<Uuid, Bounds>,
) {
let Some(shape) = state.shapes.get(id) else { let Some(shape) = state.shapes.get(id) else {
continue; return;
}; };
let shapes = &state.shapes;
let shape = if let Some(scale_content) = state.scale_content.get(id) { let shape = if let Some(scale_content) = state.scale_content.get(id) {
&shape.scale_content(*scale_content) &shape.scale_content(*scale_content)
} else { } else {
@ -339,7 +321,7 @@ pub fn propagate_modifiers(
}; };
let Type::Frame(frame_data) = &shape.shape_type else { let Type::Frame(frame_data) = &shape.shape_type else {
continue; return;
}; };
if let Some(Layout::FlexLayout(layout_data, flex_data)) = &frame_data.layout { if let Some(Layout::FlexLayout(layout_data, flex_data)) = &frame_data.layout {
@ -348,24 +330,77 @@ pub fn propagate_modifiers(
layout_data, layout_data,
flex_data, flex_data,
shapes, shapes,
&mut bounds, bounds,
&state.structure, &state.structure,
); );
entries.append(&mut children); entries.append(&mut children);
} } else if let Some(Layout::GridLayout(layout_data, grid_data)) = &frame_data.layout {
if let Some(Layout::GridLayout(layout_data, grid_data)) = &frame_data.layout {
let mut children = grid_layout::reflow_grid_layout( let mut children = grid_layout::reflow_grid_layout(
shape, shape,
layout_data, layout_data,
grid_data, grid_data,
shapes, shapes,
&mut bounds, bounds,
&state.structure, &state.structure,
); );
entries.append(&mut children); entries.append(&mut children);
} }
reflown.insert(*id); reflown.insert(*id);
}
pub fn propagate_modifiers(
state: &State,
modifiers: &[TransformEntry],
pixel_precision: bool,
) -> Vec<TransformEntry> {
let mut entries: VecDeque<_> = modifiers
.iter()
.map(|entry| Modifier::Transform(entry.clone()))
.collect();
for id in state.structure.keys() {
if id != &Uuid::nil() {
entries.push_back(Modifier::Reflow(*id));
}
}
let mut modifiers = HashMap::<Uuid, Matrix>::new();
let mut bounds = HashMap::<Uuid, Bounds>::new();
let mut reflown = HashSet::<Uuid>::new();
let mut layout_reflows = Vec::<Uuid>::new();
// We first propagate the transforms to the children and then after
// recalculate the layouts. The layout can create further transforms that
// we need to re-propagate.
// In order for loop to eventualy finish, we limit the flex reflow to just
// one (the reflown set).
while !entries.is_empty() {
while let Some(modifier) = entries.pop_front() {
match modifier {
Modifier::Transform(entry) => propagate_transform(
entry,
pixel_precision,
state,
&mut entries,
&mut bounds,
&mut modifiers,
),
Modifier::Reflow(id) => propagate_reflow(
&id,
state,
&mut entries,
&mut bounds,
&mut layout_reflows,
&mut reflown,
),
}
}
for id in layout_reflows.iter() {
if reflown.contains(id) {
continue;
}
reflow_shape(id, state, &mut reflown, &mut entries, &mut bounds);
} }
layout_reflows = Vec::new(); layout_reflows = Vec::new();
} }