diff --git a/Libraries/LibWeb/Painting/Command.h b/Libraries/LibWeb/Painting/Command.h index e564e99ef86..88f1b3b2c7c 100644 --- a/Libraries/LibWeb/Painting/Command.h +++ b/Libraries/LibWeb/Painting/Command.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -118,7 +119,6 @@ struct StackingContextTransform { struct PushStackingContext { float opacity; - CSS::ResolvedFilter filter; // The bounding box of the source paintable (pre-transform). Gfx::IntRect source_paintable_rect; // A translation to be applied after the stacking context has been transformed. @@ -398,6 +398,11 @@ struct ApplyOpacity { float opacity; }; +struct ApplyFilters { + float opacity; + CSS::ResolvedFilter filter; +}; + struct ApplyTransform { Gfx::FloatPoint origin; Gfx::FloatMatrix4x4 matrix; @@ -453,6 +458,7 @@ using Command = Variant< PaintNestedDisplayList, PaintScrollBar, ApplyOpacity, + ApplyFilters, ApplyTransform, ApplyMaskBitmap>; diff --git a/Libraries/LibWeb/Painting/DisplayList.cpp b/Libraries/LibWeb/Painting/DisplayList.cpp index b7b0f89173d..ec7ad75e93b 100644 --- a/Libraries/LibWeb/Painting/DisplayList.cpp +++ b/Libraries/LibWeb/Painting/DisplayList.cpp @@ -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(); diff --git a/Libraries/LibWeb/Painting/DisplayList.h b/Libraries/LibWeb/Painting/DisplayList.h index 386743ec5b0..4b9c9ca4709 100644 --- a/Libraries/LibWeb/Painting/DisplayList.h +++ b/Libraries/LibWeb/Painting/DisplayList.h @@ -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; diff --git a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp index f1eff706d31..e34cc01bd90 100644 --- a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp +++ b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp @@ -396,33 +396,7 @@ void DisplayListPlayerSkia::push_stacking_context(PushStackingContext const& com .translate(-command.transform.origin); auto matrix = to_skia_matrix(new_transform); - if (!command.filter.is_none()) { - sk_sp 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 const& filter_function : command.filter.filters) - append_filter(to_skia_image_filter(filter_function)); - - // 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); - canvas.saveLayer(nullptr, &paint); - } else if (command.opacity < 1) { + if (command.opacity < 1) { auto source_paintable_rect = to_skia_rect(command.source_paintable_rect); SkRect dest; matrix.mapRect(&dest, source_paintable_rect); @@ -1103,6 +1077,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 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); diff --git a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h index 2a1e2b50203..6e1f408cda7 100644 --- a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h +++ b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h @@ -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; diff --git a/Libraries/LibWeb/Painting/DisplayListRecorder.cpp b/Libraries/LibWeb/Painting/DisplayListRecorder.cpp index 44385334af5..c49fdad2b6c 100644 --- a/Libraries/LibWeb/Painting/DisplayListRecorder.cpp +++ b/Libraries/LibWeb/Painting/DisplayListRecorder.cpp @@ -285,7 +285,6 @@ void DisplayListRecorder::push_stacking_context(PushStackingContextParams params { append(PushStackingContext { .opacity = params.opacity, - .filter = params.filter, .source_paintable_rect = params.source_paintable_rect, .transform = { .origin = params.transform.origin, @@ -398,6 +397,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 { diff --git a/Libraries/LibWeb/Painting/DisplayListRecorder.h b/Libraries/LibWeb/Painting/DisplayListRecorder.h index 0883408220f..59c8ef67c81 100644 --- a/Libraries/LibWeb/Painting/DisplayListRecorder.h +++ b/Libraries/LibWeb/Painting/DisplayListRecorder.h @@ -111,7 +111,6 @@ public: struct PushStackingContextParams { float opacity; - CSS::ResolvedFilter filter; bool is_fixed_position; Gfx::IntRect source_paintable_rect; StackingContextTransform transform; @@ -140,6 +139,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); diff --git a/Libraries/LibWeb/Painting/PaintableBox.cpp b/Libraries/LibWeb/Painting/PaintableBox.cpp index aaff8189b74..c30a6ee9d8e 100644 --- a/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -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()) { diff --git a/Libraries/LibWeb/Painting/SVGSVGPaintable.cpp b/Libraries/LibWeb/Painting/SVGSVGPaintable.cpp index 7d782e4aa0b..9384eb107a6 100644 --- a/Libraries/LibWeb/Painting/SVGSVGPaintable.cpp +++ b/Libraries/LibWeb/Painting/SVGSVGPaintable.cpp @@ -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(); diff --git a/Libraries/LibWeb/Painting/StackingContext.cpp b/Libraries/LibWeb/Painting/StackingContext.cpp index 41d630e35c8..c7155a8be5d 100644 --- a/Libraries/LibWeb/Painting/StackingContext.cpp +++ b/Libraries/LibWeb/Painting/StackingContext.cpp @@ -301,7 +301,6 @@ void StackingContext::paint(PaintContext& context) const DisplayListRecorder::PushStackingContextParams push_stacking_context_params { .opacity = opacity, - .filter = paintable_box().computed_values().filter(), .is_fixed_position = paintable_box().is_fixed_position(), .source_paintable_rect = source_paintable_rect, .transform = {