mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-05-28 05:52:53 +00:00
We also pass whether the shadow goes inside or outside the element. Only outer shadows are rendered currently, and inner ones may want to be handled separately from them, as they will never interfere with each other.
65 lines
2.7 KiB
C++
65 lines
2.7 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
* Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibGfx/DisjointRectSet.h>
|
|
#include <LibGfx/Filters/FastBoxBlurFilter.h>
|
|
#include <LibGfx/Painter.h>
|
|
#include <LibWeb/Painting/PaintContext.h>
|
|
#include <LibWeb/Painting/ShadowPainting.h>
|
|
|
|
namespace Web::Painting {
|
|
|
|
void paint_box_shadow(PaintContext& context, Gfx::IntRect const& content_rect, Vector<BoxShadowData> const& box_shadow_layers)
|
|
{
|
|
if (box_shadow_layers.is_empty())
|
|
return;
|
|
|
|
// Note: Box-shadow layers are ordered front-to-back, so we paint them in reverse
|
|
for (int layer_index = box_shadow_layers.size() - 1; layer_index >= 0; layer_index--) {
|
|
auto& box_shadow_data = box_shadow_layers[layer_index];
|
|
// FIXME: Paint inset shadows.
|
|
if (box_shadow_data.placement != BoxShadowPlacement::Outer)
|
|
continue;
|
|
|
|
Gfx::IntRect bitmap_rect = {
|
|
0,
|
|
0,
|
|
content_rect.width() + (2 * box_shadow_data.spread_distance) + (4 * box_shadow_data.blur_radius),
|
|
content_rect.height() + (2 * box_shadow_data.spread_distance) + (4 * box_shadow_data.blur_radius)
|
|
};
|
|
|
|
Gfx::IntPoint blur_rect_position = {
|
|
content_rect.x() - box_shadow_data.spread_distance - (2 * box_shadow_data.blur_radius) + box_shadow_data.offset_x,
|
|
content_rect.y() - box_shadow_data.spread_distance - (2 * box_shadow_data.blur_radius) + box_shadow_data.offset_y
|
|
};
|
|
|
|
if (bitmap_rect.is_empty())
|
|
return;
|
|
|
|
auto bitmap_or_error = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, bitmap_rect.size());
|
|
if (bitmap_or_error.is_error()) {
|
|
dbgln("Unable to allocate temporary bitmap for box-shadow rendering: {}", bitmap_or_error.error());
|
|
return;
|
|
}
|
|
auto new_bitmap = bitmap_or_error.release_value_but_fixme_should_propagate_errors();
|
|
|
|
Gfx::Painter painter(*new_bitmap);
|
|
painter.fill_rect({ { 2 * box_shadow_data.blur_radius, 2 * box_shadow_data.blur_radius }, { content_rect.width() + (2 * box_shadow_data.spread_distance), content_rect.height() + (2 * box_shadow_data.spread_distance) } }, box_shadow_data.color);
|
|
|
|
Gfx::FastBoxBlurFilter filter(*new_bitmap);
|
|
filter.apply_three_passes(box_shadow_data.blur_radius);
|
|
|
|
Gfx::DisjointRectSet rect_set;
|
|
rect_set.add(bitmap_rect);
|
|
auto shattered = rect_set.shatter({ content_rect.location() - blur_rect_position, content_rect.size() });
|
|
|
|
for (auto& rect : shattered.rects())
|
|
context.painter().blit(rect.location() + blur_rect_position, *new_bitmap, rect);
|
|
}
|
|
}
|
|
|
|
}
|