mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
✨ Fix problems with SVGraw and modifiers
This commit is contained in:
@@ -290,15 +290,21 @@ pub extern "C" fn add_shape_child(a: u32, b: u32, c: u32, d: u32) {
|
||||
|
||||
fn set_children_set(entries: IndexSet<Uuid>) {
|
||||
let mut deleted = IndexSet::new();
|
||||
let mut parent_id = None;
|
||||
|
||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||
parent_id = Some(shape.id);
|
||||
(_, deleted) = shape.compute_children_differences(&entries);
|
||||
shape.children = entries.clone();
|
||||
});
|
||||
|
||||
with_state_mut!(state, {
|
||||
let Some(parent_id) = parent_id else {
|
||||
return;
|
||||
};
|
||||
|
||||
for id in deleted {
|
||||
state.delete_shape(id);
|
||||
state.delete_shape_children(parent_id, id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -535,7 +535,12 @@ impl RenderState {
|
||||
|
||||
match &shape.shape_type {
|
||||
Type::SVGRaw(sr) => {
|
||||
if let Some(svg_transform) = shape.svg_transform() {
|
||||
matrix.pre_concat(&svg_transform);
|
||||
}
|
||||
|
||||
self.surfaces.canvas(fills_surface_id).concat(&matrix);
|
||||
|
||||
if let Some(svg) = shape.svg.as_ref() {
|
||||
svg.render(self.surfaces.canvas(fills_surface_id))
|
||||
} else {
|
||||
@@ -1574,7 +1579,7 @@ impl RenderState {
|
||||
while let Some(shape_id) = nodes.pop() {
|
||||
if let Some(shape) = tree.get(&shape_id) {
|
||||
if shape_id != Uuid::nil() {
|
||||
self.update_tile_for(&shape, tree);
|
||||
self.update_tile_for(shape, tree);
|
||||
} else {
|
||||
// We only need to rebuild tiles from the first level.
|
||||
let children = shape.children_ids(false);
|
||||
@@ -1595,7 +1600,7 @@ impl RenderState {
|
||||
while let Some(shape_id) = nodes.pop() {
|
||||
if let Some(shape) = tree.get(&shape_id) {
|
||||
if shape_id != Uuid::nil() {
|
||||
self.update_tile_for(&shape, tree);
|
||||
self.update_tile_for(shape, tree);
|
||||
}
|
||||
|
||||
let children = shape.children_ids(false);
|
||||
|
||||
@@ -182,6 +182,7 @@ pub struct Shape {
|
||||
pub layout_item: Option<LayoutItem>,
|
||||
pub extrect: OnceCell<math::Rect>,
|
||||
pub bounds: OnceCell<math::Bounds>,
|
||||
pub svg_transform: Option<Matrix>,
|
||||
}
|
||||
|
||||
// Returns all ancestor shapes of this shape, traversing up the parent hierarchy
|
||||
@@ -263,6 +264,7 @@ impl Shape {
|
||||
layout_item: None,
|
||||
extrect: OnceCell::new(),
|
||||
bounds: OnceCell::new(),
|
||||
svg_transform: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,6 +395,10 @@ impl Shape {
|
||||
self.hidden = value;
|
||||
}
|
||||
|
||||
pub fn svg_transform(&self) -> Option<Matrix> {
|
||||
self.svg_transform
|
||||
}
|
||||
|
||||
// FIXME: These arguments could be grouped or simplified
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn set_flex_layout_child_data(
|
||||
@@ -876,7 +882,7 @@ impl Shape {
|
||||
}
|
||||
Type::Text(text_content) => {
|
||||
// FIXME: we need to recalculate the text bounds here because the shape's selrect
|
||||
let text_bounds = text_content.calculate_bounds(&shape);
|
||||
let text_bounds = text_content.calculate_bounds(shape);
|
||||
text_bounds.to_rect()
|
||||
}
|
||||
_ => shape.bounds().to_rect(),
|
||||
@@ -1160,6 +1166,8 @@ impl Shape {
|
||||
}
|
||||
} else if let Type::Text(text) = &mut self.shape_type {
|
||||
text.transform(transform);
|
||||
} else if let Type::SVGRaw(_) = &mut self.shape_type {
|
||||
self.svg_transform = Some(*transform);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ fn calculate_group_bounds(
|
||||
let mut result = Vec::<Point>::new();
|
||||
|
||||
for child_id in shape.children_ids_iter(true) {
|
||||
let Some(child) = shapes.get(&child_id) else {
|
||||
let Some(child) = shapes.get(child_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -109,7 +109,7 @@ fn calculate_bool_bounds(
|
||||
shape: &Shape,
|
||||
shapes: ShapesPoolRef,
|
||||
bounds: &HashMap<Uuid, Bounds>,
|
||||
modifiers: &HashMap<Uuid, Matrix>
|
||||
modifiers: &HashMap<Uuid, Matrix>,
|
||||
) -> Option<Bounds> {
|
||||
let shape_bounds = bounds.find(shape);
|
||||
let children_ids = shape.children_ids(true);
|
||||
@@ -258,7 +258,7 @@ fn propagate_reflow(
|
||||
bounds: &mut HashMap<Uuid, Bounds>,
|
||||
layout_reflows: &mut Vec<Uuid>,
|
||||
reflown: &mut HashSet<Uuid>,
|
||||
modifiers: &HashMap<Uuid, Matrix>
|
||||
modifiers: &HashMap<Uuid, Matrix>,
|
||||
) {
|
||||
let Some(shape) = state.shapes.get(id) else {
|
||||
return;
|
||||
@@ -267,7 +267,7 @@ fn propagate_reflow(
|
||||
let shapes = &state.shapes;
|
||||
let mut reflow_parent = false;
|
||||
|
||||
if reflown.contains(&id) {
|
||||
if reflown.contains(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -403,7 +403,7 @@ pub fn propagate_modifiers(
|
||||
&mut bounds,
|
||||
&mut layout_reflows,
|
||||
&mut reflown,
|
||||
&mut modifiers,
|
||||
&modifiers,
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -429,13 +429,14 @@ mod tests {
|
||||
|
||||
use crate::math::{Matrix, Point};
|
||||
use crate::shapes::*;
|
||||
use crate::state::ShapesPool;
|
||||
|
||||
#[test]
|
||||
fn test_propagate_shape() {
|
||||
let parent_id = Uuid::new_v4();
|
||||
|
||||
let shapes = {
|
||||
let mut shapes = ShapesPoolRef::new();
|
||||
let mut shapes = ShapesPool::new();
|
||||
shapes.initialize(10);
|
||||
|
||||
let child_id = Uuid::new_v4();
|
||||
@@ -468,7 +469,6 @@ mod tests {
|
||||
transform,
|
||||
&HashMap::new(),
|
||||
&HashMap::new(),
|
||||
&HashMap::new(),
|
||||
);
|
||||
|
||||
assert_eq!(result.len(), 1);
|
||||
@@ -478,7 +478,7 @@ mod tests {
|
||||
fn test_group_bounds() {
|
||||
let parent_id = Uuid::new_v4();
|
||||
let shapes = {
|
||||
let mut shapes = ShapesPoolRef::new();
|
||||
let mut shapes = ShapesPool::new();
|
||||
shapes.initialize(10);
|
||||
|
||||
let child1_id = Uuid::new_v4();
|
||||
@@ -500,7 +500,7 @@ mod tests {
|
||||
let parent = shapes.get(&parent_id).unwrap();
|
||||
|
||||
let bounds =
|
||||
calculate_group_bounds(parent, &shapes, &HashMap::new(), &HashMap::new()).unwrap();
|
||||
calculate_group_bounds(parent, &shapes, &HashMap::new()).unwrap();
|
||||
|
||||
assert_eq!(bounds.width(), 3.0);
|
||||
assert_eq!(bounds.height(), 3.0);
|
||||
|
||||
@@ -175,7 +175,7 @@ impl ToPath for Shape {
|
||||
match &self.shape_type {
|
||||
Type::Frame(ref frame) => {
|
||||
let children = self.children_ids(true);
|
||||
let mut result = Path::new(rect_segments(&self, frame.corners));
|
||||
let mut result = Path::new(rect_segments(self, frame.corners));
|
||||
for id in children {
|
||||
let Some(shape) = shapes.get(&id) else {
|
||||
continue;
|
||||
@@ -202,11 +202,11 @@ impl ToPath for Shape {
|
||||
|
||||
Type::Bool(bool_data) => bool_data.path.clone(),
|
||||
|
||||
Type::Rect(ref rect) => Path::new(rect_segments(&self, rect.corners)),
|
||||
Type::Rect(ref rect) => Path::new(rect_segments(self, rect.corners)),
|
||||
|
||||
Type::Path(path_data) => path_data.clone(),
|
||||
|
||||
Type::Circle => Path::new(circle_segments(&self)),
|
||||
Type::Circle => Path::new(circle_segments(self)),
|
||||
|
||||
Type::SVGRaw(_) => Path::default(),
|
||||
|
||||
@@ -217,7 +217,7 @@ impl ToPath for Shape {
|
||||
result = join_paths(result, Path::from_skia_path(path));
|
||||
}
|
||||
|
||||
Path::new(transform_segments(result.segments().clone(), &self))
|
||||
Path::new(transform_segments(result.segments().clone(), self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,9 +94,14 @@ impl<'a> State<'a> {
|
||||
self.current_id = Some(id);
|
||||
}
|
||||
|
||||
pub fn delete_shape(&mut self, id: Uuid) {
|
||||
pub fn delete_shape_children(&mut self, parent_id: Uuid, id: Uuid) {
|
||||
// We don't really do a self.shapes.remove so that redo/undo keep working
|
||||
if let Some(shape) = self.shapes.get(&id) {
|
||||
let Some(shape) = self.shapes.get(&id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Only remove the children when is being deleted from the owner
|
||||
if shape.parent_id.is_none() || shape.parent_id == Some(parent_id) {
|
||||
let tiles::TileRect(rsx, rsy, rex, rey) =
|
||||
self.render_state.get_tiles_for_shape(shape, &self.shapes);
|
||||
for x in rsx..=rex {
|
||||
|
||||
@@ -217,7 +217,7 @@ impl<'a> ShapesPoolImpl<'a> {
|
||||
Some(cell.get_or_init(|| {
|
||||
let shape = &*shape_ptr;
|
||||
shape.transformed(
|
||||
&self,
|
||||
self,
|
||||
(*modifiers_ptr).get(&id_ref),
|
||||
(*structure_ptr).get(&id_ref),
|
||||
)
|
||||
@@ -264,7 +264,7 @@ impl<'a> ShapesPoolImpl<'a> {
|
||||
}
|
||||
self.modifiers = modifiers_with_refs;
|
||||
|
||||
let all_ids = shapes::all_with_ancestors(&ids, &self, true);
|
||||
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());
|
||||
@@ -287,7 +287,7 @@ impl<'a> ShapesPoolImpl<'a> {
|
||||
}
|
||||
self.structure = structure_with_refs;
|
||||
|
||||
let all_ids = shapes::all_with_ancestors(&ids, &self, true);
|
||||
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());
|
||||
@@ -317,7 +317,9 @@ impl<'a> ShapesPoolImpl<'a> {
|
||||
}
|
||||
|
||||
pub fn subtree(&self, id: &Uuid) -> ShapesPoolImpl<'a> {
|
||||
let Some(shape) = self.get(id) else { panic!("Subtree not found"); };
|
||||
let Some(shape) = self.get(id) else {
|
||||
panic!("Subtree not found");
|
||||
};
|
||||
|
||||
// TODO: Maybe create all_children_iter
|
||||
let all_children = shape.all_children(self, true, true);
|
||||
@@ -327,7 +329,9 @@ impl<'a> ShapesPoolImpl<'a> {
|
||||
let mut shapes_uuid_to_idx = HashMap::default();
|
||||
|
||||
for id in all_children.iter() {
|
||||
let Some(shape) = self.get(id) else { panic!("Not found"); };
|
||||
let Some(shape) = self.get(id) else {
|
||||
panic!("Not found");
|
||||
};
|
||||
shapes.push(shape.clone());
|
||||
|
||||
let id_ref: &'a Uuid = unsafe { &*(&self.shapes[idx].id as *const Uuid) };
|
||||
|
||||
Reference in New Issue
Block a user