Skip to content

Commit

Permalink
Add support for inset shadows
Browse files Browse the repository at this point in the history
  • Loading branch information
cfraz89 committed Aug 20, 2024
1 parent b027876 commit eabcc24
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 34 deletions.
7 changes: 7 additions & 0 deletions examples/tailwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ fn app() -> Element {
for _row in 0..3 {
div { class: "flex flex-row",
div { id: "cool", "h123456789asdjkahskj\nhiiiii" }
div { id: "cool-inset", "h123456789asdjkahskj\nhiiiii" }
p { class: "cool", "hi" }
for x in 1..=9 {
div { class: "bg-red-{x}00 border", "{x}" }
Expand All @@ -32,6 +33,12 @@ p.cool { background-color: purple; }
font-size: 32px;
box-shadow: 16px 16px 16px rgba(0,0,0,0.6);
}
#cool-inset {
margin-top: 16px;
background-color: purple;
font-size: 32px;
box-shadow: inset 16px 16px 16px rgba(255,255,255,0.6);
}
.bg-red-100 { background-color: rgb(254 226 226); }
.bg-red-200 { background-color: rgb(254 202 202); }
.bg-red-300 { background-color: rgb(252 165 165); }
Expand Down
112 changes: 78 additions & 34 deletions packages/blitz/src/renderer/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,9 @@ impl<'dom> VelloSceneGenerator<'dom> {
let cx = self.element_cx(element, location);
cx.stroke_effects(scene);
cx.stroke_outline(scene);
cx.draw_box_shadow(scene);
cx.draw_outset_box_shadow(scene);
cx.stroke_frame(scene);
cx.draw_inset_box_shadow(scene);
cx.stroke_border(scene);
cx.stroke_devtools(scene);
cx.draw_image(scene);
Expand Down Expand Up @@ -932,42 +933,85 @@ impl ElementCx<'_> {

// fn draw_image_frame(&self, scene: &mut Scene) {}

fn draw_box_shadow(&self, scene: &mut Scene) {
fn draw_outset_box_shadow(&self, scene: &mut Scene) {
let box_shadow = &self.style.get_effects().box_shadow.0;
for shadow in box_shadow.iter() {
//TODO implement inset shadow
if !shadow.inset {
let shadow_color = shadow.base.color.as_vello();
if shadow_color != Color::TRANSPARENT {
let transform = self.transform.then_translate(Vec2 {
x: shadow.base.horizontal.px() as f64,
y: shadow.base.vertical.px() as f64,
});

//TODO draw shadows with matching individual radii instead of averaging
let radius = (self.frame.border_top_left_radius_height
+ self.frame.border_bottom_left_radius_width
+ self.frame.border_bottom_left_radius_height
+ self.frame.border_bottom_left_radius_width
+ self.frame.border_bottom_right_radius_height
+ self.frame.border_bottom_right_radius_width
+ self.frame.border_top_right_radius_height
+ self.frame.border_top_right_radius_width)
/ 8.0;

// Fill the color
scene.draw_blurred_rounded_rect(
transform,
self.frame.outer_rect,
shadow_color,
radius,
shadow.base.blur.px() as f64,
);
}
} else {
println!("TODO: support drawing inset box-shadow")
for shadow in box_shadow.iter().filter(|s| !s.inset) {
let shadow_color = shadow.base.color.as_vello();
if shadow_color != Color::TRANSPARENT {
let transform = self.transform.then_translate(Vec2 {
x: shadow.base.horizontal.px() as f64,
y: shadow.base.vertical.px() as f64,
});

//TODO draw shadows with matching individual radii instead of averaging
let radius = (self.frame.border_top_left_radius_height
+ self.frame.border_bottom_left_radius_width
+ self.frame.border_bottom_left_radius_height
+ self.frame.border_bottom_left_radius_width
+ self.frame.border_bottom_right_radius_height
+ self.frame.border_bottom_right_radius_width
+ self.frame.border_top_right_radius_height
+ self.frame.border_top_right_radius_width)
/ 8.0;

// Fill the color
scene.draw_blurred_rounded_rect(
transform,
self.frame.outer_rect,
shadow_color,
radius,
shadow.base.blur.px() as f64,
);
}
}
}

fn draw_inset_box_shadow(&self, scene: &mut Scene) {
let box_shadow = &self.style.get_effects().box_shadow.0;
let has_inset_shadow = box_shadow.iter().any(|s| s.inset);
if has_inset_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.frame());
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 {
let transform = self.transform.then_translate(Vec2 {
x: shadow.base.horizontal.px() as f64,
y: shadow.base.vertical.px() as f64,
});

//TODO draw shadows with matching individual radii instead of averaging
let radius = (self.frame.border_top_left_radius_height
+ self.frame.border_bottom_left_radius_width
+ self.frame.border_bottom_left_radius_height
+ self.frame.border_bottom_left_radius_width
+ self.frame.border_bottom_right_radius_height
+ self.frame.border_bottom_right_radius_width
+ self.frame.border_top_right_radius_height
+ self.frame.border_top_right_radius_width)
/ 8.0;

// Fill the color
scene.draw_blurred_rounded_rect(
transform,
self.frame.outer_rect,
shadow_color,
radius,
shadow.base.blur.px() as f64,
);
}
}
if has_inset_shadow {
scene.pop_layer();
CLIP_DEPTH.fetch_sub(1, atomic::Ordering::SeqCst);
}
}

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

0 comments on commit eabcc24

Please sign in to comment.