mirror of
https://github.com/penpot/penpot.git
synced 2025-02-22 06:46:40 -05:00
♻️ Refactor render shape
This commit is contained in:
parent
3268225941
commit
5755d7d8f9
1 changed files with 64 additions and 54 deletions
|
@ -275,6 +275,7 @@ impl RenderState {
|
||||||
modifiers: Option<&Matrix>,
|
modifiers: Option<&Matrix>,
|
||||||
clip_bounds: Option<skia::Rect>,
|
clip_bounds: Option<skia::Rect>,
|
||||||
) {
|
) {
|
||||||
|
self.drawing_surface.canvas().save();
|
||||||
if let Some(modifiers) = modifiers {
|
if let Some(modifiers) = modifiers {
|
||||||
self.drawing_surface.canvas().concat(&modifiers);
|
self.drawing_surface.canvas().concat(&modifiers);
|
||||||
}
|
}
|
||||||
|
@ -340,6 +341,7 @@ impl RenderState {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.apply_drawing_to_render_canvas();
|
self.apply_drawing_to_render_canvas();
|
||||||
|
self.drawing_surface.canvas().restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_render_loop(
|
pub fn start_render_loop(
|
||||||
|
@ -361,6 +363,7 @@ impl RenderState {
|
||||||
self.drawing_surface
|
self.drawing_surface
|
||||||
.canvas()
|
.canvas()
|
||||||
.translate((self.viewbox.pan_x, self.viewbox.pan_y));
|
.translate((self.viewbox.pan_x, self.viewbox.pan_y));
|
||||||
|
//
|
||||||
self.pending_nodes = vec![NodeRenderState {
|
self.pending_nodes = vec![NodeRenderState {
|
||||||
id: Uuid::nil(),
|
id: Uuid::nil(),
|
||||||
visited_children: false,
|
visited_children: false,
|
||||||
|
@ -479,6 +482,63 @@ impl RenderState {
|
||||||
debug::render(self);
|
debug::render(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn render_shape_enter(&mut self, element: &mut Shape, mask: bool) {
|
||||||
|
// Masked groups needs two rendering passes, the first one rendering
|
||||||
|
// the content and the second one rendering the mask so we need to do
|
||||||
|
// an extra save_layer to keep all the masked group separate from other
|
||||||
|
// already drawn elements.
|
||||||
|
match element.kind {
|
||||||
|
Kind::Group(group) => {
|
||||||
|
if group.masked {
|
||||||
|
let paint = skia::Paint::default();
|
||||||
|
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
|
||||||
|
self.render_surface.canvas().save_layer(&layer_rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut paint = skia::Paint::default();
|
||||||
|
paint.set_blend_mode(element.blend_mode().into());
|
||||||
|
paint.set_alpha_f(element.opacity());
|
||||||
|
|
||||||
|
// When we're rendering the mask shape we need to set a special blend mode
|
||||||
|
// called 'destination-in' that keeps the drawn content within the mask.
|
||||||
|
// @see https://skia.org/docs/user/api/skblendmode_overview/
|
||||||
|
if mask {
|
||||||
|
let mut mask_paint = skia::Paint::default();
|
||||||
|
mask_paint.set_blend_mode(skia::BlendMode::DstIn);
|
||||||
|
let mask_rec = skia::canvas::SaveLayerRec::default().paint(&mask_paint);
|
||||||
|
self.render_surface.canvas().save_layer(&mask_rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(image_filter) = element.image_filter(self.viewbox.zoom * self.options.dpr())
|
||||||
|
{
|
||||||
|
paint.set_image_filter(image_filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
|
||||||
|
self.render_surface.canvas().save_layer(&layer_rec);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_shape_exit(&mut self, element: &mut Shape, visited_mask: bool) {
|
||||||
|
if visited_mask {
|
||||||
|
// Because masked groups needs two rendering passes (first drawing
|
||||||
|
// the content and then drawing the mask), we need to do an
|
||||||
|
// extra restore.
|
||||||
|
match element.kind {
|
||||||
|
Kind::Group(group) => {
|
||||||
|
if group.masked {
|
||||||
|
self.render_surface.canvas().restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.render_surface.canvas().restore();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn render_shape_tree(
|
pub fn render_shape_tree(
|
||||||
&mut self,
|
&mut self,
|
||||||
tree: &mut HashMap<Uuid, Shape>,
|
tree: &mut HashMap<Uuid, Shape>,
|
||||||
|
@ -498,7 +558,7 @@ impl RenderState {
|
||||||
visited_mask,
|
visited_mask,
|
||||||
mask,
|
mask,
|
||||||
} = node_render_state;
|
} = node_render_state;
|
||||||
let element = tree.get(&node_render_state.id).ok_or(
|
let element = tree.get_mut(&node_render_state.id).ok_or(
|
||||||
"Error: Element with root_id {node_render_state.id} not found in the tree."
|
"Error: Element with root_id {node_render_state.id} not found in the tree."
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)?;
|
)?;
|
||||||
|
@ -534,20 +594,8 @@ impl RenderState {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Because masked groups needs two rendering passes (first drawing
|
|
||||||
// the content and then drawing the mask), we need to do an
|
|
||||||
// extra restore.
|
|
||||||
match element.kind {
|
|
||||||
Kind::Group(group) => {
|
|
||||||
if group.masked {
|
|
||||||
self.render_surface.canvas().restore();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.render_surface.canvas().restore();
|
self.render_shape_exit(element, visited_mask);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,54 +610,16 @@ impl RenderState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Masked groups needs two rendering passes, the first one rendering
|
self.render_shape_enter(element, mask);
|
||||||
// the content and the second one rendering the mask so we need to do
|
|
||||||
// an extra save_layer to keep all the masked group separate from other
|
|
||||||
// already drawn elements.
|
|
||||||
match element.kind {
|
|
||||||
Kind::Group(group) => {
|
|
||||||
if group.masked {
|
|
||||||
let paint = skia::Paint::default();
|
|
||||||
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
|
|
||||||
self.render_surface.canvas().save_layer(&layer_rec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut paint = skia::Paint::default();
|
|
||||||
paint.set_blend_mode(element.blend_mode().into());
|
|
||||||
paint.set_alpha_f(element.opacity());
|
|
||||||
|
|
||||||
// When we're rendering the mask shape we need to set a special blend mode
|
|
||||||
// called 'destination-in' that keeps the drawn content within the mask.
|
|
||||||
// @see https://skia.org/docs/user/api/skblendmode_overview/
|
|
||||||
if mask {
|
|
||||||
let mut mask_paint = skia::Paint::default();
|
|
||||||
mask_paint.set_blend_mode(skia::BlendMode::DstIn);
|
|
||||||
let mask_rec = skia::canvas::SaveLayerRec::default().paint(&mask_paint);
|
|
||||||
self.render_surface.canvas().save_layer(&mask_rec);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(image_filter) = element.image_filter(self.viewbox.zoom * self.options.dpr())
|
|
||||||
{
|
|
||||||
paint.set_image_filter(image_filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
|
|
||||||
self.render_surface.canvas().save_layer(&layer_rec);
|
|
||||||
|
|
||||||
self.drawing_surface.canvas().save();
|
|
||||||
if !node_render_state.id.is_nil() {
|
if !node_render_state.id.is_nil() {
|
||||||
self.render_shape(
|
self.render_shape(
|
||||||
&mut element.clone(),
|
element,
|
||||||
modifiers.get(&element.id),
|
modifiers.get(&element.id),
|
||||||
clip_bounds,
|
clip_bounds,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
self.apply_drawing_to_render_canvas();
|
self.apply_drawing_to_render_canvas();
|
||||||
}
|
}
|
||||||
self.drawing_surface.canvas().restore();
|
|
||||||
|
|
||||||
// Set the node as visited_children before processing children
|
// Set the node as visited_children before processing children
|
||||||
self.pending_nodes.push(NodeRenderState {
|
self.pending_nodes.push(NodeRenderState {
|
||||||
|
|
Loading…
Add table
Reference in a new issue