mirror of
https://github.com/penpot/penpot.git
synced 2025-07-03 08:27:16 +02:00
♻️ Decouple render and shapes
This commit is contained in:
parent
7b1934dcb6
commit
c7c43d6313
2 changed files with 50 additions and 29 deletions
|
@ -4,7 +4,7 @@ use skia::Contains;
|
||||||
use skia_safe as skia;
|
use skia_safe as skia;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::shapes::Shape;
|
use crate::math;
|
||||||
use crate::view::Viewbox;
|
use crate::view::Viewbox;
|
||||||
|
|
||||||
mod blend;
|
mod blend;
|
||||||
|
@ -22,6 +22,10 @@ pub trait Renderable {
|
||||||
fn render(&self, surface: &mut skia::Surface, images: &ImageStore) -> Result<(), String>;
|
fn render(&self, surface: &mut skia::Surface, images: &ImageStore) -> Result<(), String>;
|
||||||
fn blend_mode(&self) -> BlendMode;
|
fn blend_mode(&self) -> BlendMode;
|
||||||
fn opacity(&self) -> f32;
|
fn opacity(&self) -> f32;
|
||||||
|
fn bounds(&self) -> math::Rect;
|
||||||
|
fn hidden(&self) -> bool;
|
||||||
|
fn clip(&self) -> bool;
|
||||||
|
fn children_ids(&self) -> Vec<Uuid>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct CachedSurfaceImage {
|
pub(crate) struct CachedSurfaceImage {
|
||||||
|
@ -160,10 +164,10 @@ impl RenderState {
|
||||||
.clear(skia::Color::TRANSPARENT);
|
.clear(skia::Color::TRANSPARENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn navigate(&mut self, shapes: &HashMap<Uuid, Shape>) -> Result<(), String> {
|
pub fn navigate(&mut self, tree: &HashMap<Uuid, impl Renderable>) -> Result<(), String> {
|
||||||
if let Some(cached_surface_image) = self.cached_surface_image.as_ref() {
|
if let Some(cached_surface_image) = self.cached_surface_image.as_ref() {
|
||||||
if cached_surface_image.is_dirty(&self.viewbox) {
|
if cached_surface_image.is_dirty(&self.viewbox) {
|
||||||
self.render_all(shapes, true);
|
self.render_all(tree, true);
|
||||||
} else {
|
} else {
|
||||||
self.render_all_from_cache()?;
|
self.render_all_from_cache()?;
|
||||||
}
|
}
|
||||||
|
@ -174,7 +178,7 @@ impl RenderState {
|
||||||
|
|
||||||
pub fn render_all(
|
pub fn render_all(
|
||||||
&mut self,
|
&mut self,
|
||||||
shapes: &HashMap<Uuid, Shape>,
|
tree: &HashMap<Uuid, impl Renderable>,
|
||||||
generate_cached_surface_image: bool,
|
generate_cached_surface_image: bool,
|
||||||
) {
|
) {
|
||||||
self.reset_canvas();
|
self.reset_canvas();
|
||||||
|
@ -184,7 +188,7 @@ impl RenderState {
|
||||||
);
|
);
|
||||||
self.translate(self.viewbox.pan_x, self.viewbox.pan_y);
|
self.translate(self.viewbox.pan_x, self.viewbox.pan_y);
|
||||||
|
|
||||||
let is_complete = self.render_shape_tree(&Uuid::nil(), shapes);
|
let is_complete = self.render_shape_tree(&Uuid::nil(), tree);
|
||||||
if generate_cached_surface_image || self.cached_surface_image.is_none() {
|
if generate_cached_surface_image || self.cached_surface_image.is_none() {
|
||||||
self.cached_surface_image = Some(CachedSurfaceImage {
|
self.cached_surface_image = Some(CachedSurfaceImage {
|
||||||
image: self.final_surface.image_snapshot(),
|
image: self.final_surface.image_snapshot(),
|
||||||
|
@ -252,7 +256,7 @@ impl RenderState {
|
||||||
self.debug_surface.canvas().draw_rect(scaled_rect, &paint);
|
self.debug_surface.canvas().draw_rect(scaled_rect, &paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_debug_shape(&mut self, shape: &Shape, intersected: bool) {
|
fn render_debug_element(&mut self, element: &impl Renderable, intersected: bool) {
|
||||||
let mut paint = skia::Paint::default();
|
let mut paint = skia::Paint::default();
|
||||||
paint.set_style(skia::PaintStyle::Stroke);
|
paint.set_style(skia::PaintStyle::Stroke);
|
||||||
paint.set_color(if intersected {
|
paint.set_color(if intersected {
|
||||||
|
@ -262,7 +266,7 @@ impl RenderState {
|
||||||
});
|
});
|
||||||
paint.set_stroke_width(1.);
|
paint.set_stroke_width(1.);
|
||||||
|
|
||||||
let mut scaled_rect = shape.selrect.clone();
|
let mut scaled_rect = element.bounds();
|
||||||
let x = 100. + scaled_rect.x() * 0.2;
|
let x = 100. + scaled_rect.x() * 0.2;
|
||||||
let y = 100. + scaled_rect.y() * 0.2;
|
let y = 100. + scaled_rect.y() * 0.2;
|
||||||
let width = scaled_rect.width() * 0.2;
|
let width = scaled_rect.width() * 0.2;
|
||||||
|
@ -284,18 +288,18 @@ impl RenderState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a boolean indicating if the viewbox contains the rendered shapes
|
// Returns a boolean indicating if the viewbox contains the rendered shapes
|
||||||
fn render_shape_tree(&mut self, id: &Uuid, shapes: &HashMap<Uuid, Shape>) -> bool {
|
fn render_shape_tree(&mut self, root_id: &Uuid, tree: &HashMap<Uuid, impl Renderable>) -> bool {
|
||||||
let shape = shapes.get(&id).unwrap();
|
let element = tree.get(&root_id).unwrap();
|
||||||
let mut is_complete = self.viewbox.area.contains(shape.selrect);
|
let mut is_complete = self.viewbox.area.contains(element.bounds());
|
||||||
|
|
||||||
if !id.is_nil() {
|
if !root_id.is_nil() {
|
||||||
if !shape.selrect.intersects(self.viewbox.area) || shape.hidden {
|
if !element.bounds().intersects(self.viewbox.area) || element.hidden() {
|
||||||
self.render_debug_shape(shape, false);
|
self.render_debug_element(element, false);
|
||||||
// TODO: This means that not all the shapes are renderer so we
|
// TODO: This means that not all the shapes are renderer so we
|
||||||
// need to call a render_all on the zoom out.
|
// need to call a render_all on the zoom out.
|
||||||
return is_complete; // TODO return is_complete or return false??
|
return is_complete; // TODO return is_complete or return false??
|
||||||
} else {
|
} else {
|
||||||
self.render_debug_shape(shape, true);
|
self.render_debug_element(element, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,11 +307,11 @@ impl RenderState {
|
||||||
self.final_surface.canvas().save();
|
self.final_surface.canvas().save();
|
||||||
self.drawing_surface.canvas().save();
|
self.drawing_surface.canvas().save();
|
||||||
|
|
||||||
if !id.is_nil() {
|
if !root_id.is_nil() {
|
||||||
self.render_single_element(shape);
|
self.render_single_element(element);
|
||||||
if shape.clip_content {
|
if element.clip() {
|
||||||
self.drawing_surface.canvas().clip_rect(
|
self.drawing_surface.canvas().clip_rect(
|
||||||
shape.selrect,
|
element.bounds(),
|
||||||
skia::ClipOp::Intersect,
|
skia::ClipOp::Intersect,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
@ -315,13 +319,13 @@ impl RenderState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw all the children shapes
|
// draw all the children shapes
|
||||||
let shape_ids = shape.children.iter();
|
for id in element.children_ids() {
|
||||||
for shape_id in shape_ids {
|
is_complete = self.render_shape_tree(&id, tree) && is_complete;
|
||||||
is_complete = self.render_shape_tree(shape_id, shapes) && is_complete;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.final_surface.canvas().restore();
|
self.final_surface.canvas().restore();
|
||||||
self.drawing_surface.canvas().restore();
|
self.drawing_surface.canvas().restore();
|
||||||
|
|
||||||
return is_complete;
|
return is_complete;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,11 @@
|
||||||
use skia_safe as skia;
|
use skia_safe as skia;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::{draw_image_in_container, Fill, Kind, Shape};
|
use super::{draw_image_in_container, Fill, Kind, Shape};
|
||||||
use crate::math::Rect;
|
use crate::math::Rect;
|
||||||
use crate::render::{ImageStore, Renderable};
|
use crate::render::{ImageStore, Renderable};
|
||||||
|
|
||||||
impl Renderable for Shape {
|
impl Renderable for Shape {
|
||||||
fn blend_mode(&self) -> crate::render::BlendMode {
|
|
||||||
self.blend_mode
|
|
||||||
}
|
|
||||||
|
|
||||||
fn opacity(&self) -> f32 {
|
|
||||||
self.opacity
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&self, surface: &mut skia_safe::Surface, images: &ImageStore) -> Result<(), String> {
|
fn render(&self, surface: &mut skia_safe::Surface, images: &ImageStore) -> Result<(), String> {
|
||||||
let mut transform = skia::Matrix::new_identity();
|
let mut transform = skia::Matrix::new_identity();
|
||||||
let (translate_x, translate_y) = self.translation();
|
let (translate_x, translate_y) = self.translation();
|
||||||
|
@ -49,6 +42,30 @@ impl Renderable for Shape {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn blend_mode(&self) -> crate::render::BlendMode {
|
||||||
|
self.blend_mode
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opacity(&self) -> f32 {
|
||||||
|
self.opacity
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hidden(&self) -> bool {
|
||||||
|
self.hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bounds(&self) -> Rect {
|
||||||
|
self.selrect
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clip(&self) -> bool {
|
||||||
|
self.clip_content
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children_ids(&self) -> Vec<Uuid> {
|
||||||
|
self.children.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_fill(
|
fn render_fill(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue