mirror of
https://github.com/penpot/penpot.git
synced 2026-08-01 19:06:18 +00:00
🎉 Suport in wasm for both layer and background blur
This commit is contained in:
parent
100caa794d
commit
21cad83b2a
@ -76,7 +76,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.disabled-label-tooltip {
|
.disabled-label-tooltip {
|
||||||
flex-grow:1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
|
|||||||
@ -944,21 +944,21 @@
|
|||||||
|
|
||||||
(defn set-shape-blur
|
(defn set-shape-blur
|
||||||
[blur]
|
[blur]
|
||||||
(if (some? blur)
|
(let [type (sr/translate-blur-type :layer-blur)]
|
||||||
(let [type (sr/translate-blur-type :layer-blur)
|
(if (some? blur)
|
||||||
hidden (:hidden blur)
|
(let [hidden (:hidden blur)
|
||||||
value (:value blur)]
|
value (:value blur)]
|
||||||
(h/call wasm/internal-module "_set_shape_blur" type hidden value))
|
(h/call wasm/internal-module "_set_shape_blur" type hidden value))
|
||||||
(h/call wasm/internal-module "_clear_shape_blur")))
|
(h/call wasm/internal-module "_clear_shape_blur" type))))
|
||||||
|
|
||||||
(defn set-shape-background-blur
|
(defn set-shape-background-blur
|
||||||
[background-blur]
|
[background-blur]
|
||||||
(if (some? background-blur)
|
(let [type (sr/translate-blur-type :background-blur)]
|
||||||
(let [type (sr/translate-blur-type :background-blur)
|
(if (some? background-blur)
|
||||||
hidden (:hidden background-blur)
|
(let [hidden (:hidden background-blur)
|
||||||
value (:value background-blur)]
|
value (:value background-blur)]
|
||||||
(h/call wasm/internal-module "_set_shape_blur" type hidden value))
|
(h/call wasm/internal-module "_set_shape_blur" type hidden value))
|
||||||
(h/call wasm/internal-module "_clear_shape_blur")))
|
(h/call wasm/internal-module "_clear_shape_blur" type))))
|
||||||
|
|
||||||
(defn set-shape-corners
|
(defn set-shape-corners
|
||||||
[corners]
|
[corners]
|
||||||
|
|||||||
@ -130,7 +130,6 @@
|
|||||||
(defn- set-wasm-attr!
|
(defn- set-wasm-attr!
|
||||||
[shape k]
|
[shape k]
|
||||||
(when wasm/context-initialized?
|
(when wasm/context-initialized?
|
||||||
;;TODO_BLUR: ask about this,
|
|
||||||
(let [shape (case k
|
(let [shape (case k
|
||||||
:svg-attrs (svg-filters/apply-svg-derived (assoc shape :svg-attrs (get shape :svg-attrs)))
|
:svg-attrs (svg-filters/apply-svg-derived (assoc shape :svg-attrs (get shape :svg-attrs)))
|
||||||
(:fills :blur :shadow) (svg-filters/apply-svg-derived shape)
|
(:fills :blur :shadow) (svg-filters/apply-svg-derived shape)
|
||||||
|
|||||||
@ -44,7 +44,6 @@
|
|||||||
(set! context-initialized? false)
|
(set! context-initialized? false)
|
||||||
(reset! context-lost? false))
|
(reset! context-lost? false))
|
||||||
|
|
||||||
;; TODO_BLUR: ask for blur-type??
|
|
||||||
(defonce serializers
|
(defonce serializers
|
||||||
#js {:blur-type shared/RawBlurType
|
#js {:blur-type shared/RawBlurType
|
||||||
:blend-mode shared/RawBlendMode
|
:blend-mode shared/RawBlendMode
|
||||||
|
|||||||
@ -24,7 +24,6 @@ use std::collections::{HashMap, HashSet};
|
|||||||
use options::RenderOptions;
|
use options::RenderOptions;
|
||||||
pub use surfaces::{SurfaceId, Surfaces};
|
pub use surfaces::{SurfaceId, Surfaces};
|
||||||
|
|
||||||
// TODO_BLUR: should we add here BackgroundBlur
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::math;
|
use crate::math;
|
||||||
use crate::shapes::{
|
use crate::shapes::{
|
||||||
@ -371,7 +370,7 @@ pub(crate) struct RenderState {
|
|||||||
// migration to remove group-level fills is completed, this code should be removed.
|
// migration to remove group-level fills is completed, this code should be removed.
|
||||||
// Frames contained in groups must reset this nested_fills stack pushing a new empty vector.
|
// Frames contained in groups must reset this nested_fills stack pushing a new empty vector.
|
||||||
pub nested_fills: Vec<Vec<Fill>>,
|
pub nested_fills: Vec<Vec<Fill>>,
|
||||||
pub nested_blurs: Vec<Option<Blur>>, // FIXME: why is this an option?, sholud be an option now? TODO_BLUR
|
pub nested_blurs: Vec<Option<Blur>>, // FIXME: why is this an option?
|
||||||
pub nested_shadows: Vec<Vec<Shadow>>,
|
pub nested_shadows: Vec<Vec<Shadow>>,
|
||||||
pub show_grid: Option<Uuid>,
|
pub show_grid: Option<Uuid>,
|
||||||
pub rulers: RulerState,
|
pub rulers: RulerState,
|
||||||
@ -588,7 +587,7 @@ impl RenderState {
|
|||||||
backbuffer_crop_cache: HashMap::default(),
|
backbuffer_crop_cache: HashMap::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// TODO_BLUR: ?
|
|
||||||
/// Combines every visible layer blur currently active (ancestors + shape)
|
/// Combines every visible layer blur currently active (ancestors + shape)
|
||||||
/// into a single equivalent blur. Layer blur radii compound by adding their
|
/// into a single equivalent blur. Layer blur radii compound by adding their
|
||||||
/// variances (σ² = radius²), so we:
|
/// variances (σ² = radius²), so we:
|
||||||
@ -650,10 +649,7 @@ impl RenderState {
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let blur = match shape
|
let blur = match shape.visible_background_blur() {
|
||||||
.blur
|
|
||||||
.filter(|b| !b.hidden && b.blur_type == BlurType::BackgroundBlur)
|
|
||||||
{
|
|
||||||
Some(blur) => blur,
|
Some(blur) => blur,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
@ -1203,6 +1199,7 @@ impl RenderState {
|
|||||||
&& parent_shadows.is_none()
|
&& parent_shadows.is_none()
|
||||||
&& !shape.needs_layer()
|
&& !shape.needs_layer()
|
||||||
&& shape.blur.is_none()
|
&& shape.blur.is_none()
|
||||||
|
&& shape.background_blur.is_none()
|
||||||
&& !has_inherited_blur
|
&& !has_inherited_blur
|
||||||
&& shape.shadows.is_empty()
|
&& shape.shadows.is_empty()
|
||||||
&& shape.transform.is_identity()
|
&& shape.transform.is_identity()
|
||||||
@ -1312,20 +1309,9 @@ impl RenderState {
|
|||||||
// We don't want to change the value in the global state
|
// We don't want to change the value in the global state
|
||||||
let mut shape: Cow<Shape> = Cow::Borrowed(shape);
|
let mut shape: Cow<Shape> = Cow::Borrowed(shape);
|
||||||
|
|
||||||
// Remove background blur from the shape so it doesn't get processed
|
// Background blur is stored separately (shape.background_blur) and is
|
||||||
// as a layer blur. The actual rendering is done before the save_layer
|
// rendered before the save_layer in render_background_blur(), so here
|
||||||
// in render_background_blur() so it's independent of shape opacity.
|
// shape.blur only ever holds a layer blur.
|
||||||
if !skip_effects
|
|
||||||
&& apply_to_current_surface
|
|
||||||
&& fills_surface_id == SurfaceId::Fills
|
|
||||||
&& !matches!(shape.shape_type, Type::Text(_))
|
|
||||||
&& !matches!(shape.shape_type, Type::SVGRaw(_))
|
|
||||||
&& shape
|
|
||||||
.blur
|
|
||||||
.is_some_and(|b| !b.hidden && b.blur_type == BlurType::BackgroundBlur)
|
|
||||||
{
|
|
||||||
shape.to_mut().set_blur(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let frame_has_blur = Self::frame_clip_layer_blur(&shape).is_some();
|
let frame_has_blur = Self::frame_clip_layer_blur(&shape).is_some();
|
||||||
let shape_has_blur = shape.blur.is_some();
|
let shape_has_blur = shape.blur.is_some();
|
||||||
@ -2842,6 +2828,7 @@ impl RenderState {
|
|||||||
|
|
||||||
plain_shape_mut.clear_shadows();
|
plain_shape_mut.clear_shadows();
|
||||||
plain_shape_mut.blur = None;
|
plain_shape_mut.blur = None;
|
||||||
|
plain_shape_mut.background_blur = None;
|
||||||
|
|
||||||
// Shadow rendering uses a single render_shape call with no render_shape_exit,
|
// Shadow rendering uses a single render_shape call with no render_shape_exit,
|
||||||
// so strokes must be drawn here. Disable clip_content to avoid skip_strokes
|
// so strokes must be drawn here. Disable clip_content to avoid skip_strokes
|
||||||
@ -3645,10 +3632,8 @@ impl RenderState {
|
|||||||
// assigned to this tile) because the blur snapshots Current
|
// assigned to this tile) because the blur snapshots Current
|
||||||
// which must contain the shapes behind it.
|
// which must contain the shapes behind it.
|
||||||
let tile_has_bg_blur = ids.iter().any(|id| {
|
let tile_has_bg_blur = ids.iter().any(|id| {
|
||||||
tree.get(id).is_some_and(|s| {
|
tree.get(id)
|
||||||
s.blur
|
.is_some_and(|s| s.visible_background_blur().is_some())
|
||||||
.is_some_and(|b| !b.hidden && b.blur_type == BlurType::BackgroundBlur)
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// We only need first level shapes, in the same order as the parent node.
|
// We only need first level shapes, in the same order as the parent node.
|
||||||
|
|||||||
@ -188,6 +188,7 @@ pub struct Shape {
|
|||||||
pub blend_mode: BlendMode,
|
pub blend_mode: BlendMode,
|
||||||
pub vertical_align: VerticalAlign,
|
pub vertical_align: VerticalAlign,
|
||||||
pub blur: Option<Blur>,
|
pub blur: Option<Blur>,
|
||||||
|
pub background_blur: Option<Blur>,
|
||||||
pub opacity: f32,
|
pub opacity: f32,
|
||||||
pub hidden: bool,
|
pub hidden: bool,
|
||||||
pub svg: Option<skia::svg::Dom>,
|
pub svg: Option<skia::svg::Dom>,
|
||||||
@ -291,6 +292,7 @@ impl Shape {
|
|||||||
opacity: 1.,
|
opacity: 1.,
|
||||||
hidden: false,
|
hidden: false,
|
||||||
blur: None,
|
blur: None,
|
||||||
|
background_blur: None,
|
||||||
svg: None,
|
svg: None,
|
||||||
svg_attrs: None,
|
svg_attrs: None,
|
||||||
shadows: Vec::with_capacity(1),
|
shadows: Vec::with_capacity(1),
|
||||||
@ -314,6 +316,10 @@ impl Shape {
|
|||||||
blur.scale_content(value);
|
blur.scale_content(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(background_blur) = self.background_blur.as_mut() {
|
||||||
|
background_blur.scale_content(value);
|
||||||
|
}
|
||||||
|
|
||||||
self.layout_item
|
self.layout_item
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.for_each(|i| i.scale_content(value));
|
.for_each(|i| i.scale_content(value));
|
||||||
@ -631,6 +637,15 @@ impl Shape {
|
|||||||
self.blur = blur;
|
self.blur = blur;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_background_blur(&mut self, blur: Option<Blur>) {
|
||||||
|
self.invalidate_extrect();
|
||||||
|
self.background_blur = blur;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visible_background_blur(&self) -> Option<Blur> {
|
||||||
|
self.background_blur.filter(|blur| !blur.hidden)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_child(&mut self, id: Uuid) {
|
pub fn add_child(&mut self, id: Uuid) {
|
||||||
self.children.push(id);
|
self.children.push(id);
|
||||||
}
|
}
|
||||||
@ -1421,6 +1436,7 @@ impl Shape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.blur.is_none()
|
self.blur.is_none()
|
||||||
|
&& self.background_blur.is_none()
|
||||||
&& self.shadows.is_empty()
|
&& self.shadows.is_empty()
|
||||||
&& (self.opacity - 1.0).abs() <= 1e-4
|
&& (self.opacity - 1.0).abs() <= 1e-4
|
||||||
&& self.blend_mode().0 == skia::BlendMode::SrcOver
|
&& self.blend_mode().0 == skia::BlendMode::SrcOver
|
||||||
@ -1665,7 +1681,7 @@ impl Shape {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.blur.is_some() {
|
if self.blur.is_some() || self.background_blur.is_some() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1805,6 +1821,38 @@ mod tests {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn layer_blur_and_background_blur_can_coexist() {
|
||||||
|
let mut shape = any_shape();
|
||||||
|
|
||||||
|
let layer_blur = Blur::new(BlurType::LayerBlur, false, 4.0);
|
||||||
|
let background_blur = Blur::new(BlurType::BackgroundBlur, false, 8.0);
|
||||||
|
|
||||||
|
shape.set_blur(Some(layer_blur));
|
||||||
|
shape.set_background_blur(Some(background_blur));
|
||||||
|
|
||||||
|
assert_eq!(shape.blur, Some(layer_blur));
|
||||||
|
assert_eq!(shape.background_blur, Some(background_blur));
|
||||||
|
assert_eq!(shape.visible_background_blur(), Some(background_blur));
|
||||||
|
|
||||||
|
// Clearing one type must not affect the other.
|
||||||
|
shape.set_blur(None);
|
||||||
|
assert_eq!(shape.blur, None);
|
||||||
|
assert_eq!(shape.background_blur, Some(background_blur));
|
||||||
|
|
||||||
|
shape.set_blur(Some(layer_blur));
|
||||||
|
shape.set_background_blur(None);
|
||||||
|
assert_eq!(shape.blur, Some(layer_blur));
|
||||||
|
assert_eq!(shape.background_blur, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hidden_background_blur_is_not_visible() {
|
||||||
|
let mut shape = any_shape();
|
||||||
|
shape.set_background_blur(Some(Blur::new(BlurType::BackgroundBlur, true, 8.0)));
|
||||||
|
assert_eq!(shape.visible_background_blur(), None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_set_corners() {
|
fn test_set_corners() {
|
||||||
let mut shape = any_shape();
|
let mut shape = any_shape();
|
||||||
|
|||||||
@ -29,14 +29,21 @@ impl From<RawBlurType> for BlurType {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn set_shape_blur(blur_type: u8, hidden: bool, value: f32) {
|
pub extern "C" fn set_shape_blur(blur_type: u8, hidden: bool, value: f32) {
|
||||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||||
let blur_type = RawBlurType::from(blur_type);
|
let blur_type: BlurType = RawBlurType::from(blur_type).into();
|
||||||
shape.set_blur(Some(Blur::new(blur_type.into(), hidden, value)));
|
let blur = Some(Blur::new(blur_type, hidden, value));
|
||||||
|
match blur_type {
|
||||||
|
BlurType::LayerBlur => shape.set_blur(blur),
|
||||||
|
BlurType::BackgroundBlur => shape.set_background_blur(blur),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn clear_shape_blur() {
|
pub extern "C" fn clear_shape_blur(blur_type: u8) {
|
||||||
with_current_shape_mut!(state, |shape: &mut Shape| {
|
with_current_shape_mut!(state, |shape: &mut Shape| {
|
||||||
shape.set_blur(None);
|
match RawBlurType::from(blur_type).into() {
|
||||||
|
BlurType::LayerBlur => shape.set_blur(None),
|
||||||
|
BlurType::BackgroundBlur => shape.set_background_blur(None),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user