diff --git a/Libraries/LibWeb/Painting/Command.h b/Libraries/LibWeb/Painting/Command.h index 47c643e052c..cb395bbd922 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. @@ -408,6 +408,11 @@ struct ApplyOpacity { float opacity; }; +struct ApplyFilters { + float opacity; + CSS::ResolvedFilter filter; +}; + struct ApplyTransform { Gfx::FloatPoint origin; Gfx::FloatMatrix4x4 matrix; @@ -463,6 +468,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 b72a2b3b9d9..d3ea84fe993 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); @@ -1105,6 +1079,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 2b1584cee64..3d3f6b479d1 100644 --- a/Libraries/LibWeb/Painting/DisplayListRecorder.cpp +++ b/Libraries/LibWeb/Painting/DisplayListRecorder.cpp @@ -295,7 +295,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, @@ -408,6 +407,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 581622c1cc0..300d2be7e07 100644 --- a/Libraries/LibWeb/Painting/DisplayListRecorder.h +++ b/Libraries/LibWeb/Painting/DisplayListRecorder.h @@ -121,7 +121,6 @@ public: struct PushStackingContextParams { float opacity; - CSS::ResolvedFilter filter; bool is_fixed_position; Gfx::IntRect source_paintable_rect; StackingContextTransform transform; @@ -150,6 +149,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/StackingContext.cpp b/Libraries/LibWeb/Painting/StackingContext.cpp index 41d630e35c8..6938e848826 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 = { @@ -328,6 +327,7 @@ void StackingContext::paint(PaintContext& context) const context.display_list_recorder().push_scroll_frame_id(*paintable_box().scroll_frame_id()); } context.display_list_recorder().push_stacking_context(push_stacking_context_params); + context.display_list_recorder().apply_filters(opacity, paintable_box().computed_values().filter()); if (auto mask_image = computed_values.mask_image()) { auto mask_display_list = DisplayList::create();