mirror of
https://github.com/penpot/penpot.git
synced 2026-08-05 20:38:38 +00:00
⚡ Bound save_layer rects in the vector export path
This commit is contained in:
parent
25a470bf64
commit
6ec7e47197
@ -329,15 +329,21 @@ fn render_text_on_canvas(
|
||||
layer_opacity: Option<f32>,
|
||||
overlay_emoji: bool,
|
||||
) {
|
||||
let layer_bounds = shape.layer_bounds();
|
||||
|
||||
if let Some(blur_filter) = blur {
|
||||
let mut blur_paint = Paint::default();
|
||||
blur_paint.set_image_filter(blur_filter.clone());
|
||||
let blur_layer = SaveLayerRec::default().paint(&blur_paint);
|
||||
let blur_layer = SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&blur_paint);
|
||||
canvas.save_layer(&blur_layer);
|
||||
}
|
||||
|
||||
if let Some(shadow_paint) = shadow {
|
||||
let layer_rec = SaveLayerRec::default().paint(shadow_paint);
|
||||
let layer_rec = SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(shadow_paint);
|
||||
canvas.save_layer(&layer_rec);
|
||||
draw_text(
|
||||
canvas,
|
||||
@ -351,7 +357,9 @@ fn render_text_on_canvas(
|
||||
if let Some(erode) = skia_safe::image_filters::erode((eps, eps), None, None) {
|
||||
let mut layer_paint = Paint::default();
|
||||
layer_paint.set_image_filter(erode);
|
||||
let layer_rec = SaveLayerRec::default().paint(&layer_paint);
|
||||
let layer_rec = SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&layer_paint);
|
||||
canvas.save_layer(&layer_rec);
|
||||
draw_text(
|
||||
canvas,
|
||||
@ -582,7 +590,10 @@ fn draw_decoration_stroke(
|
||||
skia::BlendMode::SrcOut
|
||||
};
|
||||
|
||||
canvas.save_layer(&SaveLayerRec::default());
|
||||
let outset = stroke_paint.stroke_width().max(0.0);
|
||||
let layer_bounds = bar.with_outset((outset, outset));
|
||||
|
||||
canvas.save_layer(&SaveLayerRec::default().bounds(&layer_bounds));
|
||||
let mut mask_paint = Paint::default();
|
||||
mask_paint.set_color(skia::Color::BLACK);
|
||||
mask_paint.set_anti_alias(true);
|
||||
@ -590,7 +601,11 @@ fn draw_decoration_stroke(
|
||||
|
||||
let mut blend_paint = Paint::default();
|
||||
blend_paint.set_blend_mode(blend);
|
||||
canvas.save_layer(&SaveLayerRec::default().paint(&blend_paint));
|
||||
canvas.save_layer(
|
||||
&SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&blend_paint),
|
||||
);
|
||||
canvas.draw_rect(bar, stroke_paint);
|
||||
canvas.restore();
|
||||
canvas.restore();
|
||||
@ -705,7 +720,12 @@ pub fn render_emoji_overlay(
|
||||
if let Some(blur_filter) = blur {
|
||||
let mut blur_paint = Paint::default();
|
||||
blur_paint.set_image_filter(blur_filter.clone());
|
||||
canvas.save_layer(&SaveLayerRec::default().paint(&blur_paint));
|
||||
let layer_bounds = shape.layer_bounds();
|
||||
canvas.save_layer(
|
||||
&SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&blur_paint),
|
||||
);
|
||||
}
|
||||
|
||||
for (emoji_para, deco_para) in emoji_layout
|
||||
@ -728,13 +748,17 @@ fn draw_text(
|
||||
layer_opacity: Option<f32>,
|
||||
overlay_emoji: bool,
|
||||
) {
|
||||
let layer_bounds = shape.layer_bounds();
|
||||
|
||||
if let Some(opacity) = layer_opacity {
|
||||
let mut opacity_paint = Paint::default();
|
||||
opacity_paint.set_alpha_f(opacity);
|
||||
let layer_rec = SaveLayerRec::default().paint(&opacity_paint);
|
||||
let layer_rec = SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&opacity_paint);
|
||||
canvas.save_layer(&layer_rec);
|
||||
} else {
|
||||
canvas.save_layer(&SaveLayerRec::default());
|
||||
canvas.save_layer(&SaveLayerRec::default().bounds(&layer_bounds));
|
||||
}
|
||||
|
||||
paint_text_with_emoji_overlay(canvas, shape, paragraph_builder_groups, overlay_emoji);
|
||||
@ -759,27 +783,41 @@ fn render_masked_stroke_on_canvas(
|
||||
blur: Option<&ImageFilter>,
|
||||
layer_opacity: Option<f32>,
|
||||
) {
|
||||
let layer_bounds = shape.layer_bounds();
|
||||
|
||||
if let Some(blur_filter) = blur {
|
||||
let mut blur_paint = Paint::default();
|
||||
blur_paint.set_image_filter(blur_filter.clone());
|
||||
canvas.save_layer(&SaveLayerRec::default().paint(&blur_paint));
|
||||
canvas.save_layer(
|
||||
&SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&blur_paint),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(opacity) = layer_opacity {
|
||||
let mut opacity_paint = Paint::default();
|
||||
opacity_paint.set_alpha_f(opacity);
|
||||
canvas.save_layer(&SaveLayerRec::default().paint(&opacity_paint));
|
||||
canvas.save_layer(
|
||||
&SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&opacity_paint),
|
||||
);
|
||||
}
|
||||
|
||||
canvas.save_layer(&SaveLayerRec::default());
|
||||
canvas.save_layer(&SaveLayerRec::default().bounds(&layer_bounds));
|
||||
|
||||
canvas.save_layer(&SaveLayerRec::default());
|
||||
canvas.save_layer(&SaveLayerRec::default().bounds(&layer_bounds));
|
||||
|
||||
paint_text(canvas, shape, mask_builders);
|
||||
|
||||
let mut stroke_paint = Paint::default();
|
||||
stroke_paint.set_blend_mode(stroke_mask_blend);
|
||||
canvas.save_layer(&SaveLayerRec::default().paint(&stroke_paint));
|
||||
canvas.save_layer(
|
||||
&SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&stroke_paint),
|
||||
);
|
||||
|
||||
paint_text(canvas, shape, stroke_builders);
|
||||
|
||||
@ -789,7 +827,11 @@ fn render_masked_stroke_on_canvas(
|
||||
if let Some(fill_builders) = fill_builders {
|
||||
let mut dst_over_paint = Paint::default();
|
||||
dst_over_paint.set_blend_mode(skia::BlendMode::DstOver);
|
||||
canvas.save_layer(&SaveLayerRec::default().paint(&dst_over_paint));
|
||||
canvas.save_layer(
|
||||
&SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&dst_over_paint),
|
||||
);
|
||||
|
||||
paint_text(canvas, shape, fill_builders);
|
||||
|
||||
|
||||
@ -79,11 +79,14 @@ impl ShapeRenderer for VectorRenderer<'_> {
|
||||
}
|
||||
|
||||
fn draw_drop_shadows(&mut self, shape: &Shape) -> Result<()> {
|
||||
let layer_bounds = shape.layer_bounds();
|
||||
for shadow in shape.drop_shadows_visible() {
|
||||
if let Some(filter) = shadow.get_drop_shadow_filter() {
|
||||
let mut paint = Paint::default();
|
||||
paint.set_image_filter(filter);
|
||||
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
|
||||
let layer_rec = skia::canvas::SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&paint);
|
||||
self.canvas.save_layer(&layer_rec);
|
||||
let mut fill_paint = Paint::default();
|
||||
fill_paint.set_anti_alias(true);
|
||||
@ -99,10 +102,14 @@ impl ShapeRenderer for VectorRenderer<'_> {
|
||||
if !shape.has_fills() {
|
||||
return Ok(());
|
||||
}
|
||||
let layer_bounds = shape.layer_bounds();
|
||||
for shadow in shape.inner_shadows_visible() {
|
||||
let paint = shadow.get_inner_shadow_paint(true, shape.image_filter(1.).as_ref());
|
||||
self.canvas
|
||||
.save_layer(&skia::canvas::SaveLayerRec::default().paint(&paint));
|
||||
self.canvas.save_layer(
|
||||
&skia::canvas::SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&paint),
|
||||
);
|
||||
let mut fill_paint = Paint::default();
|
||||
fill_paint.set_anti_alias(true);
|
||||
fill_paint.set_color(skia::Color::BLACK);
|
||||
@ -161,9 +168,13 @@ impl ShapeRenderer for VectorRenderer<'_> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let layer_bounds = shape.layer_bounds();
|
||||
for shadow_paint in &drop_shadows {
|
||||
self.canvas
|
||||
.save_layer(&skia::canvas::SaveLayerRec::default().paint(shadow_paint));
|
||||
self.canvas.save_layer(
|
||||
&skia::canvas::SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(shadow_paint),
|
||||
);
|
||||
|
||||
text::render_overlay_emoji(
|
||||
self.canvas,
|
||||
@ -331,7 +342,10 @@ impl ShapeRenderer for VectorRenderer<'_> {
|
||||
if let Some(filter) = skia::image_filters::blur((sigma, sigma), None, None, None) {
|
||||
let mut paint = Paint::default();
|
||||
paint.set_image_filter(filter);
|
||||
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
|
||||
let layer_bounds = shape.layer_bounds();
|
||||
let layer_rec = skia::canvas::SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&paint);
|
||||
self.canvas.save_layer(&layer_rec);
|
||||
true
|
||||
} else {
|
||||
@ -715,7 +729,10 @@ fn render_group(
|
||||
}
|
||||
}
|
||||
|
||||
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
|
||||
let layer_bounds = element.extrect(tree, scale);
|
||||
let layer_rec = skia::canvas::SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&paint);
|
||||
canvas.save_layer(&layer_rec);
|
||||
}
|
||||
|
||||
@ -726,7 +743,12 @@ fn render_group(
|
||||
// as content, then re-draw the mask silhouette (the group's first child)
|
||||
// with DstIn to clip everything to it.
|
||||
let paint = Paint::default();
|
||||
canvas.save_layer(&skia::canvas::SaveLayerRec::default().paint(&paint));
|
||||
let subtree_bounds = element.extrect(tree, scale);
|
||||
canvas.save_layer(
|
||||
&skia::canvas::SaveLayerRec::default()
|
||||
.bounds(&subtree_bounds)
|
||||
.paint(&paint),
|
||||
);
|
||||
|
||||
for child_id in &children {
|
||||
render_tree_inner(shared, canvas, child_id, tree, scale, opts)?;
|
||||
@ -735,7 +757,11 @@ fn render_group(
|
||||
if let Some(mask_id) = element.mask_id() {
|
||||
let mut mask_paint = Paint::default();
|
||||
mask_paint.set_blend_mode(skia::BlendMode::DstIn);
|
||||
canvas.save_layer(&skia::canvas::SaveLayerRec::default().paint(&mask_paint));
|
||||
canvas.save_layer(
|
||||
&skia::canvas::SaveLayerRec::default()
|
||||
.bounds(&subtree_bounds)
|
||||
.paint(&mask_paint),
|
||||
);
|
||||
render_tree_inner(shared, canvas, mask_id, tree, scale, opts)?;
|
||||
canvas.restore(); // mask layer
|
||||
}
|
||||
@ -797,7 +823,10 @@ fn render_frame(
|
||||
}
|
||||
}
|
||||
|
||||
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
|
||||
let layer_bounds = element.extrect(tree, scale);
|
||||
let layer_rec = skia::canvas::SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&paint);
|
||||
canvas.save_layer(&layer_rec);
|
||||
}
|
||||
|
||||
@ -857,13 +886,18 @@ fn render_container_drop_shadows(
|
||||
draw_fills: bool,
|
||||
opts: &TreeOpts,
|
||||
) -> Result<()> {
|
||||
let subtree_bounds = element.extrect(tree, scale);
|
||||
for shadow in element.drop_shadows_visible() {
|
||||
let Some(filter) = shadow.get_drop_shadow_filter() else {
|
||||
continue;
|
||||
};
|
||||
let mut paint = Paint::default();
|
||||
paint.set_image_filter(filter);
|
||||
canvas.save_layer(&skia::canvas::SaveLayerRec::default().paint(&paint));
|
||||
canvas.save_layer(
|
||||
&skia::canvas::SaveLayerRec::default()
|
||||
.bounds(&subtree_bounds)
|
||||
.paint(&paint),
|
||||
);
|
||||
|
||||
if draw_fills && !element.fills.is_empty() {
|
||||
let mut renderer = VectorRenderer::new(canvas, shared, scale);
|
||||
@ -902,7 +936,10 @@ fn render_leaf(
|
||||
let mut paint = Paint::default();
|
||||
paint.set_blend_mode(element.blend_mode().into());
|
||||
paint.set_alpha_f(element.opacity());
|
||||
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
|
||||
let layer_bounds = element.layer_bounds();
|
||||
let layer_rec = skia::canvas::SaveLayerRec::default()
|
||||
.bounds(&layer_bounds)
|
||||
.paint(&paint);
|
||||
canvas.save_layer(&layer_rec);
|
||||
}
|
||||
|
||||
@ -1101,7 +1138,8 @@ fn draw_stroke_kind_aware(canvas: &Canvas, shape: &Shape, stroke: &Stroke, paint
|
||||
}
|
||||
StrokeKind::Outer => {
|
||||
canvas.save();
|
||||
canvas.save_layer(&skia::canvas::SaveLayerRec::default());
|
||||
let layer_bounds = shape.layer_bounds();
|
||||
canvas.save_layer(&skia::canvas::SaveLayerRec::default().bounds(&layer_bounds));
|
||||
draw_shape_geometry(canvas, shape, paint);
|
||||
let mut clear_paint = Paint::default();
|
||||
clear_paint.set_blend_mode(skia::BlendMode::Clear);
|
||||
@ -1134,7 +1172,8 @@ fn draw_image_stroke(
|
||||
let container = shape.selrect;
|
||||
|
||||
canvas.save();
|
||||
canvas.save_layer(&skia::canvas::SaveLayerRec::default());
|
||||
let layer_bounds = shape.layer_bounds();
|
||||
canvas.save_layer(&skia::canvas::SaveLayerRec::default().bounds(&layer_bounds));
|
||||
|
||||
// Opaque stroke silhouette; the SrcIn image draw below fills it.
|
||||
draw_stroke_geometry(canvas, scale, shape, stroke, true);
|
||||
|
||||
@ -1070,7 +1070,7 @@ impl Shape {
|
||||
extrect
|
||||
}
|
||||
|
||||
fn calculate_extrect_uncached(&self, shapes_pool: ShapesPoolRef, scale: f32) -> math::Rect {
|
||||
fn own_extrect_bounds(&self) -> Bounds {
|
||||
let shape = self;
|
||||
let max_stroke = Stroke::max_bounds_width(shape.strokes.iter(), shape.is_open());
|
||||
|
||||
@ -1096,6 +1096,19 @@ impl Shape {
|
||||
bounds = self.apply_stroke_bounds(bounds, max_stroke);
|
||||
bounds = self.apply_shadow_bounds(bounds);
|
||||
bounds = self.apply_blur_bounds(bounds);
|
||||
bounds
|
||||
}
|
||||
|
||||
/// Bound for a `SaveLayerRec` wrapping this shape's own drawing, in
|
||||
/// untransformed space (callers concatenate [`Self::centered_transform`]
|
||||
/// first). Includes shadow/blur margins, so it is also a valid input bound
|
||||
/// for a layer whose paint carries an image filter.
|
||||
pub fn layer_bounds(&self) -> math::Rect {
|
||||
self.own_extrect_bounds().to_rect()
|
||||
}
|
||||
|
||||
fn calculate_extrect_uncached(&self, shapes_pool: ShapesPoolRef, scale: f32) -> math::Rect {
|
||||
let mut bounds = self.own_extrect_bounds();
|
||||
bounds = self.apply_children_bounds(bounds, shapes_pool, scale);
|
||||
bounds = self.apply_children_blur(bounds, shapes_pool);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user