mirror of
https://github.com/penpot/penpot.git
synced 2025-12-12 06:24:17 +01:00
🐛 Fix boolean and group shadows
This commit is contained in:
@@ -124,7 +124,7 @@ impl NodeRenderState {
|
||||
/// * `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_shadow_clip_bounds(
|
||||
pub fn get_nested_shadow_clip_bounds(
|
||||
&self,
|
||||
element: &Shape,
|
||||
modifiers: Option<&Matrix>,
|
||||
@@ -134,7 +134,13 @@ impl NodeRenderState {
|
||||
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;
|
||||
transform.post_translate(element.center());
|
||||
transform.pre_translate(-element.center());
|
||||
@@ -753,6 +759,8 @@ 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
|
||||
@@ -1326,67 +1334,72 @@ impl RenderState {
|
||||
translation,
|
||||
);
|
||||
|
||||
// Nested shapes shadowing - apply black shadow to child shapes too
|
||||
for shadow_shape_id in element.children.iter() {
|
||||
let shadow_shape = tree.get(shadow_shape_id).unwrap();
|
||||
let clip_bounds = node_render_state.get_shadow_clip_bounds(
|
||||
element,
|
||||
modifiers.get(&element.id),
|
||||
shadow,
|
||||
);
|
||||
|
||||
if !matches!(shadow_shape.shape_type, Type::Text(_)) {
|
||||
self.render_drop_black_shadow(
|
||||
tree,
|
||||
modifiers,
|
||||
structure,
|
||||
shadow_shape,
|
||||
if !matches!(element.shape_type, Type::Bool(_)) {
|
||||
// Nested shapes shadowing - apply black shadow to child shapes too
|
||||
for shadow_shape_id in element.children.iter() {
|
||||
let shadow_shape = tree.get(shadow_shape_id).unwrap();
|
||||
let clip_bounds = node_render_state.get_nested_shadow_clip_bounds(
|
||||
element,
|
||||
modifiers.get(&element.id),
|
||||
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
|
||||
.canvas(SurfaceId::DropShadows)
|
||||
.save_layer(&layer_rec);
|
||||
self.surfaces
|
||||
.canvas(SurfaceId::DropShadows)
|
||||
.scale((scale, scale));
|
||||
self.surfaces
|
||||
.canvas(SurfaceId::DropShadows)
|
||||
.translate(translation);
|
||||
if !matches!(shadow_shape.shape_type, Type::Text(_)) {
|
||||
self.render_drop_black_shadow(
|
||||
tree,
|
||||
modifiers,
|
||||
structure,
|
||||
shadow_shape,
|
||||
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);
|
||||
|
||||
let mut transformed_shadow: Cow<Shadow> = Cow::Borrowed(shadow);
|
||||
// transformed_shadow.to_mut().offset = (0., 0.);
|
||||
transformed_shadow.to_mut().color = skia::Color::BLACK;
|
||||
transformed_shadow.to_mut().blur = transformed_shadow.blur * scale;
|
||||
self.surfaces
|
||||
.canvas(SurfaceId::DropShadows)
|
||||
.save_layer(&layer_rec);
|
||||
self.surfaces
|
||||
.canvas(SurfaceId::DropShadows)
|
||||
.scale((scale, scale));
|
||||
self.surfaces
|
||||
.canvas(SurfaceId::DropShadows)
|
||||
.translate(translation);
|
||||
|
||||
let mut new_shadow_paint = skia::Paint::default();
|
||||
new_shadow_paint
|
||||
.set_image_filter(transformed_shadow.get_drop_shadow_filter());
|
||||
new_shadow_paint.set_blend_mode(skia::BlendMode::SrcOver);
|
||||
let mut transformed_shadow: Cow<Shadow> = Cow::Borrowed(shadow);
|
||||
// transformed_shadow.to_mut().offset = (0., 0.);
|
||||
transformed_shadow.to_mut().color = skia::Color::BLACK;
|
||||
transformed_shadow.to_mut().blur =
|
||||
transformed_shadow.blur * scale;
|
||||
|
||||
self.render_shape(
|
||||
tree,
|
||||
modifiers,
|
||||
structure,
|
||||
shadow_shape,
|
||||
scale_content.get(&element.id),
|
||||
clip_bounds,
|
||||
SurfaceId::DropShadows,
|
||||
SurfaceId::DropShadows,
|
||||
SurfaceId::DropShadows,
|
||||
SurfaceId::DropShadows,
|
||||
true,
|
||||
None,
|
||||
Some(vec![new_shadow_paint.clone()]),
|
||||
);
|
||||
self.surfaces.canvas(SurfaceId::DropShadows).restore();
|
||||
let mut new_shadow_paint = skia::Paint::default();
|
||||
new_shadow_paint.set_image_filter(
|
||||
transformed_shadow.get_drop_shadow_filter(),
|
||||
);
|
||||
new_shadow_paint.set_blend_mode(skia::BlendMode::SrcOver);
|
||||
|
||||
self.render_shape(
|
||||
tree,
|
||||
modifiers,
|
||||
structure,
|
||||
shadow_shape,
|
||||
scale_content.get(&element.id),
|
||||
clip_bounds,
|
||||
SurfaceId::DropShadows,
|
||||
SurfaceId::DropShadows,
|
||||
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))
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// This method computes the expanded bounds that would be needed to fully render
|
||||
/// the shadow effect for a frame shape. It considers:
|
||||
/// - The base frame bounds (selection rectangle)
|
||||
/// the shadow effect for a shape. It considers:
|
||||
/// - The base bounds (selection rectangle)
|
||||
/// - Maximum stroke width across all strokes, accounting for stroke rendering kind
|
||||
/// - Shadow offset (x, y displacement)
|
||||
/// - Shadow blur radius (expands bounds outward)
|
||||
@@ -742,12 +742,7 @@ impl Shape {
|
||||
/// # Returns
|
||||
/// A `math::Rect` representing the bounding rectangle that encompasses the shadow.
|
||||
/// Returns an empty rectangle if the shadow is hidden.
|
||||
pub fn get_frame_shadow_bounds(&self, shadow: &Shadow) -> math::Rect {
|
||||
assert!(
|
||||
self.is_frame(),
|
||||
"This method can only be called on frame shapes"
|
||||
);
|
||||
|
||||
pub fn get_selrect_shadow_bounds(&self, shadow: &Shadow) -> math::Rect {
|
||||
let base_bounds = self.selrect();
|
||||
let mut rect = skia::Rect::new_empty();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user