mirror of
https://github.com/penpot/penpot.git
synced 2026-08-01 19:06:18 +00:00
🐛 Fix boolean and group shadows
This commit is contained in:
parent
99a100ad63
commit
da05d6b67d
@ -124,7 +124,7 @@ impl NodeRenderState {
|
|||||||
/// * `element` - The shape element for which to calculate shadow clip bounds
|
/// * `element` - The shape element for which to calculate shadow clip bounds
|
||||||
/// * `modifiers` - Optional transformation matrix to apply to the bounds
|
/// * `modifiers` - Optional transformation matrix to apply to the bounds
|
||||||
/// * `shadow` - The shadow configuration containing blur, offset, and other properties
|
/// * `shadow` - The shadow configuration containing blur, offset, and other properties
|
||||||
pub fn get_shadow_clip_bounds(
|
pub fn get_nested_shadow_clip_bounds(
|
||||||
&self,
|
&self,
|
||||||
element: &Shape,
|
element: &Shape,
|
||||||
modifiers: Option<&Matrix>,
|
modifiers: Option<&Matrix>,
|
||||||
@ -134,7 +134,13 @@ impl NodeRenderState {
|
|||||||
return self.clip_bounds;
|
return self.clip_bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bounds = element.get_frame_shadow_bounds(shadow);
|
// Assert that the shape is either a Frame or Group
|
||||||
|
assert!(
|
||||||
|
matches!(element.shape_type, Type::Frame(_) | Type::Group(_)),
|
||||||
|
"Shape must be a Frame or Group for nested shadow clip bounds calculation"
|
||||||
|
);
|
||||||
|
|
||||||
|
let bounds = element.get_selrect_shadow_bounds(shadow);
|
||||||
let mut transform = element.transform;
|
let mut transform = element.transform;
|
||||||
transform.post_translate(element.center());
|
transform.post_translate(element.center());
|
||||||
transform.pre_translate(-element.center());
|
transform.pre_translate(-element.center());
|
||||||
@ -753,6 +759,8 @@ impl RenderState {
|
|||||||
s.canvas().concat(&matrix);
|
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 {
|
let shape = if let Type::Bool(_) = &shape.shape_type {
|
||||||
// If any child transform doesn't match the parent transform means
|
// If any child transform doesn't match the parent transform means
|
||||||
// that the children is transformed and we need to recalculate the
|
// that the children is transformed and we need to recalculate the
|
||||||
@ -1326,67 +1334,72 @@ impl RenderState {
|
|||||||
translation,
|
translation,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Nested shapes shadowing - apply black shadow to child shapes too
|
if !matches!(element.shape_type, Type::Bool(_)) {
|
||||||
for shadow_shape_id in element.children.iter() {
|
// Nested shapes shadowing - apply black shadow to child shapes too
|
||||||
let shadow_shape = tree.get(shadow_shape_id).unwrap();
|
for shadow_shape_id in element.children.iter() {
|
||||||
let clip_bounds = node_render_state.get_shadow_clip_bounds(
|
let shadow_shape = tree.get(shadow_shape_id).unwrap();
|
||||||
element,
|
let clip_bounds = node_render_state.get_nested_shadow_clip_bounds(
|
||||||
modifiers.get(&element.id),
|
element,
|
||||||
shadow,
|
modifiers.get(&element.id),
|
||||||
);
|
|
||||||
|
|
||||||
if !matches!(shadow_shape.shape_type, Type::Text(_)) {
|
|
||||||
self.render_drop_black_shadow(
|
|
||||||
tree,
|
|
||||||
modifiers,
|
|
||||||
structure,
|
|
||||||
shadow_shape,
|
|
||||||
shadow,
|
shadow,
|
||||||
scale_content.get(&element.id),
|
|
||||||
clip_bounds,
|
|
||||||
scale,
|
|
||||||
translation,
|
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
let paint = skia::Paint::default();
|
|
||||||
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
|
|
||||||
|
|
||||||
self.surfaces
|
if !matches!(shadow_shape.shape_type, Type::Text(_)) {
|
||||||
.canvas(SurfaceId::DropShadows)
|
self.render_drop_black_shadow(
|
||||||
.save_layer(&layer_rec);
|
tree,
|
||||||
self.surfaces
|
modifiers,
|
||||||
.canvas(SurfaceId::DropShadows)
|
structure,
|
||||||
.scale((scale, scale));
|
shadow_shape,
|
||||||
self.surfaces
|
shadow,
|
||||||
.canvas(SurfaceId::DropShadows)
|
scale_content.get(&element.id),
|
||||||
.translate(translation);
|
clip_bounds,
|
||||||
|
scale,
|
||||||
|
translation,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let paint = skia::Paint::default();
|
||||||
|
let layer_rec =
|
||||||
|
skia::canvas::SaveLayerRec::default().paint(&paint);
|
||||||
|
|
||||||
let mut transformed_shadow: Cow<Shadow> = Cow::Borrowed(shadow);
|
self.surfaces
|
||||||
// transformed_shadow.to_mut().offset = (0., 0.);
|
.canvas(SurfaceId::DropShadows)
|
||||||
transformed_shadow.to_mut().color = skia::Color::BLACK;
|
.save_layer(&layer_rec);
|
||||||
transformed_shadow.to_mut().blur = transformed_shadow.blur * scale;
|
self.surfaces
|
||||||
|
.canvas(SurfaceId::DropShadows)
|
||||||
|
.scale((scale, scale));
|
||||||
|
self.surfaces
|
||||||
|
.canvas(SurfaceId::DropShadows)
|
||||||
|
.translate(translation);
|
||||||
|
|
||||||
let mut new_shadow_paint = skia::Paint::default();
|
let mut transformed_shadow: Cow<Shadow> = Cow::Borrowed(shadow);
|
||||||
new_shadow_paint
|
// transformed_shadow.to_mut().offset = (0., 0.);
|
||||||
.set_image_filter(transformed_shadow.get_drop_shadow_filter());
|
transformed_shadow.to_mut().color = skia::Color::BLACK;
|
||||||
new_shadow_paint.set_blend_mode(skia::BlendMode::SrcOver);
|
transformed_shadow.to_mut().blur =
|
||||||
|
transformed_shadow.blur * scale;
|
||||||
|
|
||||||
self.render_shape(
|
let mut new_shadow_paint = skia::Paint::default();
|
||||||
tree,
|
new_shadow_paint.set_image_filter(
|
||||||
modifiers,
|
transformed_shadow.get_drop_shadow_filter(),
|
||||||
structure,
|
);
|
||||||
shadow_shape,
|
new_shadow_paint.set_blend_mode(skia::BlendMode::SrcOver);
|
||||||
scale_content.get(&element.id),
|
|
||||||
clip_bounds,
|
self.render_shape(
|
||||||
SurfaceId::DropShadows,
|
tree,
|
||||||
SurfaceId::DropShadows,
|
modifiers,
|
||||||
SurfaceId::DropShadows,
|
structure,
|
||||||
SurfaceId::DropShadows,
|
shadow_shape,
|
||||||
true,
|
scale_content.get(&element.id),
|
||||||
None,
|
clip_bounds,
|
||||||
Some(vec![new_shadow_paint.clone()]),
|
SurfaceId::DropShadows,
|
||||||
);
|
SurfaceId::DropShadows,
|
||||||
self.surfaces.canvas(SurfaceId::DropShadows).restore();
|
SurfaceId::DropShadows,
|
||||||
|
SurfaceId::DropShadows,
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
Some(vec![new_shadow_paint.clone()]),
|
||||||
|
);
|
||||||
|
self.surfaces.canvas(SurfaceId::DropShadows).restore();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -725,12 +725,12 @@ impl Shape {
|
|||||||
.get_or_init(|| self.calculate_extrect(shapes_pool, modifiers))
|
.get_or_init(|| self.calculate_extrect(shapes_pool, modifiers))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the bounding rectangle for a frame shape's shadow, taking into account
|
/// Calculates the bounding rectangle for a selrect shape's shadow, taking into account
|
||||||
/// stroke widths and shadow properties.
|
/// stroke widths and shadow properties.
|
||||||
///
|
///
|
||||||
/// This method computes the expanded bounds that would be needed to fully render
|
/// This method computes the expanded bounds that would be needed to fully render
|
||||||
/// the shadow effect for a frame shape. It considers:
|
/// the shadow effect for a shape. It considers:
|
||||||
/// - The base frame bounds (selection rectangle)
|
/// - The base bounds (selection rectangle)
|
||||||
/// - Maximum stroke width across all strokes, accounting for stroke rendering kind
|
/// - Maximum stroke width across all strokes, accounting for stroke rendering kind
|
||||||
/// - Shadow offset (x, y displacement)
|
/// - Shadow offset (x, y displacement)
|
||||||
/// - Shadow blur radius (expands bounds outward)
|
/// - Shadow blur radius (expands bounds outward)
|
||||||
@ -742,12 +742,7 @@ impl Shape {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// A `math::Rect` representing the bounding rectangle that encompasses the shadow.
|
/// A `math::Rect` representing the bounding rectangle that encompasses the shadow.
|
||||||
/// Returns an empty rectangle if the shadow is hidden.
|
/// Returns an empty rectangle if the shadow is hidden.
|
||||||
pub fn get_frame_shadow_bounds(&self, shadow: &Shadow) -> math::Rect {
|
pub fn get_selrect_shadow_bounds(&self, shadow: &Shadow) -> math::Rect {
|
||||||
assert!(
|
|
||||||
self.is_frame(),
|
|
||||||
"This method can only be called on frame shapes"
|
|
||||||
);
|
|
||||||
|
|
||||||
let base_bounds = self.selrect();
|
let base_bounds = self.selrect();
|
||||||
let mut rect = skia::Rect::new_empty();
|
let mut rect = skia::Rect::new_empty();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user