LibWeb: Add ApplyFilters command for both CSS and SVGs

Fixes #2015
This commit is contained in:
Saksham Mittal 2024-11-21 13:12:37 +05:30
parent d6bcd3fb0b
commit 260017133f
No known key found for this signature in database
9 changed files with 57 additions and 0 deletions

View file

@ -27,6 +27,7 @@
#include <LibGfx/Size.h>
#include <LibGfx/TextAlignment.h>
#include <LibGfx/TextLayout.h>
#include <LibWeb/CSS/ComputedValues.h>
#include <LibWeb/CSS/Enums.h>
#include <LibWeb/Painting/BorderRadiiData.h>
#include <LibWeb/Painting/BorderRadiusCornerClipper.h>
@ -398,6 +399,11 @@ struct ApplyOpacity {
float opacity;
};
struct ApplyFilters {
float opacity;
CSS::ResolvedFilter filter;
};
struct ApplyTransform {
Gfx::FloatPoint origin;
Gfx::FloatMatrix4x4 matrix;
@ -453,6 +459,7 @@ using Command = Variant<
PaintNestedDisplayList,
PaintScrollBar,
ApplyOpacity,
ApplyFilters,
ApplyTransform,
ApplyMaskBitmap>;

View file

@ -122,6 +122,7 @@ void DisplayListPlayer::execute(DisplayList& display_list)
else HANDLE_COMMAND(PaintScrollBar, paint_scrollbar)
else HANDLE_COMMAND(PaintNestedDisplayList, paint_nested_display_list)
else HANDLE_COMMAND(ApplyOpacity, apply_opacity)
else HANDLE_COMMAND(ApplyFilters, apply_filters)
else HANDLE_COMMAND(ApplyTransform, apply_transform)
else HANDLE_COMMAND(ApplyMaskBitmap, apply_mask_bitmap)
else VERIFY_NOT_REACHED();

View file

@ -76,6 +76,7 @@ private:
virtual void paint_nested_display_list(PaintNestedDisplayList const&) = 0;
virtual void paint_scrollbar(PaintScrollBar const&) = 0;
virtual void apply_opacity(ApplyOpacity const&) = 0;
virtual void apply_filters(ApplyFilters const&) = 0;
virtual void apply_transform(ApplyTransform const&) = 0;
virtual void apply_mask_bitmap(ApplyMaskBitmap const&) = 0;
virtual bool would_be_fully_clipped_by_painter(Gfx::IntRect) const = 0;

View file

@ -1103,6 +1103,41 @@ void DisplayListPlayerSkia::apply_opacity(ApplyOpacity const& command)
canvas.saveLayer(nullptr, &paint);
}
void DisplayListPlayerSkia::apply_filters(ApplyFilters const& command)
{
if (command.filter.is_none()) {
return;
}
sk_sp<SkImageFilter> image_filter;
auto append_filter = [&image_filter](auto new_filter) {
if (image_filter)
image_filter = SkImageFilters::Compose(new_filter, image_filter);
else
image_filter = new_filter;
};
// Apply filters in order
for (auto filter : command.filter.filters) {
append_filter(to_skia_image_filter(filter));
}
// We apply opacity as a color filter here so we only need to save and restore a single layer.
if (command.opacity < 1) {
append_filter(to_skia_image_filter(CSS::ResolvedFilter::FilterFunction {
CSS::ResolvedFilter::Color {
CSS::FilterOperation::Color::Type::Opacity,
command.opacity,
},
}));
}
SkPaint paint;
paint.setImageFilter(image_filter);
auto& canvas = surface().canvas();
canvas.saveLayer(nullptr, &paint);
return;
}
void DisplayListPlayerSkia::apply_transform(ApplyTransform const& command)
{
auto affine_transform = Gfx::extract_2d_affine_transform(command.matrix);

View file

@ -63,6 +63,7 @@ private:
void paint_scrollbar(PaintScrollBar const&) override;
void paint_nested_display_list(PaintNestedDisplayList const&) override;
void apply_opacity(ApplyOpacity const&) override;
void apply_filters(ApplyFilters const&) override;
void apply_transform(ApplyTransform const&) override;
void apply_mask_bitmap(ApplyMaskBitmap const&) override;

View file

@ -398,6 +398,11 @@ void DisplayListRecorder::apply_opacity(float opacity)
append(ApplyOpacity { .opacity = opacity });
}
void DisplayListRecorder::apply_filters(float opacity, CSS::ResolvedFilter filter)
{
append(ApplyFilters { .opacity = opacity, .filter = filter });
}
void DisplayListRecorder::apply_transform(Gfx::FloatPoint origin, Gfx::FloatMatrix4x4 matrix)
{
append(ApplyTransform {

View file

@ -140,6 +140,7 @@ public:
void paint_scrollbar(int scroll_frame_id, Gfx::IntRect, CSSPixelFraction scroll_size, bool vertical);
void apply_opacity(float opacity);
void apply_filters(float opacity, CSS::ResolvedFilter filter);
void apply_transform(Gfx::FloatPoint origin, Gfx::FloatMatrix4x4);
void apply_mask_bitmap(Gfx::IntPoint origin, Gfx::ImmutableBitmap const&, Gfx::Bitmap::MaskKind);

View file

@ -382,6 +382,10 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
}
}
if (phase == PaintPhase::Foreground) {
context.display_list_recorder().apply_filters(this->computed_values().opacity(), this->computed_values().filter());
}
auto scrollbar_width = computed_values().scrollbar_width();
if (phase == PaintPhase::Overlay && scrollbar_width != CSS::ScrollbarWidth::None) {
if (auto scrollbar_data = compute_scrollbar_data(ScrollDirection::Vertical); scrollbar_data.has_value()) {

View file

@ -70,6 +70,8 @@ void SVGSVGPaintable::paint_descendants(PaintContext& context, PaintableBox cons
context.display_list_recorder().apply_opacity(computed_values.opacity());
}
context.display_list_recorder().apply_filters(paintable.computed_values().opacity(), paintable.computed_values().filter());
if (svg_box.has_css_transform()) {
auto transform_matrix = svg_box.transform();
Gfx::FloatPoint transform_origin = svg_box.transform_origin().template to_type<float>();