Removed modifiers from code

This commit is contained in:
alonso.torres
2025-10-28 17:11:02 +01:00
parent f6eb492329
commit dbf9bdceb5
18 changed files with 194 additions and 458 deletions

View File

@@ -495,11 +495,7 @@ pub extern "C" fn get_selection_rect() -> *mut u8 {
with_state_mut!(state, {
let bbs: Vec<_> = entries
.iter()
.flat_map(|id| {
let default = Matrix::default();
let modifier = state.modifiers.get(id).unwrap_or(&default);
state.shapes.get(id).map(|b| b.bounds().transform(modifier))
})
.flat_map(|id| state.shapes.get(id).map(|b| b.bounds()))
.collect();
let result_bound = if bbs.len() == 1 {
@@ -569,9 +565,15 @@ pub extern "C" fn set_structure_modifiers() {
#[no_mangle]
pub extern "C" fn clean_modifiers() {
with_state_mut!(state, {
state.structure.clear();
state.scale_content.clear();
// state.modifiers.clear();
state.shapes.clean_modifiers();
state.shapes.clean_structure();
});
}
#[no_mangle]
pub extern "C" fn clean_geometry_modifiers() {
with_state_mut!(state, {
state.shapes.clean_modifiers();
});
}

View File

@@ -32,6 +32,7 @@ pub fn are_close_points(a: impl Into<(f32, f32)>, b: impl Into<(f32, f32)>) -> b
is_close_to(a_x, b_x) && is_close_to(a_y, b_y)
}
#[allow(dead_code)]
pub fn is_close_matrix(m: &Matrix, other: &Matrix) -> bool {
is_close_to(m.scale_x(), other.scale_x())
&& is_close_to(m.scale_y(), other.scale_y())

View File

@@ -388,8 +388,6 @@ pub fn bool_from_shapes(
bool_type: BoolType,
children_ids: &IndexSet<Uuid>,
shapes: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Path {
if children_ids.is_empty() {
return Path::default();
@@ -399,13 +397,13 @@ pub fn bool_from_shapes(
return Path::default();
};
let mut current_path = child.to_path(shapes, modifiers, structure);
let mut current_path = child.to_path(shapes);
for idx in (0..children_ids.len() - 1).rev() {
let Some(other) = shapes.get(&children_ids[idx]) else {
continue;
};
let other_path = other.to_path(shapes, modifiers, structure);
let other_path = other.to_path(shapes);
let (segs_a, segs_b) = split_segments(&current_path, &other_path);
@@ -422,26 +420,15 @@ pub fn bool_from_shapes(
current_path
}
pub fn update_bool_to_path(
shape: &Shape,
shapes: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Shape {
let mut shape = shape.clone();
let children_ids = shape.modified_children_ids(structure.get(&shape.id), true);
#[allow(dead_code)]
pub fn update_bool_to_path(shape: &mut Shape, shapes: ShapesPoolRef) {
let children_ids = shape.children_ids(true);
let Type::Bool(bool_data) = &mut shape.shape_type else {
return shape;
return;
};
bool_data.path = bool_from_shapes(
bool_data.bool_type,
&children_ids,
shapes,
modifiers,
structure,
);
shape
bool_data.path = bool_from_shapes(bool_data.bool_type, &children_ids, shapes);
}
#[allow(dead_code)]
@@ -450,14 +437,14 @@ pub fn debug_render_bool_paths(
render_state: &mut RenderState,
shape: &Shape,
shapes: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
_modifiers: &HashMap<Uuid, Matrix>,
_structure: &HashMap<Uuid, Vec<StructureEntry>>,
) {
let canvas = render_state.surfaces.canvas(SurfaceId::Strokes);
let mut shape = shape.clone();
let children_ids = shape.modified_children_ids(structure.get(&shape.id), true);
let children_ids = shape.children_ids(true);
let Type::Bool(bool_data) = &mut shape.shape_type else {
return;
@@ -471,13 +458,13 @@ pub fn debug_render_bool_paths(
return;
};
let mut current_path = child.to_path(shapes, modifiers, structure);
let mut current_path = child.to_path(shapes);
for idx in (0..children_ids.len() - 1).rev() {
let Some(other) = shapes.get(&children_ids[idx]) else {
continue;
};
let other_path = other.to_path(shapes, modifiers, structure);
let other_path = other.to_path(shapes);
let (segs_a, segs_b) = split_segments(&current_path, &other_path);

View File

@@ -22,8 +22,7 @@ pub use surfaces::{SurfaceId, Surfaces};
use crate::performance;
use crate::shapes::{
all_with_ancestors, Blur, BlurType, Corners, Fill, Shadow, Shape, SolidColor, Stroke,
StructureEntry, Type,
all_with_ancestors, Blur, BlurType, Corners, Fill, Shadow, Shape, SolidColor, Stroke, Type,
};
use crate::state::{ShapesPoolMutRef, ShapesPoolRef};
use crate::tiles::{self, PendingTiles, TileRect};
@@ -31,8 +30,6 @@ use crate::uuid::Uuid;
use crate::view::Viewbox;
use crate::wapi;
use crate::math;
use crate::math::bools;
use indexmap::IndexSet;
pub use fonts::*;
@@ -63,13 +60,11 @@ impl NodeRenderState {
/// Calculates the clip bounds for child elements of a given shape.
///
/// This function determines the clipping region that should be applied to child elements
/// when rendering. It takes into account the element's selection rectangle, transform,
/// and any additional modifiers.
/// when rendering. It takes into account the element's selection rectangle, transform.
///
/// # Parameters
///
/// * `element` - The shape element for which to calculate clip bounds
/// * `modifiers` - Optional transformation matrix to apply to the bounds
/// * `offset` - Optional offset (x, y) to adjust the bounds position. When provided,
/// the bounds are translated by the negative of this offset, effectively moving
/// the clipping region to compensate for coordinate system transformations.
@@ -78,7 +73,6 @@ impl NodeRenderState {
pub fn get_children_clip_bounds(
&self,
element: &Shape,
modifiers: Option<&Matrix>,
offset: Option<(f32, f32)>,
) -> Option<(Rect, Option<Corners>, Matrix)> {
if self.id.is_nil() || !element.clip() {
@@ -97,10 +91,6 @@ impl NodeRenderState {
transform.post_translate(bounds.center());
transform.pre_translate(-bounds.center());
if let Some(modifier) = modifiers {
transform.post_concat(modifier);
}
let corners = match &element.shape_type {
Type::Rect(data) => data.corners,
Type::Frame(data) => data.corners,
@@ -119,12 +109,10 @@ impl NodeRenderState {
/// # Parameters
///
/// * `element` - The shape element for which to calculate shadow clip bounds
/// * `modifiers` - Optional transformation matrix to apply to the bounds
/// * `shadow` - The shadow configuration containing blur, offset, and other properties
pub fn get_nested_shadow_clip_bounds(
&self,
element: &Shape,
modifiers: Option<&Matrix>,
shadow: &Shadow,
) -> Option<(Rect, Option<Corners>, Matrix)> {
if self.id.is_nil() {
@@ -142,10 +130,6 @@ impl NodeRenderState {
transform.post_translate(element.center());
transform.pre_translate(-element.center());
if let Some(modifier) = modifiers {
transform.post_concat(modifier);
}
let corners = match &element.shape_type {
Type::Rect(data) => data.corners,
Type::Frame(data) => data.corners,
@@ -275,28 +259,6 @@ pub fn get_cache_size(viewbox: Viewbox, scale: f32) -> skia::ISize {
.into()
}
fn is_modified_child(
shape: &Shape,
shapes: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
) -> bool {
if modifiers.is_empty() {
return false;
}
let ids = shape.all_children(shapes, true, false);
let default = &Matrix::default();
let parent_modifier = modifiers.get(&shape.id).unwrap_or(default);
// Returns true if the transform of any child is different to the parent's
ids.iter().any(|id| {
!math::is_close_matrix(
parent_modifier,
modifiers.get(id).unwrap_or(&Matrix::default()),
)
})
}
impl RenderState {
pub fn new(width: i32, height: i32) -> RenderState {
// This needs to be done once per WebGL context.
@@ -476,9 +438,6 @@ impl RenderState {
#[allow(clippy::too_many_arguments)]
pub fn render_shape(
&mut self,
shapes: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
shape: &Shape,
scale_content: Option<&f32>,
clip_bounds: Option<(Rect, Option<Corners>, Matrix)>,
@@ -546,10 +505,6 @@ impl RenderState {
// We don't want to change the value in the global state
let mut shape: Cow<Shape> = Cow::Borrowed(shape);
if let Some(shape_modifiers) = modifiers.get(&shape.id) {
shape.to_mut().apply_transform(shape_modifiers);
}
let mut nested_blur_value = 0.;
for nested_blur in self.nested_blurs.iter().flatten() {
if !nested_blur.hidden && nested_blur.blur_type == BlurType::LayerBlur {
@@ -580,11 +535,6 @@ impl RenderState {
match &shape.shape_type {
Type::SVGRaw(sr) => {
if let Some(shape_modifiers) = modifiers.get(&shape.id) {
self.surfaces
.canvas(fills_surface_id)
.concat(shape_modifiers);
}
self.surfaces.canvas(fills_surface_id).concat(&matrix);
if let Some(svg) = shape.svg.as_ref() {
svg.render(self.surfaces.canvas(fills_surface_id))
@@ -751,20 +701,7 @@ impl RenderState {
s.canvas().concat(&matrix);
});
// For boolean shapes, there's no need to calculate children because
// when painting the shape, the necessary path is already calculated
let shape = if let Type::Bool(_) = &shape.shape_type {
// If any child transform doesn't match the parent transform means
// that the children is transformed and we need to recalculate the
// boolean
if is_modified_child(&shape, shapes, modifiers) {
&bools::update_bool_to_path(&shape, shapes, modifiers, structure)
} else {
&shape
}
} else {
&shape
};
let shape = &shape;
if shape.fills.is_empty()
&& !matches!(shape.shape_type, Type::Group(_))
@@ -837,12 +774,7 @@ impl RenderState {
}
}
pub fn render_from_cache(
&mut self,
shapes: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) {
pub fn render_from_cache(&mut self, shapes: ShapesPoolRef) {
let scale = self.get_cached_scale();
if let Some(snapshot) = &self.cached_target_snapshot {
let canvas = self.surfaces.canvas(SurfaceId::Target);
@@ -875,7 +807,7 @@ impl RenderState {
debug::render(self);
}
ui::render(self, shapes, modifiers, structure);
ui::render(self, shapes);
debug::render_wasm_label(self);
self.flush_and_submit();
@@ -885,8 +817,6 @@ impl RenderState {
pub fn start_render_loop(
&mut self,
tree: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
scale_content: &HashMap<Uuid, f32>,
timestamp: i32,
) -> Result<(), String> {
@@ -937,7 +867,7 @@ impl RenderState {
self.current_tile = None;
self.render_in_progress = true;
self.apply_drawing_to_render_canvas(None);
self.process_animation_frame(tree, modifiers, structure, scale_content, timestamp)?;
self.process_animation_frame(tree, scale_content, timestamp)?;
performance::end_measure!("start_render_loop");
Ok(())
}
@@ -945,21 +875,13 @@ impl RenderState {
pub fn process_animation_frame(
&mut self,
tree: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
scale_content: &HashMap<Uuid, f32>,
timestamp: i32,
) -> Result<(), String> {
performance::begin_measure!("process_animation_frame");
if self.render_in_progress {
if tree.len() != 0 {
self.render_shape_tree_partial(
tree,
modifiers,
structure,
scale_content,
timestamp,
)?;
self.render_shape_tree_partial(tree, scale_content, timestamp)?;
} else {
println!("Empty tree");
}
@@ -1031,9 +953,6 @@ impl RenderState {
#[inline]
pub fn render_shape_exit(
&mut self,
tree: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
element: &Shape,
visited_mask: bool,
scale_content: Option<&f32>,
@@ -1091,9 +1010,6 @@ impl RenderState {
element_strokes.to_mut().clear_shadows();
element_strokes.to_mut().clip_content = false;
self.render_shape(
tree,
modifiers,
structure,
&element_strokes,
scale_content,
None,
@@ -1179,9 +1095,6 @@ impl RenderState {
#[allow(clippy::too_many_arguments)]
fn render_drop_black_shadow(
&mut self,
shapes: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
shape: &Shape,
shadow: &Shadow,
scale_content: Option<&f32>,
@@ -1233,9 +1146,6 @@ impl RenderState {
.translate(translation);
self.render_shape(
shapes,
modifiers,
structure,
&plain_shape,
scale_content,
clip_bounds,
@@ -1254,8 +1164,6 @@ impl RenderState {
pub fn render_shape_tree_partial_uncached(
&mut self,
tree: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
scale_content: &HashMap<Uuid, f32>,
timestamp: i32,
) -> Result<(bool, bool), String> {
@@ -1272,10 +1180,11 @@ impl RenderState {
} = node_render_state;
is_empty = false;
let element = tree.get(&node_id).ok_or(
"Error: Element with root_id {node_render_state.id} not found in the tree."
.to_string(),
)?;
let element = tree.get(&node_id).ok_or(format!(
"Error: Element with root_id {} not found in the tree.",
node_render_state.id
))?;
// If the shape is not in the tile set, then we update
// it.
@@ -1284,14 +1193,7 @@ impl RenderState {
}
if visited_children {
self.render_shape_exit(
tree,
modifiers,
structure,
element,
visited_mask,
scale_content.get(&element.id),
);
self.render_shape_exit(element, visited_mask, scale_content.get(&element.id));
continue;
}
@@ -1351,9 +1253,6 @@ impl RenderState {
// First pass: Render shadow in black to establish alpha mask
self.render_drop_black_shadow(
tree,
modifiers,
structure,
element,
shadow,
scale_content.get(&element.id),
@@ -1369,17 +1268,11 @@ impl RenderState {
if shadow_shape.hidden {
continue;
}
let clip_bounds = node_render_state.get_nested_shadow_clip_bounds(
element,
modifiers.get(&element.id),
shadow,
);
let clip_bounds = node_render_state
.get_nested_shadow_clip_bounds(element, shadow);
if !matches!(shadow_shape.shape_type, Type::Text(_)) {
self.render_drop_black_shadow(
tree,
modifiers,
structure,
shadow_shape,
shadow,
scale_content.get(&element.id),
@@ -1415,9 +1308,6 @@ impl RenderState {
new_shadow_paint.set_blend_mode(skia::BlendMode::SrcOver);
self.render_shape(
tree,
modifiers,
structure,
shadow_shape,
scale_content.get(&element.id),
clip_bounds,
@@ -1456,9 +1346,6 @@ impl RenderState {
.clear(skia::Color::TRANSPARENT);
self.render_shape(
tree,
modifiers,
structure,
element,
scale_content.get(&element.id),
clip_bounds,
@@ -1497,14 +1384,10 @@ impl RenderState {
});
if element.is_recursive() {
let children_clip_bounds = node_render_state.get_children_clip_bounds(
element,
modifiers.get(&element.id),
None,
);
let children_clip_bounds =
node_render_state.get_children_clip_bounds(element, None);
let mut children_ids =
element.modified_children_ids(structure.get(&element.id), false);
let mut children_ids = element.children_ids(false);
// Z-index ordering on Layouts
if element.has_layout() {
@@ -1538,8 +1421,6 @@ impl RenderState {
pub fn render_shape_tree_partial(
&mut self,
tree: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
scale_content: &HashMap<Uuid, f32>,
timestamp: i32,
) -> Result<(), String> {
@@ -1566,13 +1447,8 @@ impl RenderState {
}
} else {
performance::begin_measure!("render_shape_tree::uncached");
let (is_empty, early_return) = self.render_shape_tree_partial_uncached(
tree,
modifiers,
structure,
scale_content,
timestamp,
)?;
let (is_empty, early_return) =
self.render_shape_tree_partial_uncached(tree, scale_content, timestamp)?;
if early_return {
return Ok(());
}
@@ -1606,7 +1482,7 @@ impl RenderState {
let Some(root) = tree.get(&Uuid::nil()) else {
return Err(String::from("Root shape not found"));
};
let root_ids = root.modified_children_ids(structure.get(&root.id), false);
let root_ids = root.children_ids(false);
// If we finish processing every node rendering is complete
// let's check if there are more pending nodes
@@ -1649,7 +1525,7 @@ impl RenderState {
debug::render(self);
}
ui::render(self, tree, modifiers, structure);
ui::render(self, tree);
debug::render_wasm_label(self);
Ok(())
@@ -1678,6 +1554,7 @@ impl RenderState {
// Then, add the shape to the new tiles
for tile in new_tiles {
self.remove_cached_tile_shape(tile, shape.id);
self.tiles.add_shape_at(tile, shape.id);
}
}
@@ -1689,27 +1566,18 @@ impl RenderState {
self.tiles.remove_shape_at(tile, id);
}
pub fn rebuild_tiles_shallow(
&mut self,
tree: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) {
pub fn rebuild_tiles_shallow(&mut self, tree: ShapesPoolRef) {
performance::begin_measure!("rebuild_tiles_shallow");
self.tiles.invalidate();
self.surfaces.remove_cached_tiles(self.background_color);
let mut nodes = vec![Uuid::nil()];
while let Some(shape_id) = nodes.pop() {
if let Some(shape) = tree.get(&shape_id) {
let mut shape: Cow<Shape> = Cow::Borrowed(shape);
if shape_id != Uuid::nil() {
if let Some(modifier) = modifiers.get(&shape_id) {
shape.to_mut().apply_transform(modifier);
}
self.update_tile_for(&shape, tree);
} else {
// We only need to rebuild tiles from the first level.
let children = shape.modified_children_ids(structure.get(&shape.id), false);
let children = shape.children_ids(false);
for child_id in children.iter() {
nodes.push(*child_id);
}
@@ -1719,27 +1587,18 @@ impl RenderState {
performance::end_measure!("rebuild_tiles_shallow");
}
pub fn rebuild_tiles(
&mut self,
tree: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) {
pub fn rebuild_tiles(&mut self, tree: ShapesPoolRef) {
performance::begin_measure!("rebuild_tiles");
self.tiles.invalidate();
self.surfaces.remove_cached_tiles(self.background_color);
let mut nodes = vec![Uuid::nil()];
while let Some(shape_id) = nodes.pop() {
if let Some(shape) = tree.get(&shape_id) {
let mut shape: Cow<Shape> = Cow::Borrowed(shape);
if shape_id != Uuid::nil() {
if let Some(modifier) = modifiers.get(&shape_id) {
shape.to_mut().apply_transform(modifier);
}
self.update_tile_for(&shape, tree);
}
let children = shape.modified_children_ids(structure.get(&shape.id), false);
let children = shape.children_ids(false);
for child_id in children.iter() {
nodes.push(*child_id);
}

View File

@@ -1,21 +1,12 @@
use skia_safe::{self as skia};
use std::collections::HashMap;
use crate::math::{Matrix, Rect};
use crate::math::Rect;
use crate::shapes::modifiers::grid_layout::grid_cell_data;
use crate::shapes::{Shape, StructureEntry};
use crate::shapes::Shape;
use crate::state::ShapesPoolRef;
use crate::uuid::Uuid;
pub fn render_overlay(
zoom: f32,
canvas: &skia::Canvas,
shape: &Shape,
shapes: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) {
let cells = grid_cell_data(shape, shapes, modifiers, structure, true);
pub fn render_overlay(zoom: f32, canvas: &skia::Canvas, shape: &Shape, shapes: ShapesPoolRef) {
let cells = grid_cell_data(shape, shapes, true);
let mut paint = skia::Paint::default();
paint.set_style(skia::PaintStyle::Stroke);

View File

@@ -1,18 +1,9 @@
use skia_safe::{self as skia, Color4f};
use std::collections::HashMap;
use super::{RenderState, ShapesPoolRef, SurfaceId};
use crate::math::Matrix;
use crate::render::grid_layout;
use crate::shapes::StructureEntry;
use crate::uuid::Uuid;
pub fn render(
render_state: &mut RenderState,
shapes: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) {
pub fn render(render_state: &mut RenderState, shapes: ShapesPoolRef) {
let canvas = render_state.surfaces.canvas(SurfaceId::UI);
canvas.clear(Color4f::new(0.0, 0.0, 0.0, 0.0));
@@ -29,7 +20,7 @@ pub fn render(
if let Some(id) = render_state.show_grid {
if let Some(shape) = shapes.get(&id) {
grid_layout::render_overlay(zoom, canvas, shape, shapes, modifiers, structure);
grid_layout::render_overlay(zoom, canvas, shape, shapes);
}
}

View File

@@ -47,6 +47,7 @@ pub use svgraw::*;
pub use text::*;
pub use transform::*;
use crate::math::bools as math_bools;
use crate::math::{self, Bounds, Matrix, Point};
use indexmap::IndexSet;
@@ -309,6 +310,10 @@ impl Shape {
matches!(self.shape_type, Type::Frame(_))
}
pub fn is_bool(&self) -> bool {
matches!(self.shape_type, Type::Bool(_))
}
pub fn is_group_like(&self) -> bool {
matches!(self.shape_type, Type::Group(_)) || matches!(self.shape_type, Type::Bool(_))
}
@@ -901,6 +906,7 @@ impl Shape {
self.children.first()
}
// TODO: Review this to use children_ids_iter instead
pub fn children_ids(&self, include_hidden: bool) -> IndexSet<Uuid> {
if include_hidden {
return self.children.clone().into_iter().rev().collect();
@@ -1164,7 +1170,7 @@ impl Shape {
for st in structure {
match st.entry_type {
StructureEntryType::AddChild => {
result.insert(result.len() - st.index as usize, st.id);
result.insert(st.index as usize, st.id);
}
StructureEntryType::RemoveChild => {
to_remove.insert(&st.id);
@@ -1182,6 +1188,7 @@ impl Shape {
pub fn transformed(
&self,
shapes_pool: ShapesPoolRef,
transform: Option<&Matrix>,
structure: Option<&Vec<StructureEntry>>,
) -> Self {
@@ -1192,6 +1199,9 @@ impl Shape {
if let Some(structure) = structure {
shape.to_mut().apply_structure(structure);
}
if self.is_bool() {
math_bools::update_bool_to_path(shape.to_mut(), shapes_pool)
}
shape.into_owned()
}
@@ -1247,73 +1257,6 @@ impl Shape {
.count()
}
/*
Returns the list of children taking into account the structure modifiers
*/
pub fn modified_children_ids(
&self,
structure: Option<&Vec<StructureEntry>>,
include_hidden: bool,
) -> IndexSet<Uuid> {
if let Some(structure) = structure {
let mut result: Vec<Uuid> =
Vec::from_iter(self.children_ids(include_hidden).iter().copied());
let mut to_remove = HashSet::<&Uuid>::new();
for st in structure {
match st.entry_type {
StructureEntryType::AddChild => {
result.insert(result.len() - st.index as usize, st.id);
}
StructureEntryType::RemoveChild => {
to_remove.insert(&st.id);
}
_ => {}
}
}
let ret: IndexSet<Uuid> = result
.iter()
.filter(|id| !to_remove.contains(id))
.copied()
.collect();
ret
} else {
self.children_ids(include_hidden)
}
}
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> {
let drop_shadows: Vec<&Shadow> = self.drop_shadows_visible().collect();

View File

@@ -10,8 +10,7 @@ use crate::math::{self as math, bools, identitish, Bounds, Matrix, Point};
use common::GetBounds;
use crate::shapes::{
ConstraintH, ConstraintV, Frame, Group, GrowType, Layout, Modifier, Shape, StructureEntry,
TransformEntry, Type,
ConstraintH, ConstraintV, Frame, Group, GrowType, Layout, Modifier, Shape, TransformEntry, Type,
};
use crate::state::{ShapesPoolRef, State};
use crate::uuid::Uuid;
@@ -24,10 +23,9 @@ fn propagate_children(
parent_bounds_after: &Bounds,
transform: Matrix,
bounds: &HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
scale_content: &HashMap<Uuid, f32>,
) -> VecDeque<Modifier> {
let children_ids = shape.modified_children_ids(structure.get(&shape.id), true);
let children_ids = shape.children_ids(true);
if children_ids.is_empty() || identitish(&transform) {
return VecDeque::new();
@@ -92,12 +90,11 @@ fn calculate_group_bounds(
shape: &Shape,
shapes: ShapesPoolRef,
bounds: &HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Option<Bounds> {
let shape_bounds = bounds.find(shape);
let mut result = Vec::<Point>::new();
for child_id in shape.modified_children_ids_iter(structure.get(&shape.id), true) {
for child_id in shape.children_ids_iter(true) {
let Some(child) = shapes.get(&child_id) else {
continue;
};
@@ -112,23 +109,15 @@ fn calculate_bool_bounds(
shape: &Shape,
shapes: ShapesPoolRef,
bounds: &HashMap<Uuid, Bounds>,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Option<Bounds> {
let shape_bounds = bounds.find(shape);
let children_ids = shape.modified_children_ids(structure.get(&shape.id), true);
let children_ids = shape.children_ids(true);
let Type::Bool(bool_data) = &shape.shape_type else {
return Some(shape_bounds);
};
let path = bools::bool_from_shapes(
bool_data.bool_type,
&children_ids,
shapes,
modifiers,
structure,
);
let path = bools::bool_from_shapes(bool_data.bool_type, &children_ids, shapes);
Some(path.bounds())
}
@@ -235,7 +224,6 @@ fn propagate_transform(
&shape_bounds_after,
transform,
bounds,
&state.structure,
&state.scale_content,
);
entries.append(&mut children);
@@ -265,7 +253,6 @@ fn propagate_reflow(
bounds: &mut HashMap<Uuid, Bounds>,
layout_reflows: &mut Vec<Uuid>,
reflown: &mut HashSet<Uuid>,
modifiers: &HashMap<Uuid, Matrix>,
) {
let Some(shape) = state.shapes.get(id) else {
return;
@@ -303,7 +290,7 @@ fn propagate_reflow(
}
}
Type::Group(Group { masked: true }) => {
let children_ids = shape.modified_children_ids(state.structure.get(&shape.id), true);
let children_ids = shape.children_ids(true);
if let Some(child) = shapes.get(&children_ids[0]) {
let child_bounds = bounds.find(child);
bounds.insert(shape.id, child_bounds);
@@ -312,18 +299,14 @@ fn propagate_reflow(
reflown.insert(*id);
}
Type::Group(_) => {
if let Some(shape_bounds) =
calculate_group_bounds(shape, shapes, bounds, &state.structure)
{
if let Some(shape_bounds) = calculate_group_bounds(shape, shapes, bounds) {
bounds.insert(shape.id, shape_bounds);
reflow_parent = true;
}
reflown.insert(*id);
}
Type::Bool(_) => {
if let Some(shape_bounds) =
calculate_bool_bounds(shape, shapes, bounds, modifiers, &state.structure)
{
if let Some(shape_bounds) = calculate_bool_bounds(shape, shapes, bounds) {
bounds.insert(shape.id, shape_bounds);
reflow_parent = true;
}
@@ -365,24 +348,12 @@ fn reflow_shape(
};
if let Some(Layout::FlexLayout(layout_data, flex_data)) = &frame_data.layout {
let mut children = flex_layout::reflow_flex_layout(
shape,
layout_data,
flex_data,
shapes,
bounds,
&state.structure,
);
let mut children =
flex_layout::reflow_flex_layout(shape, layout_data, flex_data, shapes, bounds);
entries.append(&mut children);
} else if let Some(Layout::GridLayout(layout_data, grid_data)) = &frame_data.layout {
let mut children = grid_layout::reflow_grid_layout(
shape,
layout_data,
grid_data,
shapes,
bounds,
&state.structure,
);
let mut children =
grid_layout::reflow_grid_layout(shape, layout_data, grid_data, shapes, bounds);
entries.append(&mut children);
}
reflown.insert(*id);
@@ -398,12 +369,6 @@ pub fn propagate_modifiers(
.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();
@@ -432,7 +397,6 @@ pub fn propagate_modifiers(
&mut bounds,
&mut layout_reflows,
&mut reflown,
&modifiers,
),
}
}

View File

@@ -2,7 +2,7 @@
use crate::math::{self as math, Bounds, Matrix, Point, Vector, VectorExt};
use crate::shapes::{
AlignContent, AlignItems, AlignSelf, FlexData, JustifyContent, LayoutData, LayoutItem,
Modifier, Shape, StructureEntry,
Modifier, Shape,
};
use crate::state::ShapesPoolRef;
use crate::uuid::Uuid;
@@ -181,11 +181,10 @@ fn initialize_tracks(
flex_data: &FlexData,
shapes: ShapesPoolRef,
bounds: &HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Vec<TrackData> {
let mut tracks = Vec::<TrackData>::new();
let mut current_track = TrackData::default();
let mut children = shape.modified_children_ids(structure.get(&shape.id), true);
let mut children = shape.children_ids(true);
let mut first = true;
if flex_data.is_reverse() {
@@ -435,7 +434,6 @@ fn calculate_track_data(
layout_bounds: &Bounds,
shapes: ShapesPoolRef,
bounds: &HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Vec<TrackData> {
let layout_axis = LayoutAxis::new(shape, layout_bounds, layout_data, flex_data);
let mut tracks = initialize_tracks(
@@ -445,7 +443,6 @@ fn calculate_track_data(
flex_data,
shapes,
bounds,
structure,
);
distribute_fill_main_space(&layout_axis, &mut tracks);
@@ -576,20 +573,11 @@ pub fn reflow_flex_layout(
flex_data: &FlexData,
shapes: ShapesPoolRef,
bounds: &mut HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> VecDeque<Modifier> {
let mut result = VecDeque::new();
let layout_bounds = &bounds.find(shape);
let layout_axis = LayoutAxis::new(shape, layout_bounds, layout_data, flex_data);
let tracks = calculate_track_data(
shape,
layout_data,
flex_data,
layout_bounds,
shapes,
bounds,
structure,
);
let tracks = calculate_track_data(shape, layout_data, flex_data, layout_bounds, shapes, bounds);
for track in tracks.iter() {
let total_shapes_size = track.shapes.iter().map(|s| s.main_size).sum::<f32>();

View File

@@ -2,7 +2,7 @@ use crate::math::{self as math, intersect_rays, Bounds, Matrix, Point, Ray, Vect
use crate::shapes::{
AlignContent, AlignItems, AlignSelf, Frame, GridCell, GridData, GridTrack, GridTrackType,
JustifyContent, JustifyItems, JustifySelf, Layout, LayoutData, LayoutItem, Modifier, Shape,
StructureEntry, Type,
Type,
};
use crate::state::ShapesPoolRef;
use crate::uuid::Uuid;
@@ -603,8 +603,6 @@ pub fn create_cell_data<'a>(
pub fn grid_cell_data<'a>(
shape: &Shape,
shapes: ShapesPoolRef<'a>,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
allow_empty: bool,
) -> Vec<CellData<'a>> {
let Type::Frame(Frame {
@@ -616,26 +614,8 @@ pub fn grid_cell_data<'a>(
};
let bounds = &mut HashMap::<Uuid, Bounds>::new();
let shape = &mut shape.clone();
if let Some(modifiers) = modifiers.get(&shape.id) {
shape.apply_transform(modifiers);
}
let layout_bounds = shape.bounds();
let children = shape.modified_children_ids(structure.get(&shape.id), false);
for child_id in children.iter() {
let Some(child) = shapes.get(child_id) else {
continue;
};
if let Some(modifier) = modifiers.get(child_id) {
let mut b = bounds.find(child);
b.transform_mut(modifier);
bounds.insert(*child_id, b);
}
}
let children = shape.children_ids(false);
let column_tracks = calculate_tracks(
true,
@@ -725,11 +705,10 @@ pub fn reflow_grid_layout(
grid_data: &GridData,
shapes: ShapesPoolRef,
bounds: &mut HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> VecDeque<Modifier> {
let mut result = VecDeque::new();
let layout_bounds = bounds.find(shape);
let children = shape.modified_children_ids(structure.get(&shape.id), true);
let children = shape.children_ids(true);
let column_tracks = calculate_tracks(
true,

View File

@@ -1,22 +1,13 @@
use skia_safe::Matrix;
use super::{Corners, Path, Segment, Shape, StructureEntry, Type};
use super::{Corners, Path, Segment, Shape, Type};
use crate::math;
use crate::shapes::text_paths::TextPaths;
use crate::state::ShapesPoolRef;
use crate::uuid::Uuid;
use std::collections::HashMap;
const BEZIER_CIRCLE_C: f32 = 0.551_915_05;
pub trait ToPath {
fn to_path(
&self,
shapes: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Path;
fn to_path(&self, shapes: ShapesPoolRef) -> Path;
}
enum CornerType {
@@ -180,33 +171,28 @@ fn transform_segments(segments: Vec<Segment>, shape: &Shape) -> Vec<Segment> {
}
impl ToPath for Shape {
fn to_path(
&self,
shapes: ShapesPoolRef,
modifiers: &HashMap<Uuid, Matrix>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Path {
fn to_path(&self, shapes: ShapesPoolRef) -> Path {
match &self.shape_type {
Type::Frame(ref frame) => {
let children = self.modified_children_ids(structure.get(&self.id), true);
let children = self.children_ids(true);
let mut result = Path::new(rect_segments(&self, frame.corners));
for id in children {
let Some(shape) = shapes.get(&id) else {
continue;
};
result = join_paths(result, shape.to_path(shapes, modifiers, structure));
result = join_paths(result, shape.to_path(shapes));
}
result
}
Type::Group(_) => {
let children = self.modified_children_ids(structure.get(&self.id), true);
let children = self.children_ids(true);
let mut result = Path::default();
for id in children {
let Some(shape) = shapes.get(&id) else {
continue;
};
result = join_paths(result, shape.to_path(shapes, modifiers, structure));
result = join_paths(result, shape.to_path(shapes));
}
// Force closure of the group path
let mut segments = result.segments().clone();

View File

@@ -8,7 +8,6 @@ pub use text_editor::*;
use crate::render::RenderState;
use crate::shapes::Shape;
use crate::shapes::StructureEntry;
use crate::tiles;
use crate::uuid::Uuid;
@@ -24,9 +23,7 @@ pub(crate) struct State<'a> {
pub text_editor_state: TextEditorState,
pub current_id: Option<Uuid>,
pub shapes: ShapesPool<'a>,
pub modifiers: HashMap<Uuid, skia::Matrix>,
pub scale_content: HashMap<Uuid, f32>,
pub structure: HashMap<Uuid, Vec<StructureEntry>>,
}
impl<'a> State<'a> {
@@ -36,9 +33,7 @@ impl<'a> State<'a> {
text_editor_state: TextEditorState::new(),
current_id: None,
shapes: ShapesPool::new(),
modifiers: HashMap::new(),
scale_content: HashMap::new(),
structure: HashMap::new(),
}
}
@@ -65,29 +60,18 @@ impl<'a> State<'a> {
}
pub fn render_from_cache(&mut self) {
self.render_state
.render_from_cache(&self.shapes, &self.modifiers, &self.structure);
self.render_state.render_from_cache(&self.shapes);
}
pub fn start_render_loop(&mut self, timestamp: i32) -> Result<(), String> {
self.render_state.start_render_loop(
&self.shapes,
&self.modifiers,
&self.structure,
&self.scale_content,
timestamp,
)?;
self.render_state
.start_render_loop(&self.shapes, &self.scale_content, timestamp)?;
Ok(())
}
pub fn process_animation_frame(&mut self, timestamp: i32) -> Result<(), String> {
self.render_state.process_animation_frame(
&self.shapes,
&self.modifiers,
&self.structure,
&self.scale_content,
timestamp,
)?;
self.render_state
.process_animation_frame(&self.shapes, &self.scale_content, timestamp)?;
Ok(())
}
@@ -147,6 +131,8 @@ impl<'a> State<'a> {
panic!("Invalid current shape")
};
shape.set_parent(id);
// TODO this clone doesn't seem necessary
shape.clone()
};
@@ -166,6 +152,7 @@ impl<'a> State<'a> {
let Some(shape) = self.current_shape() else {
panic!("Invalid current shape")
};
// TODO: Remove this clone
if !shape.id.is_nil() {
self.render_state
.update_tile_for(&shape.clone(), &self.shapes);
@@ -173,13 +160,11 @@ impl<'a> State<'a> {
}
pub fn rebuild_tiles_shallow(&mut self) {
self.render_state
.rebuild_tiles_shallow(&self.shapes, &self.modifiers, &self.structure);
self.render_state.rebuild_tiles_shallow(&self.shapes);
}
pub fn rebuild_tiles(&mut self) {
self.render_state
.rebuild_tiles(&self.shapes, &self.modifiers, &self.structure);
self.render_state.rebuild_tiles(&self.shapes);
}
pub fn rebuild_modifier_tiles(&mut self, ids: Vec<Uuid>) {
@@ -204,7 +189,7 @@ impl<'a> State<'a> {
let bounds = shape.bounds();
let position = Point::new(pos_x, pos_y);
let cells = grid_cell_data(shape, &self.shapes, &self.modifiers, &self.structure, true);
let cells = grid_cell_data(shape, &self.shapes, true);
for cell in cells {
let points = &[

View File

@@ -2,6 +2,7 @@ use std::collections::HashMap;
use std::iter;
use crate::performance;
use crate::shapes;
use crate::shapes::Shape;
use crate::uuid::Uuid;
@@ -208,11 +209,15 @@ impl<'a> ShapesPoolImpl<'a> {
// Extend the lifetime of id to 'a - safe because it's the same Uuid stored in shapes[idx].id
let id_ref: &'a Uuid = &*(id as *const Uuid);
if (*modifiers_ptr).contains_key(&id_ref) || (*structure_ptr).contains_key(&id_ref) {
if self.to_update_bool(&*shape_ptr)
|| (*modifiers_ptr).contains_key(&id_ref)
|| (*structure_ptr).contains_key(&id_ref)
{
if let Some(cell) = (*cache_ptr).get(&id_ref) {
Some(cell.get_or_init(|| {
let shape = &*shape_ptr;
shape.transformed(
&self,
(*modifiers_ptr).get(&id_ref),
(*structure_ptr).get(&id_ref),
)
@@ -246,14 +251,25 @@ impl<'a> ShapesPoolImpl<'a> {
// Convert HashMap<Uuid, V> to HashMap<&'a Uuid, V> using references from shapes and
// Initialize the cache cells because later we don't want to have the mutable pointer
let mut ids = Vec::<Uuid>::new();
let mut modifiers_with_refs = HashMap::with_capacity(modifiers.len());
for (uuid, matrix) in modifiers {
if let Some(uuid_ref) = self.get_uuid_ref(&uuid) {
self.modified_shape_cache.insert(uuid_ref, OnceCell::new());
// self.modified_shape_cache.insert(uuid_ref, OnceCell::new());
modifiers_with_refs.insert(uuid_ref, matrix);
ids.push(*uuid_ref);
}
}
self.modifiers = modifiers_with_refs;
let all_ids = shapes::all_with_ancestors(&ids, &self, true);
for uuid in all_ids {
if let Some(uuid_ref) = self.get_uuid_ref(&uuid) {
self.modified_shape_cache.insert(uuid_ref, OnceCell::new());
}
}
}
#[allow(dead_code)]
@@ -261,13 +277,22 @@ impl<'a> ShapesPoolImpl<'a> {
// Convert HashMap<Uuid, V> to HashMap<&'a Uuid, V> using references from shapes and
// Initialize the cache cells because later we don't want to have the mutable pointer
let mut structure_with_refs = HashMap::with_capacity(structure.len());
let mut ids = Vec::<Uuid>::new();
for (uuid, entries) in structure {
if let Some(uuid_ref) = self.get_uuid_ref(&uuid) {
self.modified_shape_cache.insert(uuid_ref, OnceCell::new());
structure_with_refs.insert(uuid_ref, entries);
ids.push(*uuid_ref);
}
}
self.structure = structure_with_refs;
let all_ids = shapes::all_with_ancestors(&ids, &self, true);
for uuid in all_ids {
if let Some(uuid_ref) = self.get_uuid_ref(&uuid) {
self.modified_shape_cache.insert(uuid_ref, OnceCell::new());
}
}
}
#[allow(dead_code)]
@@ -290,4 +315,33 @@ impl<'a> ShapesPoolImpl<'a> {
// and won't be reallocated.
unsafe { Some(&*(&self.shapes[idx].id as *const Uuid)) }
}
fn to_update_bool(&self, shape: &Shape) -> bool {
// TODO: Check if any of the children is in the modifiers with a
// different matrix than the current one.
shape.is_bool()
}
}
// fn is_modified_child(
// shape: &Shape,
// shapes: ShapesPoolRef,
// modifiers: &HashMap<Uuid, Matrix>,
// ) -> bool {
// if modifiers.is_empty() {
// return false;
// }
//
// let ids = shape.all_children(shapes, true, false);
// let default = &Matrix::default();
// let parent_modifier = modifiers.get(&shape.id).unwrap_or(default);
//
// // Returns true if the transform of any child is different to the parent's
// ids.iter().any(|id| {
// !math::is_close_matrix(
// parent_modifier,
// modifiers.get(id).unwrap_or(&Matrix::default()),
// )
// })
// }

View File

@@ -213,7 +213,7 @@ pub extern "C" fn set_shape_path_content() {
pub extern "C" fn current_to_path() -> *mut u8 {
let mut result = Vec::<RawSegmentData>::default();
with_current_shape!(state, |shape: &Shape| {
let path = shape.to_path(&state.shapes, &state.modifiers, &state.structure);
let path = shape.to_path(&state.shapes);
result = path
.segments()
.iter()

View File

@@ -57,13 +57,7 @@ pub extern "C" fn calculate_bool(raw_bool_type: u8) -> *mut u8 {
let bool_type = RawBoolType::from(raw_bool_type).into();
let result;
with_state!(state, {
let path = math::bools::bool_from_shapes(
bool_type,
&entries,
&state.shapes,
&state.modifiers,
&state.structure,
);
let path = math::bools::bool_from_shapes(bool_type, &entries, &state.shapes);
result = path
.segments()
.iter()