0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-21 22:36:12 -05:00

🎉 Render wasm blur support

This commit is contained in:
Alejandro Alonso 2025-01-09 13:51:12 +01:00
parent d500058aa9
commit 7cc33b1a1a
8 changed files with 117 additions and 11 deletions

View file

@ -346,7 +346,6 @@
[hidden]
(h/call internal-module "_set_shape_hidden" hidden))
(defn- translate-bool-type
[bool-type]
(case bool-type
@ -364,6 +363,19 @@
[content]
(set-shape-path-content content))
(defn- translate-blur-type
[blur-type]
(case blur-type
:layer-blur 1
0))
(defn set-shape-blur
[blur]
(let [type (-> blur :type translate-blur-type)
hidden (:hidden blur)
value (:value blur)]
(h/call internal-module "_set_shape_blur" type hidden value)))
(def debounce-render-without-cache (fns/debounce render-without-cache 100))
(defn set-view
@ -395,7 +407,8 @@
opacity (dm/get-prop shape :opacity)
hidden (dm/get-prop shape :hidden)
content (dm/get-prop shape :content)
bool-content (dm/get-prop shape :bool-content)]
bool-content (dm/get-prop shape :bool-content)
blur (dm/get-prop shape :blur)]
(use-shape id)
(set-shape-type type)
@ -407,6 +420,8 @@
(set-shape-children children)
(set-shape-opacity opacity)
(set-shape-hidden hidden)
(when (some? blur)
(set-shape-blur blur))
(when (and (some? content) (= type :path)) (set-shape-path-content content))
(when (some? bool-content) (set-shape-bool-content bool-content))
(let [pending' (concat (set-shape-fills fills) (set-shape-strokes strokes))]

View file

@ -106,7 +106,7 @@
;; --- SHAPE IMPL
(defn- impl-assoc
(defn- set-wasm-attrs
[self k v]
(when ^boolean shape/*wasm-sync*
(api/use-shape (:id self))
@ -125,11 +125,16 @@
:hidden (api/set-shape-hidden v)
:shapes (api/set-shape-children v)
:content (api/set-shape-path-content v)
:blur (api/set-shape-blur v)
nil)
;; when something synced with wasm
;; is modified, we need to request
;; a new render.
(api/request-render))
(api/request-render)))
(defn- impl-assoc
[self k v]
(set-wasm-attrs self k v)
(case k
:id
(ShapeProxy. v
@ -150,6 +155,7 @@
(defn- impl-dissoc
[self k]
(set-wasm-attrs self k nil)
(case k
:id
(ShapeProxy. nil

View file

@ -77,3 +77,12 @@ Bool operations (`bool-type`) are serialized as `u8`:
| 2 | Intersection |
| 3 | Exclusion |
| \_ | Union |
## BlurType
Blur types are serialized as `u8`:
| Value | Field |
| ----- | ------------ |
| 1 | Layer |
| \_ | None |

View file

@ -347,6 +347,14 @@ pub extern "C" fn set_shape_hidden(hidden: bool) {
}
}
#[no_mangle]
pub extern "C" fn set_shape_blur(blur_type: u8, hidden: bool, value: f32) {
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
if let Some(shape) = state.current_shape() {
shape.set_blur(blur_type, hidden, value);
}
}
#[no_mangle]
pub extern "C" fn set_shape_path_content() {
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");

View file

@ -26,6 +26,7 @@ pub trait Renderable {
fn hidden(&self) -> bool;
fn clip(&self) -> bool;
fn children_ids(&self) -> Vec<Uuid>;
fn image_filter(&self, scale: f32) -> Option<skia::ImageFilter>;
}
pub(crate) struct CachedSurfaceImage {
@ -156,15 +157,11 @@ impl RenderState {
.render(&mut self.drawing_surface, &self.images)
.unwrap();
let mut paint = skia::Paint::default();
paint.set_blend_mode(element.blend_mode().into());
paint.set_alpha_f(element.opacity());
self.drawing_surface.draw(
&mut self.final_surface.canvas(),
(0.0, 0.0),
skia::SamplingOptions::new(skia::FilterMode::Linear, skia::MipmapMode::Nearest),
Some(&paint),
Some(&skia::Paint::default()),
);
self.drawing_surface
.canvas()
@ -310,8 +307,17 @@ impl RenderState {
}
}
let mut paint = skia::Paint::default();
paint.set_blend_mode(element.blend_mode().into());
paint.set_alpha_f(element.opacity());
let filter = element.image_filter(self.viewbox.zoom * self.options.dpr());
if let Some(image_filter) = filter {
paint.set_image_filter(image_filter);
}
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
// This is needed so the next non-children shape does not carry this shape's transform
self.final_surface.canvas().save();
self.final_surface.canvas().save_layer(&layer_rec);
self.drawing_surface.canvas().save();
if !root_id.is_nil() {

View file

@ -4,6 +4,7 @@ use uuid::Uuid;
use crate::render::{BlendMode, Renderable};
mod blurs;
mod bools;
mod fills;
mod images;
@ -12,6 +13,7 @@ mod paths;
mod renderable;
mod strokes;
pub use blurs::*;
pub use bools::*;
pub use fills::*;
pub use images::*;
@ -42,6 +44,7 @@ pub struct Shape {
fills: Vec<Fill>,
strokes: Vec<Stroke>,
blend_mode: BlendMode,
blur: Blur,
opacity: f32,
hidden: bool,
}
@ -61,6 +64,7 @@ impl Shape {
blend_mode: BlendMode::default(),
opacity: 1.,
hidden: false,
blur: Blur::default(),
}
}
@ -105,6 +109,10 @@ impl Shape {
self.hidden = value;
}
pub fn set_blur(&mut self, blur_type: u8, hidden: bool, value: f32) {
self.blur = Blur::new(blur_type, hidden, value);
}
pub fn add_child(&mut self, id: Uuid) {
self.children.push(id);
}

View file

@ -0,0 +1,38 @@
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BlurType {
None,
Layer,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Blur {
pub hidden: bool,
pub blur_type: BlurType,
pub value: f32,
}
impl From<u8> for BlurType {
fn from(value: u8) -> Self {
match value {
1 => BlurType::Layer,
_ => BlurType::None,
}
}
}
impl Blur {
pub fn default() -> Self {
Blur {
blur_type: BlurType::None,
hidden: true,
value: 0.,
}
}
pub fn new(blur_type: u8, hidden: bool, value: f32) -> Self {
Blur {
blur_type: BlurType::from(blur_type),
hidden,
value,
}
}
}

View file

@ -1,7 +1,7 @@
use skia_safe as skia;
use uuid::Uuid;
use super::{Fill, Image, Kind, Path, Shape, Stroke, StrokeCap, StrokeKind};
use super::{BlurType, Fill, Image, Kind, Path, Shape, Stroke, StrokeCap, StrokeKind};
use crate::math::Rect;
use crate::render::{ImageStore, Renderable};
@ -70,6 +70,22 @@ impl Renderable for Shape {
self.children.clone()
}
}
fn image_filter(&self, scale: f32) -> Option<skia::ImageFilter> {
if !self.blur.hidden {
match self.blur.blur_type {
BlurType::None => None,
BlurType::Layer => skia::image_filters::blur(
(self.blur.value * scale, self.blur.value * scale),
None,
None,
None,
),
}
} else {
None
}
}
}
fn render_fill(