Merge pull request #6126 from penpot/elenatorro-10516-fix-stroke-shadows

🐛 Fix stroke shadows
This commit is contained in:
Alejandro 2025-03-28 09:54:39 +01:00 committed by GitHub
commit bd5e47f5fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 122 additions and 201 deletions

View file

@ -210,43 +210,35 @@ impl RenderState {
} }
pub fn apply_drawing_to_render_canvas(&mut self, shape: Option<&Shape>) { pub fn apply_drawing_to_render_canvas(&mut self, shape: Option<&Shape>) {
self.surfaces
.flush_and_submit(&mut self.gpu_state, SurfaceId::Fills);
self.surfaces self.surfaces
.flush_and_submit(&mut self.gpu_state, SurfaceId::DropShadows); .flush_and_submit(&mut self.gpu_state, SurfaceId::DropShadows);
self.surfaces
.flush_and_submit(&mut self.gpu_state, SurfaceId::InnerShadows);
self.surfaces.draw_into( self.surfaces.draw_into(
SurfaceId::DropShadows, SurfaceId::DropShadows,
SurfaceId::Current, SurfaceId::Current,
Some(&skia::Paint::default()), Some(&skia::Paint::default()),
); );
self.surfaces
.flush_and_submit(&mut self.gpu_state, SurfaceId::Fills);
self.surfaces.draw_into( self.surfaces.draw_into(
SurfaceId::Fills, SurfaceId::Fills,
SurfaceId::Current, SurfaceId::Current,
Some(&skia::Paint::default()), Some(&skia::Paint::default()),
); );
self.surfaces.draw_into(
SurfaceId::InnerShadows,
SurfaceId::Current,
Some(&skia::Paint::default()),
);
let mut render_overlay_below_strokes = false; let mut render_overlay_below_strokes = false;
if let Some(shape) = shape { if let Some(shape) = shape {
render_overlay_below_strokes = shape.fills().len() > 0; render_overlay_below_strokes = shape.has_fills();
} }
if render_overlay_below_strokes { if render_overlay_below_strokes {
self.surfaces self.surfaces
.flush_and_submit(&mut self.gpu_state, SurfaceId::Overlay); .flush_and_submit(&mut self.gpu_state, SurfaceId::InnerShadows);
self.surfaces.draw_into( self.surfaces.draw_into(
SurfaceId::Overlay, SurfaceId::InnerShadows,
SurfaceId::Current, SurfaceId::Current,
Some(&skia::Paint::default()), Some(&skia::Paint::default()),
); );
@ -254,6 +246,7 @@ impl RenderState {
self.surfaces self.surfaces
.flush_and_submit(&mut self.gpu_state, SurfaceId::Strokes); .flush_and_submit(&mut self.gpu_state, SurfaceId::Strokes);
self.surfaces.draw_into( self.surfaces.draw_into(
SurfaceId::Strokes, SurfaceId::Strokes,
SurfaceId::Current, SurfaceId::Current,
@ -262,25 +255,22 @@ impl RenderState {
if !render_overlay_below_strokes { if !render_overlay_below_strokes {
self.surfaces self.surfaces
.flush_and_submit(&mut self.gpu_state, SurfaceId::Overlay); .flush_and_submit(&mut self.gpu_state, SurfaceId::InnerShadows);
self.surfaces.draw_into( self.surfaces.draw_into(
SurfaceId::Overlay, SurfaceId::InnerShadows,
SurfaceId::Current, SurfaceId::Current,
Some(&skia::Paint::default()), Some(&skia::Paint::default()),
); );
} }
self.surfaces
.draw_into(SurfaceId::Overlay, SurfaceId::Current, None);
self.surfaces self.surfaces
.flush_and_submit(&mut self.gpu_state, SurfaceId::Current); .flush_and_submit(&mut self.gpu_state, SurfaceId::Current);
self.surfaces.apply_mut( self.surfaces.apply_mut(
&[ &[
SurfaceId::Shadow,
SurfaceId::InnerShadows,
SurfaceId::DropShadows, SurfaceId::DropShadows,
SurfaceId::Overlay, SurfaceId::InnerShadows,
SurfaceId::Fills, SurfaceId::Fills,
SurfaceId::Strokes, SurfaceId::Strokes,
], ],
@ -403,11 +393,13 @@ impl RenderState {
} }
for stroke in shape.strokes().rev() { for stroke in shape.strokes().rev() {
strokes::render(self, &shape, stroke, antialias); shadows::render_stroke_drop_shadows(self, &shape, stroke, antialias);
strokes::render(self, &shape, stroke, None, None, antialias);
shadows::render_stroke_inner_shadows(self, &shape, stroke, antialias);
} }
shadows::render_inner_shadows(self, &shape, antialias); shadows::render_fill_inner_shadows(self, &shape, antialias);
shadows::render_drop_shadows(self, &shape, antialias); shadows::render_fill_drop_shadows(self, &shape, antialias);
} }
}; };

View file

@ -1,18 +1,14 @@
use super::{RenderState, SurfaceId}; use super::{RenderState, SurfaceId};
use crate::shapes::{Shadow, Shape, Type}; use crate::render::strokes;
use skia_safe::{self as skia, Paint}; use crate::shapes::{Shadow, Shape, Stroke, Type};
use skia_safe::Paint;
// Drop Shadows // Fill Shadows
pub fn render_drop_shadows(render_state: &mut RenderState, shape: &Shape, antialias: bool) { pub fn render_fill_drop_shadows(render_state: &mut RenderState, shape: &Shape, antialias: bool) {
if shape.has_fills() { if shape.has_fills() {
for shadow in shape.drop_shadows().rev().filter(|s| !s.hidden()) { for shadow in shape.drop_shadows().rev().filter(|s| !s.hidden()) {
render_fill_drop_shadow(render_state, &shape, &shadow, antialias); render_fill_drop_shadow(render_state, &shape, &shadow, antialias);
} }
} else {
let scale = render_state.get_scale();
for shadow in shape.drop_shadows().rev().filter(|s| !s.hidden()) {
render_stroke_drop_shadow(render_state, &shadow, scale, antialias);
}
} }
} }
@ -26,42 +22,11 @@ fn render_fill_drop_shadow(
render_shadow_paint(render_state, shape, paint, SurfaceId::DropShadows); render_shadow_paint(render_state, shape, paint, SurfaceId::DropShadows);
} }
// TODO: Stroke shadows pub fn render_fill_inner_shadows(render_state: &mut RenderState, shape: &Shape, antialias: bool) {
fn render_stroke_drop_shadow(
render_state: &mut RenderState,
shadow: &Shadow,
scale: f32,
antialias: bool,
) {
let shadow_paint = &shadow.to_paint(scale, antialias);
render_state
.surfaces
.draw_into(SurfaceId::Strokes, SurfaceId::Shadow, Some(shadow_paint));
render_state.surfaces.draw_into(
SurfaceId::Shadow,
SurfaceId::Current,
Some(&skia::Paint::default()),
);
render_state
.surfaces
.canvas(SurfaceId::Shadow)
.clear(skia::Color::TRANSPARENT);
}
// Inner Shadows
pub fn render_inner_shadows(render_state: &mut RenderState, shape: &Shape, antialias: bool) {
if shape.has_fills() { if shape.has_fills() {
for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) { for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) {
render_fill_inner_shadow(render_state, &shape, &shadow, antialias); render_fill_inner_shadow(render_state, &shape, &shadow, antialias);
} }
} else {
let scale = render_state.get_scale();
for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) {
render_stroke_inner_shadow(render_state, &shadow, scale, antialias);
}
} }
} }
@ -75,29 +40,46 @@ fn render_fill_inner_shadow(
render_shadow_paint(render_state, shape, paint, SurfaceId::InnerShadows); render_shadow_paint(render_state, shape, paint, SurfaceId::InnerShadows);
} }
// TODO: Stroke shadows pub fn render_stroke_drop_shadows(
fn render_stroke_inner_shadow(
render_state: &mut RenderState, render_state: &mut RenderState,
shadow: &Shadow, shape: &Shape,
scale: f32, stroke: &Stroke,
antialias: bool, antialias: bool,
) { ) {
let shadow_paint = &shadow.to_paint(scale, antialias); if !shape.has_fills() {
for shadow in shape.drop_shadows().rev().filter(|s| !s.hidden()) {
let filter = shadow.get_drop_shadow_filter();
strokes::render(
render_state,
&shape,
stroke,
Some(SurfaceId::Strokes), // FIXME
filter.as_ref(),
antialias,
)
}
}
}
render_state pub fn render_stroke_inner_shadows(
.surfaces render_state: &mut RenderState,
.draw_into(SurfaceId::Strokes, SurfaceId::Shadow, Some(shadow_paint)); shape: &Shape,
stroke: &Stroke,
render_state.surfaces.draw_into( antialias: bool,
SurfaceId::Shadow, ) {
SurfaceId::Overlay, if !shape.has_fills() {
Some(&skia::Paint::default()), for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) {
); let filter = shadow.get_inner_shadow_filter();
strokes::render(
render_state render_state,
.surfaces &shape,
.canvas(SurfaceId::Shadow) stroke,
.clear(skia::Color::TRANSPARENT); Some(SurfaceId::Strokes), // FIXME
filter.as_ref(),
antialias,
)
}
}
} }
fn render_shadow_paint( fn render_shadow_paint(

View file

@ -3,7 +3,7 @@ use std::collections::HashMap;
use crate::math::{Matrix, Point, Rect}; use crate::math::{Matrix, Point, Rect};
use crate::shapes::{Corners, Fill, ImageFill, Path, Shape, Stroke, StrokeCap, StrokeKind, Type}; use crate::shapes::{Corners, Fill, ImageFill, Path, Shape, Stroke, StrokeCap, StrokeKind, Type};
use skia_safe::{self as skia, RRect}; use skia_safe::{self as skia, ImageFilter, RRect};
use super::{RenderState, SurfaceId}; use super::{RenderState, SurfaceId};
@ -15,6 +15,7 @@ fn draw_stroke_on_rect(
corners: &Option<Corners>, corners: &Option<Corners>,
svg_attrs: &HashMap<String, String>, svg_attrs: &HashMap<String, String>,
scale: f32, scale: f32,
shadow: Option<&ImageFilter>,
antialias: bool, antialias: bool,
) { ) {
// Draw the different kind of strokes for a rect is straightforward, we just need apply a stroke to: // Draw the different kind of strokes for a rect is straightforward, we just need apply a stroke to:
@ -22,7 +23,11 @@ fn draw_stroke_on_rect(
// - A bigger rect if it's an outer stroke // - A bigger rect if it's an outer stroke
// - A smaller rect if it's an outer stroke // - A smaller rect if it's an outer stroke
let stroke_rect = stroke.outer_rect(rect); let stroke_rect = stroke.outer_rect(rect);
let paint = stroke.to_paint(selrect, svg_attrs, scale, antialias); let mut paint = stroke.to_paint(selrect, svg_attrs, scale, antialias);
if let Some(filter) = shadow {
paint.set_image_filter(filter.clone());
}
match corners { match corners {
Some(radii) => { Some(radii) => {
@ -43,6 +48,7 @@ fn draw_stroke_on_circle(
selrect: &Rect, selrect: &Rect,
svg_attrs: &HashMap<String, String>, svg_attrs: &HashMap<String, String>,
scale: f32, scale: f32,
shadow: Option<&ImageFilter>,
antialias: bool, antialias: bool,
) { ) {
// Draw the different kind of strokes for an oval is straightforward, we just need apply a stroke to: // Draw the different kind of strokes for an oval is straightforward, we just need apply a stroke to:
@ -50,13 +56,16 @@ fn draw_stroke_on_circle(
// - A bigger oval if it's an outer stroke // - A bigger oval if it's an outer stroke
// - A smaller oval if it's an outer stroke // - A smaller oval if it's an outer stroke
let stroke_rect = stroke.outer_rect(rect); let stroke_rect = stroke.outer_rect(rect);
canvas.draw_oval( let mut paint = stroke.to_paint(selrect, svg_attrs, scale, antialias);
&stroke_rect,
&stroke.to_paint(selrect, svg_attrs, scale, antialias), if let Some(filter) = shadow {
); paint.set_image_filter(filter.clone());
}
canvas.draw_oval(&stroke_rect, &paint);
} }
fn draw_stroke_on_path( pub fn draw_stroke_on_path(
canvas: &skia::Canvas, canvas: &skia::Canvas,
stroke: &Stroke, stroke: &Stroke,
path: &Path, path: &Path,
@ -64,13 +73,19 @@ fn draw_stroke_on_path(
path_transform: Option<&Matrix>, path_transform: Option<&Matrix>,
svg_attrs: &HashMap<String, String>, svg_attrs: &HashMap<String, String>,
scale: f32, scale: f32,
shadow: Option<&ImageFilter>,
antialias: bool, antialias: bool,
) { ) {
let mut skia_path = path.to_skia_path(); let mut skia_path = path.to_skia_path();
skia_path.transform(path_transform.unwrap()); skia_path.transform(path_transform.unwrap());
let is_open = path.is_open(); let is_open = path.is_open();
let paint_stroke = stroke.to_stroked_paint(is_open, selrect, svg_attrs, scale, antialias); let mut paint: skia_safe::Handle<_> =
stroke.to_stroked_paint(path.is_open(), selrect, svg_attrs, scale, antialias);
if let Some(filter) = shadow {
paint.set_image_filter(filter.clone());
}
// Draw the different kind of strokes for a path requires different strategies: // Draw the different kind of strokes for a path requires different strategies:
match stroke.render_kind(is_open) { match stroke.render_kind(is_open) {
@ -78,22 +93,21 @@ fn draw_stroke_on_path(
StrokeKind::InnerStroke => { StrokeKind::InnerStroke => {
canvas.save(); // As we are using clear for surfaces we use save and restore here to still be able to clean the full surface canvas.save(); // As we are using clear for surfaces we use save and restore here to still be able to clean the full surface
canvas.clip_path(&skia_path, skia::ClipOp::Intersect, antialias); canvas.clip_path(&skia_path, skia::ClipOp::Intersect, antialias);
canvas.draw_path(&skia_path, &paint_stroke); canvas.draw_path(&skia_path, &paint);
canvas.restore(); canvas.restore();
} }
// For center stroke we don't need to do anything extra // For center stroke we don't need to do anything extra
StrokeKind::CenterStroke => { StrokeKind::CenterStroke => {
canvas.draw_path(&skia_path, &paint_stroke); canvas.draw_path(&skia_path, &paint);
} }
// For outer stroke we draw a center stroke (with double width) and use another path with blend mode clear to remove the inner stroke added // For outer stroke we draw a center stroke (with double width) and use another path with blend mode clear to remove the inner stroke added
StrokeKind::OuterStroke => { StrokeKind::OuterStroke => {
let mut paint = skia::Paint::default(); let mut outer_paint = skia::Paint::default();
paint.set_blend_mode(skia::BlendMode::SrcOver); outer_paint.set_blend_mode(skia::BlendMode::SrcOver);
paint.set_anti_alias(antialias); outer_paint.set_anti_alias(antialias);
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint); let layer_rec = skia::canvas::SaveLayerRec::default().paint(&outer_paint);
canvas.save_layer(&layer_rec); canvas.save_layer(&layer_rec);
canvas.draw_path(&skia_path, &paint);
canvas.draw_path(&skia_path, &paint_stroke);
let mut clear_paint = skia::Paint::default(); let mut clear_paint = skia::Paint::default();
clear_paint.set_blend_mode(skia::BlendMode::Clear); clear_paint.set_blend_mode(skia::BlendMode::Clear);
@ -344,7 +358,7 @@ fn draw_image_stroke_in_container(
let size = image_fill.size(); let size = image_fill.size();
let scale = render_state.get_scale(); let scale = render_state.get_scale();
let canvas = render_state.surfaces.canvas(SurfaceId::Fills); let canvas = render_state.surfaces.canvas(SurfaceId::Strokes);
let container = &shape.selrect; let container = &shape.selrect;
let path_transform = shape.to_path_transform(); let path_transform = shape.to_path_transform();
let svg_attrs = &shape.svg_attrs; let svg_attrs = &shape.svg_attrs;
@ -370,6 +384,7 @@ fn draw_image_stroke_in_container(
&shape_type.corners(), &shape_type.corners(),
svg_attrs, svg_attrs,
scale, scale,
None,
antialias, antialias,
); );
} }
@ -380,6 +395,7 @@ fn draw_image_stroke_in_container(
&outer_rect, &outer_rect,
svg_attrs, svg_attrs,
scale, scale,
None,
antialias, antialias,
), ),
@ -456,15 +472,26 @@ fn draw_image_stroke_in_container(
/** /**
* This SHOULD be the only public function in this module. * This SHOULD be the only public function in this module.
*/ */
pub fn render(render_state: &mut RenderState, shape: &Shape, stroke: &Stroke, antialias: bool) { pub fn render(
render_state: &mut RenderState,
shape: &Shape,
stroke: &Stroke,
surface_id: Option<SurfaceId>,
shadow: Option<&ImageFilter>,
antialias: bool,
) {
let scale = render_state.get_scale(); let scale = render_state.get_scale();
let canvas = render_state.surfaces.canvas(SurfaceId::Strokes); let canvas = render_state
.surfaces
.canvas(surface_id.unwrap_or(SurfaceId::Strokes));
let selrect = shape.selrect; let selrect = shape.selrect;
let path_transform = shape.to_path_transform(); let path_transform = shape.to_path_transform();
let svg_attrs = &shape.svg_attrs; let svg_attrs = &shape.svg_attrs;
if let Fill::Image(image_fill) = &stroke.fill { if !shadow.is_some() && matches!(stroke.fill, Fill::Image(_)) {
draw_image_stroke_in_container(render_state, shape, stroke, image_fill, antialias); if let Fill::Image(image_fill) = &stroke.fill {
draw_image_stroke_in_container(render_state, shape, stroke, image_fill, antialias);
}
} else { } else {
match &shape.shape_type { match &shape.shape_type {
shape_type @ (Type::Rect(_) | Type::Frame(_)) => { shape_type @ (Type::Rect(_) | Type::Frame(_)) => {
@ -476,11 +503,12 @@ pub fn render(render_state: &mut RenderState, shape: &Shape, stroke: &Stroke, an
&shape_type.corners(), &shape_type.corners(),
svg_attrs, svg_attrs,
scale, scale,
shadow,
antialias, antialias,
); );
} }
Type::Circle => draw_stroke_on_circle( Type::Circle => draw_stroke_on_circle(
canvas, stroke, &selrect, &selrect, svg_attrs, scale, antialias, canvas, stroke, &selrect, &selrect, svg_attrs, scale, shadow, antialias,
), ),
shape_type @ (Type::Path(_) | Type::Bool(_)) => { shape_type @ (Type::Path(_) | Type::Bool(_)) => {
if let Some(path) = shape_type.path() { if let Some(path) = shape_type.path() {
@ -492,6 +520,7 @@ pub fn render(render_state: &mut RenderState, shape: &Shape, stroke: &Stroke, an
path_transform.as_ref(), path_transform.as_ref(),
svg_attrs, svg_attrs,
scale, scale,
shadow,
antialias, antialias,
); );
} }

View file

@ -13,10 +13,8 @@ pub enum SurfaceId {
Current, Current,
Fills, Fills,
Strokes, Strokes,
Shadow,
DropShadows, DropShadows,
InnerShadows, InnerShadows,
Overlay,
Debug, Debug,
} }
@ -30,12 +28,9 @@ pub struct Surfaces {
// keeps the current shape's strokes // keeps the current shape's strokes
shape_strokes: skia::Surface, shape_strokes: skia::Surface,
// used for rendering shadows // used for rendering shadows
shadow: skia::Surface,
// used for new shadow rendering
drop_shadows: skia::Surface, drop_shadows: skia::Surface,
// used fo rendering over shadows.
inner_shadows: skia::Surface, inner_shadows: skia::Surface,
// for drawing the things that are over shadows.
overlay: skia::Surface,
// for drawing debug info. // for drawing debug info.
debug: skia::Surface, debug: skia::Surface,
// for drawing tiles. // for drawing tiles.
@ -63,10 +58,8 @@ impl Surfaces {
let mut target = gpu_state.create_target_surface(width, height); let mut target = gpu_state.create_target_surface(width, height);
let current = target.new_surface_with_dimensions(extra_tile_dims).unwrap(); let current = target.new_surface_with_dimensions(extra_tile_dims).unwrap();
let shadow = target.new_surface_with_dimensions(extra_tile_dims).unwrap();
let drop_shadows = target.new_surface_with_dimensions(extra_tile_dims).unwrap(); let drop_shadows = target.new_surface_with_dimensions(extra_tile_dims).unwrap();
let inner_shadows = target.new_surface_with_dimensions(extra_tile_dims).unwrap(); let inner_shadows = target.new_surface_with_dimensions(extra_tile_dims).unwrap();
let overlay = target.new_surface_with_dimensions(extra_tile_dims).unwrap();
let shape_fills = target.new_surface_with_dimensions(extra_tile_dims).unwrap(); let shape_fills = target.new_surface_with_dimensions(extra_tile_dims).unwrap();
let shape_strokes = target.new_surface_with_dimensions(extra_tile_dims).unwrap(); let shape_strokes = target.new_surface_with_dimensions(extra_tile_dims).unwrap();
let debug = target.new_surface_with_dimensions((width, height)).unwrap(); let debug = target.new_surface_with_dimensions((width, height)).unwrap();
@ -79,10 +72,8 @@ impl Surfaces {
Surfaces { Surfaces {
target, target,
current, current,
shadow,
drop_shadows, drop_shadows,
inner_shadows, inner_shadows,
overlay,
shape_fills, shape_fills,
shape_strokes, shape_strokes,
debug, debug,
@ -176,10 +167,8 @@ impl Surfaces {
match id { match id {
SurfaceId::Target => &mut self.target, SurfaceId::Target => &mut self.target,
SurfaceId::Current => &mut self.current, SurfaceId::Current => &mut self.current,
SurfaceId::Shadow => &mut self.shadow,
SurfaceId::DropShadows => &mut self.drop_shadows, SurfaceId::DropShadows => &mut self.drop_shadows,
SurfaceId::InnerShadows => &mut self.inner_shadows, SurfaceId::InnerShadows => &mut self.inner_shadows,
SurfaceId::Overlay => &mut self.overlay,
SurfaceId::Fills => &mut self.shape_fills, SurfaceId::Fills => &mut self.shape_fills,
SurfaceId::Strokes => &mut self.shape_strokes, SurfaceId::Strokes => &mut self.shape_strokes,
SurfaceId::Debug => &mut self.debug, SurfaceId::Debug => &mut self.debug,
@ -225,8 +214,6 @@ impl Surfaces {
SurfaceId::Current, SurfaceId::Current,
SurfaceId::DropShadows, SurfaceId::DropShadows,
SurfaceId::InnerShadows, SurfaceId::InnerShadows,
SurfaceId::Shadow,
SurfaceId::Overlay,
], ],
|s| { |s| {
s.canvas().clear(color).reset_matrix(); s.canvas().clear(color).reset_matrix();

View file

@ -1,4 +1,4 @@
use skia_safe::{self as skia, image_filters, ImageFilter}; use skia_safe::{self as skia, image_filters, ImageFilter, Paint};
use super::Color; use super::Color;
@ -62,75 +62,8 @@ impl Shadow {
self.hidden self.hidden
} }
pub fn to_paint(&self, scale: f32, antialias: bool) -> skia::Paint { pub fn get_drop_shadow_paint(&self, antialias: bool) -> Paint {
let mut paint = skia::Paint::default(); let mut paint = Paint::default();
let image_filter = match self.style {
ShadowStyle::Drop => self.drop_shadow_filters(scale),
ShadowStyle::Inner => self.inner_shadow_filters(scale),
};
paint.set_image_filter(image_filter);
paint.set_anti_alias(antialias);
paint
}
// To be removed: Old methods for Drop Shadows and Inner Shadows (now used opnly for stroke shadows)
fn drop_shadow_filters(&self, scale: f32) -> Option<ImageFilter> {
let mut filter = image_filters::drop_shadow_only(
(self.offset.0 * scale, self.offset.1 * scale),
(self.blur * scale, self.blur * scale),
self.color,
None,
None,
None,
);
if self.spread > 0. {
filter =
image_filters::dilate((self.spread * scale, self.spread * scale), filter, None);
}
filter
}
fn inner_shadow_filters(&self, scale: f32) -> Option<ImageFilter> {
let sigma = self.blur * 0.5;
let mut filter = skia::image_filters::drop_shadow_only(
(self.offset.0 * scale, self.offset.1 * scale), // DPR?
(sigma * scale, sigma * scale),
skia::Color::BLACK,
None,
None,
None,
);
filter = skia::image_filters::color_filter(
skia::color_filters::blend(self.color, skia::BlendMode::SrcOut).unwrap(),
filter,
None,
);
if self.spread > 0. {
filter = skia::image_filters::dilate(
(self.spread * scale, self.spread * scale),
filter,
None,
);
}
filter = skia::image_filters::blend(skia::BlendMode::SrcIn, None, filter, None);
filter
}
// New methods for Drop Shadows
pub fn get_drop_shadow_paint(&self, antialias: bool) -> skia::Paint {
let mut paint = skia::Paint::default();
let image_filter = self.get_drop_shadow_filter(); let image_filter = self.get_drop_shadow_filter();
paint.set_image_filter(image_filter); paint.set_image_filter(image_filter);
@ -139,7 +72,7 @@ impl Shadow {
paint paint
} }
fn get_drop_shadow_filter(&self) -> Option<ImageFilter> { pub fn get_drop_shadow_filter(&self) -> Option<ImageFilter> {
let mut filter = image_filters::drop_shadow_only( let mut filter = image_filters::drop_shadow_only(
(self.offset.0, self.offset.1), (self.offset.0, self.offset.1),
(self.blur, self.blur), (self.blur, self.blur),
@ -156,10 +89,8 @@ impl Shadow {
filter filter
} }
// New methods for Inner Shadows pub fn get_inner_shadow_paint(&self, antialias: bool) -> Paint {
let mut paint = Paint::default();
pub fn get_inner_shadow_paint(&self, antialias: bool) -> skia::Paint {
let mut paint = skia::Paint::default();
let image_filter = self.get_inner_shadow_filter(); let image_filter = self.get_inner_shadow_filter();
@ -169,12 +100,12 @@ impl Shadow {
paint paint
} }
fn get_inner_shadow_filter(&self) -> Option<ImageFilter> { pub fn get_inner_shadow_filter(&self) -> Option<ImageFilter> {
let sigma = self.blur * 0.5; let sigma = self.blur * 0.5;
let mut filter = skia::image_filters::drop_shadow_only( let mut filter = skia::image_filters::drop_shadow_only(
(self.offset.0, self.offset.1), // DPR? (self.offset.0, self.offset.1), // DPR?
(sigma, sigma), (sigma, sigma),
skia::Color::BLACK, skia::Color::WHITE,
None, None,
None, None,
None, None,

View file

@ -232,13 +232,13 @@ impl Stroke {
match self.render_kind(is_open) { match self.render_kind(is_open) {
StrokeKind::InnerStroke => { StrokeKind::InnerStroke => {
paint.set_stroke_width(2. * paint.stroke_width()); paint.set_stroke_width(2. * paint.stroke_width());
paint
} }
StrokeKind::CenterStroke => paint, StrokeKind::CenterStroke => {}
StrokeKind::OuterStroke => { StrokeKind::OuterStroke => {
paint.set_stroke_width(2. * paint.stroke_width()); paint.set_stroke_width(2. * paint.stroke_width());
paint
} }
} }
paint
} }
} }