Skip to content

Commit

Permalink
Don't render box shadows underneath the element with the shadow
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoburns committed Sep 5, 2024
1 parent 2082a73 commit b7c50e9
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 0 deletions.
45 changes: 45 additions & 0 deletions packages/blitz/src/renderer/multicolor_rounded_rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,38 @@ impl ElementFrame {
}
}

/// Construct a bezpath drawing the frame
pub fn shadow_clip(&self) -> BezPath {
let mut path = BezPath::new();
self.shadow_clip_shape(&mut path);
path
}

fn shadow_clip_shape(&self, path: &mut BezPath) {
use Corner::*;

for corner in [TopLeft, TopRight, BottomRight, BottomLeft] {
path.insert_point(self.shadow_clip_corner(corner, 100.0));
}

if self.is_sharp(TopLeft) {
path.move_to(self.corner(TopLeft, ArcSide::Outer));
} else {
const TOLERANCE: f64 = 0.1;
let arc = self.full_arc(TopLeft, ArcSide::Outer, Direction::Anticlockwise);
let elements = arc.path_elements(TOLERANCE);
path.extend(elements);
}

for corner in [/*TopLeft, */ BottomLeft, BottomRight, TopRight] {
if self.is_sharp(corner) {
path.insert_point(self.corner(corner, ArcSide::Outer));
} else {
path.insert_arc(self.full_arc(corner, ArcSide::Outer, Direction::Anticlockwise));
}
}
}

fn corner(&self, corner: Corner, side: ArcSide) -> Point {
let Rect { x0, y0, x1, y1 } = self.outer_rect;

Expand Down Expand Up @@ -241,6 +273,19 @@ impl ElementFrame {
Point { x, y }
}

fn shadow_clip_corner(&self, corner: Corner, offset: f64) -> Point {
let Rect { x0, y0, x1, y1 } = self.outer_rect;

let (x, y) = match corner {
Corner::TopLeft => (x0 - offset, y0 - offset),
Corner::TopRight => (x1 + offset, y0 - offset),
Corner::BottomRight => (x1 + offset, y1 + offset),
Corner::BottomLeft => (x0 - offset, y1 + offset),
};

Point { x, y }
}

/// Check if the corner width is smaller than the radius.
/// If it is, we need to fill in the gap with an arc
fn corner_needs_infill(&self, corner: Corner) -> bool {
Expand Down
19 changes: 19 additions & 0 deletions packages/blitz/src/renderer/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,20 @@ impl ElementCx<'_> {

fn draw_outset_box_shadow(&self, scene: &mut Scene) {
let box_shadow = &self.style.get_effects().box_shadow.0;

// TODO: Only apply clip if element has transparency
let has_outset_shadow = box_shadow.iter().any(|s| !s.inset);
if has_outset_shadow {
CLIPS_WANTED.fetch_add(1, atomic::Ordering::SeqCst);
let clips_available = CLIPS_USED.load(atomic::Ordering::SeqCst) <= CLIP_LIMIT;
if clips_available {
scene.push_layer(Mix::Clip, 1.0, self.transform, &self.frame.shadow_clip());
CLIPS_USED.fetch_add(1, atomic::Ordering::SeqCst);
let depth = CLIP_DEPTH.fetch_add(1, atomic::Ordering::SeqCst) + 1;
CLIP_DEPTH_USED.fetch_max(depth, atomic::Ordering::SeqCst);
}
}

for shadow in box_shadow.iter().filter(|s| !s.inset) {
let shadow_color = shadow.base.color.as_vello();
if shadow_color != Color::TRANSPARENT {
Expand Down Expand Up @@ -964,6 +978,11 @@ impl ElementCx<'_> {
);
}
}

if has_outset_shadow {
scene.pop_layer();
CLIP_DEPTH.fetch_sub(1, atomic::Ordering::SeqCst);
}
}

fn draw_inset_box_shadow(&self, scene: &mut Scene) {
Expand Down

0 comments on commit b7c50e9

Please sign in to comment.