🐛 Fix Fill Inner Shadows

This commit is contained in:
Elena Torro 2025-03-20 15:01:00 +01:00
parent e60e36a0e2
commit 91d15ea221
5 changed files with 149 additions and 49 deletions

View file

@ -216,6 +216,9 @@ impl RenderState {
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,
@ -228,6 +231,12 @@ impl RenderState {
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.fills().len() > 0;
@ -269,6 +278,7 @@ impl RenderState {
self.surfaces.apply_mut( self.surfaces.apply_mut(
&[ &[
SurfaceId::Shadow, SurfaceId::Shadow,
SurfaceId::InnerShadows,
SurfaceId::DropShadows, SurfaceId::DropShadows,
SurfaceId::Overlay, SurfaceId::Overlay,
SurfaceId::Fills, SurfaceId::Fills,
@ -286,7 +296,12 @@ impl RenderState {
modifiers: Option<&Matrix>, modifiers: Option<&Matrix>,
clip_bounds: Option<(Rect, Option<Corners>, Matrix)>, clip_bounds: Option<(Rect, Option<Corners>, Matrix)>,
) { ) {
let surface_ids = &[SurfaceId::Fills, SurfaceId::Strokes, SurfaceId::DropShadows]; let surface_ids = &[
SurfaceId::Fills,
SurfaceId::Strokes,
SurfaceId::DropShadows,
SurfaceId::InnerShadows,
];
self.surfaces.apply_mut(surface_ids, |s| { self.surfaces.apply_mut(surface_ids, |s| {
s.canvas().save(); s.canvas().save();
}); });
@ -365,7 +380,12 @@ impl RenderState {
} }
_ => { _ => {
self.surfaces.apply_mut( self.surfaces.apply_mut(
&[SurfaceId::Fills, SurfaceId::Strokes, SurfaceId::DropShadows], &[
SurfaceId::Fills,
SurfaceId::Strokes,
SurfaceId::DropShadows,
SurfaceId::InnerShadows,
],
|s| { |s| {
s.canvas().concat(&matrix); s.canvas().concat(&matrix);
}, },
@ -378,19 +398,20 @@ impl RenderState {
for stroke in shape.strokes().rev() { for stroke in shape.strokes().rev() {
strokes::render(self, &shape, stroke); strokes::render(self, &shape, stroke);
} }
let scale = self.get_scale();
for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) {
shadows::render_inner_shadow(self, shadow, scale, shape.fills().len() > 0);
}
shadows::render_inner_shadows(self, &shape);
shadows::render_drop_shadows(self, &shape); shadows::render_drop_shadows(self, &shape);
} }
}; };
self.apply_drawing_to_render_canvas(Some(&shape)); self.apply_drawing_to_render_canvas(Some(&shape));
self.surfaces.apply_mut( self.surfaces.apply_mut(
&[SurfaceId::Fills, SurfaceId::Strokes, SurfaceId::DropShadows], &[
SurfaceId::Fills,
SurfaceId::Strokes,
SurfaceId::DropShadows,
SurfaceId::InnerShadows,
],
|s| { |s| {
s.canvas().restore(); s.canvas().restore();
}, },
@ -418,7 +439,12 @@ impl RenderState {
let scale = self.get_scale(); let scale = self.get_scale();
self.reset_canvas(); self.reset_canvas();
self.surfaces.apply_mut( self.surfaces.apply_mut(
&[SurfaceId::Fills, SurfaceId::Strokes, SurfaceId::DropShadows], &[
SurfaceId::Fills,
SurfaceId::Strokes,
SurfaceId::DropShadows,
SurfaceId::InnerShadows,
],
|s| { |s| {
s.canvas().scale((scale, scale)); s.canvas().scale((scale, scale));
}, },

View file

@ -1,10 +1,10 @@
use skia_safe::{self as skia};
use super::{RenderState, SurfaceId}; use super::{RenderState, SurfaceId};
use crate::shapes::{Shadow, Shape, Type}; use crate::shapes::{Shadow, Shape, Type};
use skia_safe::{self as skia, Paint};
// Drop Shadows
pub fn render_drop_shadows(render_state: &mut RenderState, shape: &Shape) { pub fn render_drop_shadows(render_state: &mut RenderState, shape: &Shape) {
if shape.fills().len() > 0 { 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); render_fill_drop_shadow(render_state, &shape, &shadow);
} }
@ -18,27 +18,10 @@ pub fn render_drop_shadows(render_state: &mut RenderState, shape: &Shape) {
fn render_fill_drop_shadow(render_state: &mut RenderState, shape: &Shape, shadow: &Shadow) { fn render_fill_drop_shadow(render_state: &mut RenderState, shape: &Shape, shadow: &Shadow) {
let paint = &shadow.get_drop_shadow_paint(); let paint = &shadow.get_drop_shadow_paint();
render_shadow_paint(render_state, shape, paint, SurfaceId::DropShadows);
match &shape.shape_type {
Type::Rect(_) | Type::Frame(_) => {
render_state
.surfaces
.draw_rect_to(SurfaceId::DropShadows, shape, paint);
}
Type::Circle => {
render_state
.surfaces
.draw_circle_to(SurfaceId::DropShadows, shape, paint);
}
Type::Path(_) | Type::Bool(_) => {
render_state
.surfaces
.draw_path_to(SurfaceId::DropShadows, shape, paint);
}
_ => {}
}
} }
// TODO: Stroke shadows
fn render_stroke_drop_shadow(render_state: &mut RenderState, shadow: &Shadow, scale: f32) { fn render_stroke_drop_shadow(render_state: &mut RenderState, shadow: &Shadow, scale: f32) {
let shadow_paint = &shadow.to_paint(scale); let shadow_paint = &shadow.to_paint(scale);
@ -58,30 +41,63 @@ fn render_stroke_drop_shadow(render_state: &mut RenderState, shadow: &Shadow, sc
.clear(skia::Color::TRANSPARENT); .clear(skia::Color::TRANSPARENT);
} }
pub fn render_inner_shadow( // Inner Shadows
render_state: &mut RenderState, pub fn render_inner_shadows(render_state: &mut RenderState, shape: &Shape) {
shadow: &Shadow, if shape.has_fills() {
scale: f32, for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) {
render_over_fills: bool, render_fill_inner_shadow(render_state, &shape, &shadow);
) { }
let shadow_paint = shadow.to_paint(scale);
if render_over_fills {
render_state
.surfaces
.draw_into(SurfaceId::Fills, SurfaceId::Shadow, Some(&shadow_paint));
} else { } else {
render_state let scale = render_state.get_scale();
.surfaces for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) {
.draw_into(SurfaceId::Strokes, SurfaceId::Shadow, Some(&shadow_paint)); render_stroke_inner_shadow(render_state, &shadow, scale);
}
} }
}
fn render_fill_inner_shadow(render_state: &mut RenderState, shape: &Shape, shadow: &Shadow) {
let paint = &shadow.get_inner_shadow_paint();
render_shadow_paint(render_state, shape, paint, SurfaceId::InnerShadows);
}
// TODO: Stroke shadows
fn render_stroke_inner_shadow(render_state: &mut RenderState, shadow: &Shadow, scale: f32) {
let shadow_paint = &shadow.to_paint(scale);
render_state render_state
.surfaces .surfaces
.draw_into(SurfaceId::Shadow, SurfaceId::Overlay, None); .draw_into(SurfaceId::Strokes, SurfaceId::Shadow, Some(shadow_paint));
render_state.surfaces.draw_into(
SurfaceId::Shadow,
SurfaceId::Overlay,
Some(&skia::Paint::default()),
);
render_state render_state
.surfaces .surfaces
.canvas(SurfaceId::Shadow) .canvas(SurfaceId::Shadow)
.clear(skia::Color::TRANSPARENT); .clear(skia::Color::TRANSPARENT);
} }
fn render_shadow_paint(
render_state: &mut RenderState,
shape: &Shape,
paint: &Paint,
surface_id: SurfaceId,
) {
match &shape.shape_type {
Type::Rect(_) | Type::Frame(_) => {
render_state.surfaces.draw_rect_to(surface_id, shape, paint);
}
Type::Circle => {
render_state
.surfaces
.draw_circle_to(surface_id, shape, paint);
}
Type::Path(_) | Type::Bool(_) => {
render_state.surfaces.draw_path_to(surface_id, shape, paint);
}
_ => {}
}
}

View file

@ -15,6 +15,7 @@ pub enum SurfaceId {
Strokes, Strokes,
Shadow, Shadow,
DropShadows, DropShadows,
InnerShadows,
Overlay, Overlay,
Debug, Debug,
} }
@ -32,6 +33,7 @@ pub struct Surfaces {
shadow: skia::Surface, shadow: skia::Surface,
// used for new shadow rendering // used for new shadow rendering
drop_shadows: skia::Surface, drop_shadows: skia::Surface,
inner_shadows: skia::Surface,
// for drawing the things that are over shadows. // for drawing the things that are over shadows.
overlay: skia::Surface, overlay: skia::Surface,
// for drawing debug info. // for drawing debug info.
@ -63,6 +65,7 @@ impl Surfaces {
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 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 overlay = 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();
@ -78,6 +81,7 @@ impl Surfaces {
current, current,
shadow, shadow,
drop_shadows, drop_shadows,
inner_shadows,
overlay, overlay,
shape_fills, shape_fills,
shape_strokes, shape_strokes,
@ -154,7 +158,12 @@ impl Surfaces {
-render_area.top() + self.margins.height as f32 / viewbox.zoom, -render_area.top() + self.margins.height as f32 / viewbox.zoom,
); );
self.apply_mut( self.apply_mut(
&[SurfaceId::Fills, SurfaceId::Strokes, SurfaceId::DropShadows], &[
SurfaceId::Fills,
SurfaceId::Strokes,
SurfaceId::DropShadows,
SurfaceId::InnerShadows,
],
|s| { |s| {
s.canvas().restore(); s.canvas().restore();
s.canvas().save(); s.canvas().save();
@ -169,6 +178,7 @@ impl Surfaces {
SurfaceId::Current => &mut self.current, SurfaceId::Current => &mut self.current,
SurfaceId::Shadow => &mut self.shadow, SurfaceId::Shadow => &mut self.shadow,
SurfaceId::DropShadows => &mut self.drop_shadows, SurfaceId::DropShadows => &mut self.drop_shadows,
SurfaceId::InnerShadows => &mut self.inner_shadows,
SurfaceId::Overlay => &mut self.overlay, 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,
@ -205,6 +215,7 @@ impl Surfaces {
pub fn reset(&mut self, color: skia::Color) { pub fn reset(&mut self, color: skia::Color) {
self.canvas(SurfaceId::Fills).restore_to_count(1); self.canvas(SurfaceId::Fills).restore_to_count(1);
self.canvas(SurfaceId::DropShadows).restore_to_count(1); self.canvas(SurfaceId::DropShadows).restore_to_count(1);
self.canvas(SurfaceId::InnerShadows).restore_to_count(1);
self.canvas(SurfaceId::Strokes).restore_to_count(1); self.canvas(SurfaceId::Strokes).restore_to_count(1);
self.canvas(SurfaceId::Current).restore_to_count(1); self.canvas(SurfaceId::Current).restore_to_count(1);
self.apply_mut( self.apply_mut(
@ -213,6 +224,7 @@ impl Surfaces {
SurfaceId::Strokes, SurfaceId::Strokes,
SurfaceId::Current, SurfaceId::Current,
SurfaceId::DropShadows, SurfaceId::DropShadows,
SurfaceId::InnerShadows,
SurfaceId::Shadow, SurfaceId::Shadow,
SurfaceId::Overlay, SurfaceId::Overlay,
], ],

View file

@ -749,6 +749,10 @@ impl Shape {
_ => false, _ => false,
} }
} }
pub fn has_fills(&self) -> bool {
!self.fills.is_empty()
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -76,6 +76,8 @@ impl Shadow {
paint 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> { fn drop_shadow_filters(&self, scale: f32) -> Option<ImageFilter> {
let mut filter = image_filters::drop_shadow_only( let mut filter = image_filters::drop_shadow_only(
(self.offset.0 * scale, self.offset.1 * scale), (self.offset.0 * scale, self.offset.1 * scale),
@ -124,7 +126,8 @@ impl Shadow {
filter filter
} }
// New methods for DropShadow // New methods for Drop Shadows
pub fn get_drop_shadow_paint(&self) -> skia::Paint { pub fn get_drop_shadow_paint(&self) -> skia::Paint {
let mut paint = skia::Paint::default(); let mut paint = skia::Paint::default();
@ -152,4 +155,43 @@ impl Shadow {
filter filter
} }
// New methods for Inner Shadows
pub fn get_inner_shadow_paint(&self) -> skia::Paint {
let mut paint = skia::Paint::default();
let image_filter = self.get_inner_shadow_filter();
paint.set_image_filter(image_filter);
paint.set_anti_alias(true);
paint
}
fn get_inner_shadow_filter(&self) -> Option<ImageFilter> {
let sigma = self.blur * 0.5;
let mut filter = skia::image_filters::drop_shadow_only(
(self.offset.0, self.offset.1), // DPR?
(sigma, sigma),
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, self.spread), filter, None);
}
filter = skia::image_filters::blend(skia::BlendMode::SrcIn, None, filter, None);
filter
}
} }