mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 09:37:34 +00:00
LibWeb: Add support for inset shadows
Also move code for outer shadows to a helper.
This commit is contained in:
parent
df79a2720b
commit
af1798dd04
4 changed files with 380 additions and 299 deletions
|
@ -69,7 +69,17 @@ void InlinePaintable::paint(PaintContext& context, PaintPhase phase) const
|
||||||
layer.spread_distance.to_px(layout_node()),
|
layer.spread_distance.to_px(layout_node()),
|
||||||
layer.placement == CSS::ShadowPlacement::Outer ? ShadowPlacement::Outer : ShadowPlacement::Inner);
|
layer.placement == CSS::ShadowPlacement::Outer ? ShadowPlacement::Outer : ShadowPlacement::Inner);
|
||||||
}
|
}
|
||||||
paint_box_shadow(context, absolute_fragment_rect, border_radii_data, resolved_box_shadow_data);
|
auto borders_data = BordersData {
|
||||||
|
.top = computed_values().border_top(),
|
||||||
|
.right = computed_values().border_right(),
|
||||||
|
.bottom = computed_values().border_bottom(),
|
||||||
|
.left = computed_values().border_left(),
|
||||||
|
};
|
||||||
|
auto absolute_fragment_rect_bordered = absolute_fragment_rect.inflated(
|
||||||
|
borders_data.top.width, borders_data.right.width,
|
||||||
|
borders_data.bottom.width, borders_data.left.width);
|
||||||
|
paint_box_shadow(context, absolute_fragment_rect_bordered, absolute_fragment_rect,
|
||||||
|
borders_data, border_radii_data, resolved_box_shadow_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
|
|
|
@ -296,7 +296,14 @@ void PaintableBox::paint_box_shadow(PaintContext& context) const
|
||||||
auto resolved_box_shadow_data = resolve_box_shadow_data();
|
auto resolved_box_shadow_data = resolve_box_shadow_data();
|
||||||
if (resolved_box_shadow_data.is_empty())
|
if (resolved_box_shadow_data.is_empty())
|
||||||
return;
|
return;
|
||||||
Painting::paint_box_shadow(context, absolute_border_box_rect(), normalized_border_radii_data(), resolved_box_shadow_data);
|
auto borders_data = BordersData {
|
||||||
|
.top = computed_values().border_top(),
|
||||||
|
.right = computed_values().border_right(),
|
||||||
|
.bottom = computed_values().border_bottom(),
|
||||||
|
.left = computed_values().border_left(),
|
||||||
|
};
|
||||||
|
Painting::paint_box_shadow(context, absolute_border_box_rect(), absolute_padding_box_rect(),
|
||||||
|
borders_data, normalized_border_radii_data(), resolved_box_shadow_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
BorderRadiiData PaintableBox::normalized_border_radii_data(ShrinkRadiiForBorders shrink) const
|
BorderRadiiData PaintableBox::normalized_border_radii_data(ShrinkRadiiForBorders shrink) const
|
||||||
|
|
|
@ -19,11 +19,57 @@
|
||||||
|
|
||||||
namespace Web::Painting {
|
namespace Web::Painting {
|
||||||
|
|
||||||
void paint_box_shadow(PaintContext& context, CSSPixelRect const& content_rect, BorderRadiiData const& border_radii, Vector<ShadowData> const& box_shadow_layers)
|
static void paint_inner_box_shadow(PaintContext& context, CSSPixelRect const& content_rect,
|
||||||
|
BordersData const& borders_data, BorderRadiiData const& border_radii, ShadowData const& box_shadow_data)
|
||||||
{
|
{
|
||||||
if (box_shadow_layers.is_empty())
|
auto& painter = context.painter();
|
||||||
return;
|
auto device_content_rect = context.rounded_device_rect(content_rect);
|
||||||
|
|
||||||
|
auto border_radii_shrunken = border_radii;
|
||||||
|
border_radii_shrunken.shrink(borders_data.top.width, borders_data.right.width, borders_data.bottom.width, borders_data.left.width);
|
||||||
|
ScopedCornerRadiusClip corner_clipper { context, painter, device_content_rect, border_radii_shrunken, CornerClip::Outside };
|
||||||
|
DevicePixels offset_x = context.rounded_device_pixels(box_shadow_data.offset_x);
|
||||||
|
DevicePixels offset_y = context.rounded_device_pixels(box_shadow_data.offset_y);
|
||||||
|
DevicePixels blur_radius = context.rounded_device_pixels(box_shadow_data.blur_radius);
|
||||||
|
DevicePixels spread_distance = context.rounded_device_pixels(box_shadow_data.spread_distance);
|
||||||
|
auto spread_distance_value = spread_distance.value();
|
||||||
|
auto shadows_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, device_content_rect.size().to_type<int>());
|
||||||
|
if (shadows_bitmap.is_error()) {
|
||||||
|
dbgln("Unable to allocate temporary bitmap {} for box-shadow rendering: {}", device_content_rect, shadows_bitmap.error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto shadow_bitmap = shadows_bitmap.release_value();
|
||||||
|
Gfx::Painter shadow_painter { *shadow_bitmap };
|
||||||
|
Gfx::AntiAliasingPainter shadow_aa_painter { shadow_painter };
|
||||||
|
auto device_content_rect_int = device_content_rect.to_type<int>();
|
||||||
|
auto outer_shadow_rect = device_content_rect_int.translated(-device_content_rect_int.x(), -device_content_rect_int.y());
|
||||||
|
auto inner_shadow_rect = outer_shadow_rect.translated({ offset_x, offset_y });
|
||||||
|
inner_shadow_rect.inflate(-spread_distance_value, -spread_distance_value, -spread_distance_value, -spread_distance_value);
|
||||||
|
outer_shadow_rect = outer_shadow_rect.translated(-blur_radius.value(), -blur_radius.value());
|
||||||
|
outer_shadow_rect.set_size(outer_shadow_rect.width() + blur_radius.value(), outer_shadow_rect.height() + blur_radius.value());
|
||||||
|
auto top_left_corner = border_radii_shrunken.top_left.as_corner(context);
|
||||||
|
auto top_right_corner = border_radii_shrunken.top_right.as_corner(context);
|
||||||
|
auto bottom_right_corner = border_radii_shrunken.bottom_right.as_corner(context);
|
||||||
|
auto bottom_left_corner = border_radii_shrunken.bottom_left.as_corner(context);
|
||||||
|
shadow_painter.fill_rect(outer_shadow_rect, box_shadow_data.color.with_alpha(0xff));
|
||||||
|
if (border_radii_shrunken.has_any_radius()) {
|
||||||
|
shadow_aa_painter.fill_rect_with_rounded_corners(inner_shadow_rect, box_shadow_data.color.with_alpha(0xff),
|
||||||
|
top_left_corner, top_right_corner, bottom_right_corner, bottom_left_corner,
|
||||||
|
Gfx::AntiAliasingPainter::BlendMode::AlphaSubtract);
|
||||||
|
} else {
|
||||||
|
shadow_painter.clear_rect(inner_shadow_rect, Color::Transparent);
|
||||||
|
}
|
||||||
|
Gfx::StackBlurFilter filter(*shadow_bitmap);
|
||||||
|
filter.process_rgba(blur_radius.value(), box_shadow_data.color);
|
||||||
|
Gfx::PainterStateSaver save { painter };
|
||||||
|
painter.add_clip_rect(device_content_rect_int);
|
||||||
|
painter.blit({ device_content_rect_int.left(), device_content_rect_int.top() },
|
||||||
|
*shadow_bitmap, shadow_bitmap->rect(), box_shadow_data.color.alpha() / 255.);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void paint_outer_box_shadow(PaintContext& context, CSSPixelRect const& content_rect,
|
||||||
|
BorderRadiiData const& border_radii, ShadowData const& box_shadow_data)
|
||||||
|
{
|
||||||
auto& painter = context.painter();
|
auto& painter = context.painter();
|
||||||
auto device_content_rect = context.rounded_device_rect(content_rect);
|
auto device_content_rect = context.rounded_device_rect(content_rect);
|
||||||
|
|
||||||
|
@ -34,12 +80,6 @@ void paint_box_shadow(PaintContext& context, CSSPixelRect const& content_rect, B
|
||||||
|
|
||||||
ScopedCornerRadiusClip corner_clipper { context, painter, device_content_rect, border_radii, CornerClip::Inside };
|
ScopedCornerRadiusClip corner_clipper { context, painter, device_content_rect, border_radii, CornerClip::Inside };
|
||||||
|
|
||||||
// Note: Box-shadow layers are ordered front-to-back, so we paint them in reverse
|
|
||||||
for (auto& box_shadow_data : box_shadow_layers.in_reverse()) {
|
|
||||||
// FIXME: Paint inset shadows.
|
|
||||||
if (box_shadow_data.placement != ShadowPlacement::Outer)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
DevicePixels offset_x = context.rounded_device_pixels(box_shadow_data.offset_x);
|
DevicePixels offset_x = context.rounded_device_pixels(box_shadow_data.offset_x);
|
||||||
DevicePixels offset_y = context.rounded_device_pixels(box_shadow_data.offset_y);
|
DevicePixels offset_y = context.rounded_device_pixels(box_shadow_data.offset_y);
|
||||||
DevicePixels blur_radius = context.rounded_device_pixels(box_shadow_data.blur_radius);
|
DevicePixels blur_radius = context.rounded_device_pixels(box_shadow_data.blur_radius);
|
||||||
|
@ -60,7 +100,7 @@ void paint_box_shadow(PaintContext& context, CSSPixelRect const& content_rect, B
|
||||||
auto non_blurred_shadow_rect = device_content_rect.inflated(spread_distance, spread_distance, spread_distance, spread_distance);
|
auto non_blurred_shadow_rect = device_content_rect.inflated(spread_distance, spread_distance, spread_distance, spread_distance);
|
||||||
if (blur_radius == 0 && !border_radii.has_any_radius()) {
|
if (blur_radius == 0 && !border_radii.has_any_radius()) {
|
||||||
fill_rect_masked(painter, non_blurred_shadow_rect.translated(offset_x, offset_y), device_content_rect, box_shadow_data.color);
|
fill_rect_masked(painter, non_blurred_shadow_rect.translated(offset_x, offset_y), device_content_rect, box_shadow_data.color);
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto top_left_shadow_corner = top_left_corner;
|
auto top_left_shadow_corner = top_left_corner;
|
||||||
|
@ -174,7 +214,9 @@ void paint_box_shadow(PaintContext& context, CSSPixelRect const& content_rect, B
|
||||||
Gfx::Painter corner_painter { *shadow_bitmap };
|
Gfx::Painter corner_painter { *shadow_bitmap };
|
||||||
Gfx::AntiAliasingPainter aa_corner_painter { corner_painter };
|
Gfx::AntiAliasingPainter aa_corner_painter { corner_painter };
|
||||||
|
|
||||||
aa_corner_painter.fill_rect_with_rounded_corners(shadow_bitmap_rect.shrunken(double_radius, double_radius, double_radius, double_radius).to_type<int>(), box_shadow_data.color, top_left_shadow_corner, top_right_shadow_corner, bottom_right_shadow_corner, bottom_left_shadow_corner);
|
aa_corner_painter.fill_rect_with_rounded_corners(
|
||||||
|
shadow_bitmap_rect.shrunken(double_radius, double_radius, double_radius, double_radius).to_type<int>(),
|
||||||
|
box_shadow_data.color, top_left_shadow_corner, top_right_shadow_corner, bottom_right_shadow_corner, bottom_left_shadow_corner);
|
||||||
Gfx::StackBlurFilter filter(*shadow_bitmap);
|
Gfx::StackBlurFilter filter(*shadow_bitmap);
|
||||||
filter.process_rgba(blur_radius.value(), box_shadow_data.color);
|
filter.process_rgba(blur_radius.value(), box_shadow_data.color);
|
||||||
|
|
||||||
|
@ -331,6 +373,22 @@ void paint_box_shadow(PaintContext& context, CSSPixelRect const& content_rect, B
|
||||||
paint_shadow(bottom_left);
|
paint_shadow(bottom_left);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void paint_box_shadow(PaintContext& context,
|
||||||
|
CSSPixelRect const& bordered_content_rect,
|
||||||
|
CSSPixelRect const& borderless_content_rect,
|
||||||
|
BordersData const& borders_data,
|
||||||
|
BorderRadiiData const& border_radii,
|
||||||
|
Vector<ShadowData> const& box_shadow_layers)
|
||||||
|
{
|
||||||
|
// Note: Box-shadow layers are ordered front-to-back, so we paint them in reverse
|
||||||
|
for (auto& box_shadow_data : box_shadow_layers.in_reverse()) {
|
||||||
|
if (box_shadow_data.placement == ShadowPlacement::Inner) {
|
||||||
|
paint_inner_box_shadow(context, borderless_content_rect, borders_data, border_radii, box_shadow_data);
|
||||||
|
} else {
|
||||||
|
paint_outer_box_shadow(context, bordered_content_rect, border_radii, box_shadow_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void paint_text_shadow(PaintContext& context, Layout::LineBoxFragment const& fragment, Vector<ShadowData> const& shadow_layers)
|
void paint_text_shadow(PaintContext& context, Layout::LineBoxFragment const& fragment, Vector<ShadowData> const& shadow_layers)
|
||||||
|
|
|
@ -26,7 +26,13 @@ struct ShadowData {
|
||||||
ShadowPlacement placement;
|
ShadowPlacement placement;
|
||||||
};
|
};
|
||||||
|
|
||||||
void paint_box_shadow(PaintContext&, CSSPixelRect const&, BorderRadiiData const&, Vector<ShadowData> const&);
|
void paint_box_shadow(
|
||||||
|
PaintContext&,
|
||||||
|
CSSPixelRect const& bordered_content_rect,
|
||||||
|
CSSPixelRect const& borderless_content_rect,
|
||||||
|
BordersData const& borders_data,
|
||||||
|
BorderRadiiData const&,
|
||||||
|
Vector<ShadowData> const&);
|
||||||
void paint_text_shadow(PaintContext&, Layout::LineBoxFragment const&, Vector<ShadowData> const&);
|
void paint_text_shadow(PaintContext&, Layout::LineBoxFragment const&, Vector<ShadowData> const&);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue