Browse Source

LibWeb: Fix "background-clip: text" for elements nested in scrollable

Instead of carrying the display list for a mask in each command that
might potentially be affected by "background-clip: text", this change
introduces a new AddMask command that is applied once for all
background layers within one box.

The new AddMask command includes a rectangle for the mask destination
that is translated by the corresponding scroll offset.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/857
Aliaksandr Kalenik 11 tháng trước cách đây
mục cha
commit
a8f4ea5226

+ 30 - 0
Tests/LibWeb/Ref/background-clip-text-inside-scrollable.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<link rel="match" href="reference/background-clip-text-inside-scrollable-ref.html" />
+<style>
+    * {
+        scrollbar-width: none;
+    }
+
+    #text {
+        background: linear-gradient(#6d98cc, #8a64e5);
+        background-clip: text;
+        color: transparent;
+        font-size: 50px;
+    }
+
+    #scrollable {
+        width: 300px;
+        height: 300px;
+        border: 1px solid black;
+        overflow: scroll;
+    }
+</style>
+<div id="scrollable">
+    <div style="height: 200px"></div>
+    Clip<span id="text">Text</span>
+    <div style="height: 600px"></div>
+</div>
+<script>
+    const scrollContainer = document.getElementById("scrollable");
+    scrollContainer.scrollTop = 200;
+</script>

+ 23 - 0
Tests/LibWeb/Ref/reference/background-clip-text-inside-scrollable-ref.html

@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<style>
+    * {
+        scrollbar-width: none;
+    }
+
+    #text {
+        background: linear-gradient(#6d98cc, #8a64e5);
+        background-clip: text;
+        color: transparent;
+        font-size: 50px;
+    }
+
+    #scrollable {
+        width: 300px;
+        height: 300px;
+        border: 1px solid black;
+        overflow: scroll;
+    }
+</style>
+<div id="scrollable">
+    Clip<span id="text">Text</span>
+</div>

+ 1 - 1
Userland/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h

@@ -36,7 +36,7 @@ public:
     virtual void resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelSize) const {};
 
     virtual bool is_paintable() const = 0;
-    virtual void paint(PaintContext& context, DevicePixelRect const& dest_rect, ImageRendering, RefPtr<Painting::DisplayList> text_clip = {}) const = 0;
+    virtual void paint(PaintContext& context, DevicePixelRect const& dest_rect, ImageRendering) const = 0;
 
     virtual Optional<Gfx::Color> color_if_single_pixel_bitmap() const { return {}; }
 };

+ 2 - 2
Userland/Libraries/LibWeb/CSS/StyleValues/ConicGradientStyleValue.cpp

@@ -42,12 +42,12 @@ void ConicGradientStyleValue::resolve_for_size(Layout::NodeWithStyleAndBoxModelM
     m_resolved->position = m_properties.position->resolved(node, CSSPixelRect { { 0, 0 }, size });
 }
 
-void ConicGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr<Painting::DisplayList> text_clip) const
+void ConicGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering) const
 {
     VERIFY(m_resolved.has_value());
     auto destination_rect = dest_rect.to_type<int>();
     auto position = context.rounded_device_point(m_resolved->position).to_type<int>();
-    context.display_list_recorder().fill_rect_with_conic_gradient(destination_rect, m_resolved->data, position, text_clip);
+    context.display_list_recorder().fill_rect_with_conic_gradient(destination_rect, m_resolved->data, position);
 }
 
 bool ConicGradientStyleValue::equals(StyleValue const& other) const

+ 1 - 1
Userland/Libraries/LibWeb/CSS/StyleValues/ConicGradientStyleValue.h

@@ -25,7 +25,7 @@ public:
 
     virtual String to_string() const override;
 
-    void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr<Painting::DisplayList> text_clip = {}) const override;
+    void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering) const override;
 
     virtual bool equals(StyleValue const& other) const override;
 

+ 2 - 2
Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp

@@ -137,11 +137,11 @@ Optional<CSSPixelFraction> ImageStyleValue::natural_aspect_ratio() const
     return {};
 }
 
-void ImageStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, RefPtr<Painting::DisplayList> text_clip) const
+void ImageStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const
 {
     if (auto const* b = bitmap(m_current_frame_index, dest_rect.size().to_type<int>()); b != nullptr) {
         auto scaling_mode = to_gfx_scaling_mode(image_rendering, b->rect(), dest_rect.to_type<int>());
-        context.display_list_recorder().draw_scaled_immutable_bitmap(dest_rect.to_type<int>(), *b, b->rect(), scaling_mode, text_clip);
+        context.display_list_recorder().draw_scaled_immutable_bitmap(dest_rect.to_type<int>(), *b, b->rect(), scaling_mode);
     }
 }
 

+ 1 - 1
Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h

@@ -45,7 +45,7 @@ public:
     Optional<CSSPixelFraction> natural_aspect_ratio() const override;
 
     virtual bool is_paintable() const override;
-    void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, RefPtr<Painting::DisplayList> clip_paths = {}) const override;
+    void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const override;
 
     virtual Optional<Gfx::Color> color_if_single_pixel_bitmap() const override;
     Gfx::ImmutableBitmap const* current_frame_bitmap(DevicePixelRect const& dest_rect) const;

+ 2 - 2
Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.cpp

@@ -109,10 +109,10 @@ void LinearGradientStyleValue::resolve_for_size(Layout::NodeWithStyleAndBoxModel
     m_resolved = ResolvedData { Painting::resolve_linear_gradient_data(node, size, *this), size };
 }
 
-void LinearGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr<Painting::DisplayList> text_clip) const
+void LinearGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering) const
 {
     VERIFY(m_resolved.has_value());
-    context.display_list_recorder().fill_rect_with_linear_gradient(dest_rect.to_type<int>(), m_resolved->data, text_clip);
+    context.display_list_recorder().fill_rect_with_linear_gradient(dest_rect.to_type<int>(), m_resolved->data);
 }
 
 }

+ 1 - 1
Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.h

@@ -60,7 +60,7 @@ public:
     void resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelSize) const override;
 
     bool is_paintable() const override { return true; }
-    void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering, RefPtr<Painting::DisplayList> text_clip = {}) const override;
+    void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const override;
 
 private:
     LinearGradientStyleValue(GradientDirection direction, Vector<LinearColorStopListElement> color_stop_list, GradientType type, GradientRepeating repeating)

+ 2 - 2
Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.cpp

@@ -207,12 +207,12 @@ bool RadialGradientStyleValue::equals(StyleValue const& other) const
     return m_properties == other_gradient.m_properties;
 }
 
-void RadialGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr<Painting::DisplayList> text_clip) const
+void RadialGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering) const
 {
     VERIFY(m_resolved.has_value());
     auto center = context.rounded_device_point(m_resolved->center).to_type<int>();
     auto size = context.rounded_device_size(m_resolved->gradient_size).to_type<int>();
-    context.display_list_recorder().fill_rect_with_radial_gradient(dest_rect.to_type<int>(), m_resolved->data, center, size, text_clip);
+    context.display_list_recorder().fill_rect_with_radial_gradient(dest_rect.to_type<int>(), m_resolved->data, center, size);
 }
 
 }

+ 1 - 1
Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.h

@@ -51,7 +51,7 @@ public:
 
     virtual String to_string() const override;
 
-    void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering, RefPtr<Painting::DisplayList> text_clip = {}) const override;
+    void paint(PaintContext&, DevicePixelRect const& dest_rect, CSS::ImageRendering) const override;
 
     virtual bool equals(StyleValue const& other) const override;
 

+ 13 - 10
Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp

@@ -56,10 +56,12 @@ static CSSPixelSize run_default_sizing_algorithm(
     return default_size;
 }
 
-static RefPtr<DisplayList> compute_text_clip_paths(PaintContext& context, Paintable const& paintable)
+static RefPtr<DisplayList> compute_text_clip_paths(PaintContext& context, Paintable const& paintable, CSSPixelPoint containing_block_location)
 {
     auto text_clip_paths = DisplayList::create();
     DisplayListRecorder display_list_recorder(*text_clip_paths);
+    // Remove containing block offset, so executing the display list will produce mask at (0, 0)
+    display_list_recorder.translate(-context.floored_device_point(containing_block_location).to_type<int>());
     auto add_text_clip_path = [&](PaintableFragment const& fragment) {
         auto glyph_run = fragment.glyph_run();
         if (!glyph_run || glyph_run->glyphs().is_empty())
@@ -116,13 +118,15 @@ static BackgroundBox get_box(CSS::BackgroundBox box_clip, BackgroundBox border_b
 // https://www.w3.org/TR/css-backgrounds-3/#backgrounds
 void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMetrics const& layout_node, CSS::ImageRendering image_rendering, ResolvedBackground resolved_background, BorderRadiiData const& border_radii)
 {
-    RefPtr<DisplayList> text_clip;
+    auto& display_list_recorder = context.display_list_recorder();
+
+    DisplayListRecorderStateSaver state { display_list_recorder };
     if (resolved_background.needs_text_clip) {
-        text_clip = compute_text_clip_paths(context, *layout_node.paintable());
+        auto display_list = compute_text_clip_paths(context, *layout_node.paintable(), resolved_background.background_rect.location());
+        auto rect = context.rounded_device_rect(resolved_background.background_rect);
+        display_list_recorder.add_mask(move(display_list), rect.to_type<int>());
     }
 
-    auto& display_list_recorder = context.display_list_recorder();
-
     BackgroundBox border_box {
         resolved_background.background_rect,
         border_radii
@@ -136,8 +140,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
         color_box.radii.top_left.as_corner(context),
         color_box.radii.top_right.as_corner(context),
         color_box.radii.bottom_right.as_corner(context),
-        color_box.radii.bottom_left.as_corner(context),
-        text_clip);
+        color_box.radii.bottom_left.as_corner(context));
 
     struct {
         DevicePixels top { 0 };
@@ -332,17 +335,17 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
                     fill_rect = fill_rect->united(image_device_rect);
                 }
             });
-            display_list_recorder.fill_rect(fill_rect->to_type<int>(), color.value(), text_clip);
+            display_list_recorder.fill_rect(fill_rect->to_type<int>(), color.value());
         } else if (is<CSS::ImageStyleValue>(image) && repeat_x && repeat_y && !repeat_x_has_gap && !repeat_y_has_gap) {
             // Use a dedicated painting command for repeated images instead of recording a separate command for each instance
             // of a repeated background, so the painter has the opportunity to optimize the painting of repeated images.
             auto dest_rect = context.rounded_device_rect(image_rect);
             auto const* bitmap = static_cast<CSS::ImageStyleValue const&>(image).current_frame_bitmap(dest_rect);
             auto scaling_mode = to_gfx_scaling_mode(image_rendering, bitmap->rect(), dest_rect.to_type<int>());
-            context.display_list_recorder().draw_repeated_immutable_bitmap(dest_rect.to_type<int>(), clip_rect.to_type<int>(), *bitmap, scaling_mode, { .x = repeat_x, .y = repeat_y }, text_clip);
+            context.display_list_recorder().draw_repeated_immutable_bitmap(dest_rect.to_type<int>(), clip_rect.to_type<int>(), *bitmap, scaling_mode, { .x = repeat_x, .y = repeat_y });
         } else {
             for_each_image_device_rect([&](auto const& image_device_rect) {
-                image.paint(context, image_device_rect, image_rendering, text_clip);
+                image.paint(context, image_device_rect, image_rendering);
             });
         }
     }

+ 12 - 8
Userland/Libraries/LibWeb/Painting/Command.h

@@ -50,7 +50,6 @@ struct DrawGlyphRun {
 struct FillRect {
     Gfx::IntRect rect;
     Color color;
-    RefPtr<DisplayList> text_clip;
 
     [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; }
     void translate_by(Gfx::IntPoint const& offset) { rect.translate_by(offset); }
@@ -71,7 +70,6 @@ struct DrawScaledImmutableBitmap {
     NonnullRefPtr<Gfx::ImmutableBitmap> bitmap;
     Gfx::IntRect src_rect;
     Gfx::ScalingMode scaling_mode;
-    RefPtr<DisplayList> text_clip;
 
     [[nodiscard]] Gfx::IntRect bounding_rect() const { return dst_rect; }
     void translate_by(Gfx::IntPoint const& offset) { dst_rect.translate_by(offset); }
@@ -88,7 +86,6 @@ struct DrawRepeatedImmutableBitmap {
     NonnullRefPtr<Gfx::ImmutableBitmap> bitmap;
     Gfx::ScalingMode scaling_mode;
     Repeat repeat;
-    RefPtr<DisplayList> text_clip;
 
     void translate_by(Gfx::IntPoint const& offset) { dst_rect.translate_by(offset); }
 };
@@ -133,7 +130,6 @@ struct PopStackingContext { };
 struct PaintLinearGradient {
     Gfx::IntRect gradient_rect;
     LinearGradientData linear_gradient_data;
-    RefPtr<DisplayList> text_clip;
 
     [[nodiscard]] Gfx::IntRect bounding_rect() const { return gradient_rect; }
 
@@ -174,7 +170,6 @@ struct FillRectWithRoundedCorners {
     Gfx::IntRect rect;
     Color color;
     CornerRadii corner_radii;
-    RefPtr<DisplayList> text_clip;
 
     [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; }
     void translate_by(Gfx::IntPoint const& offset) { rect.translate_by(offset); }
@@ -314,7 +309,6 @@ struct PaintRadialGradient {
     RadialGradientData radial_gradient_data;
     Gfx::IntPoint center;
     Gfx::IntSize size;
-    RefPtr<DisplayList> text_clip;
 
     [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; }
 
@@ -325,7 +319,6 @@ struct PaintConicGradient {
     Gfx::IntRect rect;
     ConicGradientData conic_gradient_data;
     Gfx::IntPoint position;
-    RefPtr<DisplayList> text_clip;
 
     [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; }
 
@@ -356,6 +349,16 @@ struct AddRoundedRectClip {
     void translate_by(Gfx::IntPoint const& offset) { border_rect.translate_by(offset); }
 };
 
+struct AddMask {
+    RefPtr<DisplayList> display_list;
+    Gfx::IntRect rect;
+
+    void translate_by(Gfx::IntPoint const& offset)
+    {
+        rect.translate_by(offset);
+    }
+};
+
 using Command = Variant<
     DrawGlyphRun,
     FillRect,
@@ -384,6 +387,7 @@ using Command = Variant<
     ApplyBackdropFilter,
     DrawRect,
     DrawTriangleWave,
-    AddRoundedRectClip>;
+    AddRoundedRectClip,
+    AddMask>;
 
 }

+ 1 - 0
Userland/Libraries/LibWeb/Painting/DisplayList.cpp

@@ -85,6 +85,7 @@ void DisplayListPlayer::execute(DisplayList& display_list)
         else HANDLE_COMMAND(DrawRect, draw_rect)
         else HANDLE_COMMAND(DrawTriangleWave, draw_triangle_wave)
         else HANDLE_COMMAND(AddRoundedRectClip, add_rounded_rect_clip)
+        else HANDLE_COMMAND(AddMask, add_mask)
         else VERIFY_NOT_REACHED();
         // clang-format on
     }

+ 1 - 0
Userland/Libraries/LibWeb/Painting/DisplayList.h

@@ -69,6 +69,7 @@ private:
     virtual void draw_rect(DrawRect const&) = 0;
     virtual void draw_triangle_wave(DrawTriangleWave const&) = 0;
     virtual void add_rounded_rect_clip(AddRoundedRectClip const&) = 0;
+    virtual void add_mask(AddMask const&) = 0;
     virtual bool would_be_fully_clipped_by_painter(Gfx::IntRect) const = 0;
 };
 

+ 8 - 31
Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp

@@ -374,15 +374,6 @@ static SkSamplingOptions to_skia_sampling_options(Gfx::ScalingMode scaling_mode)
     }
 }
 
-#define APPLY_TEXT_CLIP_IF_NEEDED(MASK_RECT)                    \
-    ScopeGuard const restore { [&] {                            \
-        if (command.text_clip)                                  \
-            surface().canvas().restore();                       \
-    } };                                                        \
-    if (command.text_clip) {                                    \
-        apply_mask_painted_from(*command.text_clip, MASK_RECT); \
-    }
-
 DisplayListPlayerSkia::SkiaSurface& DisplayListPlayerSkia::surface() const
 {
     return static_cast<SkiaSurface&>(*m_surface);
@@ -422,8 +413,6 @@ void DisplayListPlayerSkia::draw_glyph_run(DrawGlyphRun const& command)
 
 void DisplayListPlayerSkia::fill_rect(FillRect const& command)
 {
-    APPLY_TEXT_CLIP_IF_NEEDED(command.rect)
-
     auto const& rect = command.rect;
     auto& canvas = surface().canvas();
     SkPaint paint;
@@ -444,8 +433,6 @@ void DisplayListPlayerSkia::draw_scaled_bitmap(DrawScaledBitmap const& command)
 
 void DisplayListPlayerSkia::draw_scaled_immutable_bitmap(DrawScaledImmutableBitmap const& command)
 {
-    APPLY_TEXT_CLIP_IF_NEEDED(command.dst_rect)
-
     auto src_rect = to_skia_rect(command.src_rect);
     auto dst_rect = to_skia_rect(command.dst_rect);
     auto bitmap = to_skia_bitmap(command.bitmap->bitmap());
@@ -457,8 +444,6 @@ void DisplayListPlayerSkia::draw_scaled_immutable_bitmap(DrawScaledImmutableBitm
 
 void DisplayListPlayerSkia::draw_repeated_immutable_bitmap(DrawRepeatedImmutableBitmap const& command)
 {
-    APPLY_TEXT_CLIP_IF_NEEDED(command.clip_rect)
-
     auto bitmap = to_skia_bitmap(command.bitmap->bitmap());
     auto image = SkImages::RasterFromBitmap(bitmap);
 
@@ -655,8 +640,6 @@ static ColorStopList expand_repeat_length(ColorStopList const& color_stop_list,
 
 void DisplayListPlayerSkia::paint_linear_gradient(PaintLinearGradient const& command)
 {
-    APPLY_TEXT_CLIP_IF_NEEDED(command.gradient_rect)
-
     auto const& linear_gradient_data = command.linear_gradient_data;
     auto color_stop_list = linear_gradient_data.color_stops.list;
     auto const& repeat_length = linear_gradient_data.color_stops.repeat_length;
@@ -833,8 +816,6 @@ void DisplayListPlayerSkia::paint_text_shadow(PaintTextShadow const& command)
 
 void DisplayListPlayerSkia::fill_rect_with_rounded_corners(FillRectWithRoundedCorners const& command)
 {
-    APPLY_TEXT_CLIP_IF_NEEDED(command.rect)
-
     auto const& rect = command.rect;
 
     auto& canvas = surface().canvas();
@@ -1200,8 +1181,6 @@ void DisplayListPlayerSkia::draw_rect(DrawRect const& command)
 
 void DisplayListPlayerSkia::paint_radial_gradient(PaintRadialGradient const& command)
 {
-    APPLY_TEXT_CLIP_IF_NEEDED(command.rect)
-
     auto const& radial_gradient_data = command.radial_gradient_data;
 
     auto color_stop_list = radial_gradient_data.color_stops.list;
@@ -1249,8 +1228,6 @@ void DisplayListPlayerSkia::paint_radial_gradient(PaintRadialGradient const& com
 
 void DisplayListPlayerSkia::paint_conic_gradient(PaintConicGradient const& command)
 {
-    APPLY_TEXT_CLIP_IF_NEEDED(command.rect)
-
     auto const& conic_gradient_data = command.conic_gradient_data;
 
     auto color_stop_list = conic_gradient_data.color_stops.list;
@@ -1300,19 +1277,14 @@ void DisplayListPlayerSkia::add_rounded_rect_clip(AddRoundedRectClip const& comm
     canvas.clipRRect(rounded_rect, clip_op, true);
 }
 
-bool DisplayListPlayerSkia::would_be_fully_clipped_by_painter(Gfx::IntRect rect) const
-{
-    return surface().canvas().quickReject(to_skia_rect(rect));
-}
-
-void DisplayListPlayerSkia::apply_mask_painted_from(DisplayList& display_list, Gfx::IntRect rect)
+void DisplayListPlayerSkia::add_mask(AddMask const& command)
 {
+    auto const& rect = command.rect;
     auto mask_surface = m_surface->make_surface(rect.width(), rect.height());
 
     auto previous_surface = move(m_surface);
     m_surface = make<SkiaSurface>(mask_surface);
-    surface().canvas().translate(-rect.x(), -rect.y());
-    execute(display_list);
+    execute(*command.display_list);
     m_surface = move(previous_surface);
 
     SkMatrix mask_matrix;
@@ -1323,4 +1295,9 @@ void DisplayListPlayerSkia::apply_mask_painted_from(DisplayList& display_list, G
     surface().canvas().clipShader(shader);
 }
 
+bool DisplayListPlayerSkia::would_be_fully_clipped_by_painter(Gfx::IntRect rect) const
+{
+    return surface().canvas().quickReject(to_skia_rect(rect));
+}
+
 }

+ 1 - 2
Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h

@@ -76,11 +76,10 @@ private:
     void paint_conic_gradient(PaintConicGradient const&) override;
     void draw_triangle_wave(DrawTriangleWave const&) override;
     void add_rounded_rect_clip(AddRoundedRectClip const&) override;
+    void add_mask(AddMask const&) override;
 
     bool would_be_fully_clipped_by_painter(Gfx::IntRect) const override;
 
-    void apply_mask_painted_from(DisplayList&, Gfx::IntRect);
-
     class SkiaSurface;
     SkiaSurface& surface() const;
 

+ 22 - 23
Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp

@@ -30,14 +30,20 @@ void DisplayListRecorder::add_rounded_rect_clip(CornerRadii corner_radii, Gfx::I
         corner_clip });
 }
 
-void DisplayListRecorder::fill_rect(Gfx::IntRect const& rect, Color color, RefPtr<DisplayList> text_clip)
+void DisplayListRecorder::add_mask(RefPtr<DisplayList> display_list, Gfx::IntRect rect)
+{
+    append(AddMask {
+        .display_list = move(display_list),
+        .rect = state().translation.map(rect) });
+}
+
+void DisplayListRecorder::fill_rect(Gfx::IntRect const& rect, Color color)
 {
     if (rect.is_empty())
         return;
     append(FillRect {
         .rect = state().translation.map(rect),
         .color = color,
-        .text_clip = move(text_clip),
     });
 }
 
@@ -128,28 +134,26 @@ void DisplayListRecorder::fill_ellipse(Gfx::IntRect const& a_rect, Color color)
     });
 }
 
-void DisplayListRecorder::fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data, RefPtr<DisplayList> text_clip)
+void DisplayListRecorder::fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data)
 {
     if (gradient_rect.is_empty())
         return;
     append(PaintLinearGradient {
         .gradient_rect = state().translation.map(gradient_rect),
-        .linear_gradient_data = data,
-        .text_clip = move(text_clip) });
+        .linear_gradient_data = data });
 }
 
-void DisplayListRecorder::fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position, RefPtr<DisplayList> text_clip)
+void DisplayListRecorder::fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position)
 {
     if (rect.is_empty())
         return;
     append(PaintConicGradient {
         .rect = state().translation.map(rect),
         .conic_gradient_data = data,
-        .position = position,
-        .text_clip = move(text_clip) });
+        .position = position });
 }
 
-void DisplayListRecorder::fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size, RefPtr<DisplayList> text_clip)
+void DisplayListRecorder::fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size)
 {
     if (rect.is_empty())
         return;
@@ -157,8 +161,7 @@ void DisplayListRecorder::fill_rect_with_radial_gradient(Gfx::IntRect const& rec
         .rect = state().translation.map(rect),
         .radial_gradient_data = data,
         .center = center,
-        .size = size,
-        .text_clip = move(text_clip) });
+        .size = size });
 }
 
 void DisplayListRecorder::draw_rect(Gfx::IntRect const& rect, Color color, bool rough)
@@ -183,7 +186,7 @@ void DisplayListRecorder::draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::
     });
 }
 
-void DisplayListRecorder::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, RefPtr<DisplayList> text_clip)
+void DisplayListRecorder::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode)
 {
     if (dst_rect.is_empty())
         return;
@@ -192,11 +195,10 @@ void DisplayListRecorder::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_r
         .bitmap = bitmap,
         .src_rect = src_rect,
         .scaling_mode = scaling_mode,
-        .text_clip = move(text_clip),
     });
 }
 
-void DisplayListRecorder::draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, NonnullRefPtr<Gfx::ImmutableBitmap> bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat repeat, RefPtr<DisplayList> text_clip)
+void DisplayListRecorder::draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, NonnullRefPtr<Gfx::ImmutableBitmap> bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat repeat)
 {
     append(DrawRepeatedImmutableBitmap {
         .dst_rect = dst_rect,
@@ -204,7 +206,6 @@ void DisplayListRecorder::draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect,
         .bitmap = move(bitmap),
         .scaling_mode = scaling_mode,
         .repeat = repeat,
-        .text_clip = move(text_clip),
     });
 }
 
@@ -352,13 +353,13 @@ void DisplayListRecorder::paint_text_shadow(int blur_radius, Gfx::IntRect boundi
         .draw_location = state().translation.map(draw_location) });
 }
 
-void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius, RefPtr<DisplayList> text_clip)
+void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius)
 {
     if (rect.is_empty())
         return;
 
     if (!top_left_radius && !top_right_radius && !bottom_right_radius && !bottom_left_radius) {
-        fill_rect(rect, color, text_clip);
+        fill_rect(rect, color);
         return;
     }
 
@@ -371,18 +372,17 @@ void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& rec
             .bottom_right = bottom_right_radius,
             .bottom_left = bottom_left_radius,
         },
-        .text_clip = text_clip,
     });
 }
 
-void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius, RefPtr<DisplayList> text_clip)
+void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius)
 {
     if (a_rect.is_empty())
         return;
-    fill_rect_with_rounded_corners(a_rect, color, radius, radius, radius, radius, move(text_clip));
+    fill_rect_with_rounded_corners(a_rect, color, radius, radius, radius, radius);
 }
 
-void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius, RefPtr<DisplayList> text_clip)
+void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius)
 {
     if (a_rect.is_empty())
         return;
@@ -390,8 +390,7 @@ void DisplayListRecorder::fill_rect_with_rounded_corners(Gfx::IntRect const& a_r
         { top_left_radius, top_left_radius },
         { top_right_radius, top_right_radius },
         { bottom_right_radius, bottom_right_radius },
-        { bottom_left_radius, bottom_left_radius },
-        move(text_clip));
+        { bottom_left_radius, bottom_left_radius });
 }
 
 void DisplayListRecorder::draw_triangle_wave(Gfx::IntPoint a_p1, Gfx::IntPoint a_p2, Color color, int amplitude, int thickness = 1)

+ 10 - 9
Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h

@@ -40,7 +40,7 @@ class DisplayListRecorder {
     AK_MAKE_NONMOVABLE(DisplayListRecorder);
 
 public:
-    void fill_rect(Gfx::IntRect const& rect, Color color, RefPtr<DisplayList> text_clip = {});
+    void fill_rect(Gfx::IntRect const& rect, Color color);
 
     struct FillPathUsingColorParams {
         Gfx::Path path;
@@ -80,16 +80,16 @@ public:
 
     void fill_ellipse(Gfx::IntRect const& a_rect, Color color);
 
-    void fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data, RefPtr<DisplayList> text_clip = {});
-    void fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position, RefPtr<DisplayList> text_clip = {});
-    void fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size, RefPtr<DisplayList> text_clip = {});
+    void fill_rect_with_linear_gradient(Gfx::IntRect const& gradient_rect, LinearGradientData const& data);
+    void fill_rect_with_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const& data, Gfx::IntPoint const& position);
+    void fill_rect_with_radial_gradient(Gfx::IntRect const& rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::IntSize size);
 
     void draw_rect(Gfx::IntRect const& rect, Color color, bool rough = false);
 
     void draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor);
-    void draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor, RefPtr<DisplayList> text_clip = {});
+    void draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor);
 
-    void draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, NonnullRefPtr<Gfx::ImmutableBitmap> bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat, RefPtr<DisplayList> text_clip = {});
+    void draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, NonnullRefPtr<Gfx::ImmutableBitmap> bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat);
 
     void draw_line(Gfx::IntPoint from, Gfx::IntPoint to, Color color, int thickness = 1, Gfx::LineStyle style = Gfx::LineStyle::Solid, Color alternate_color = Color::Transparent);
 
@@ -123,6 +123,7 @@ public:
     void pop_stacking_context();
 
     void add_rounded_rect_clip(CornerRadii corner_radii, Gfx::IntRect border_rect, CornerClip corner_clip);
+    void add_mask(RefPtr<DisplayList> display_list, Gfx::IntRect rect);
 
     void apply_backdrop_filter(Gfx::IntRect const& backdrop_region, BorderRadiiData const& border_radii_data, CSS::ResolvedBackdropFilter const& backdrop_filter);
 
@@ -130,9 +131,9 @@ public:
     void paint_inner_box_shadow_params(PaintBoxShadowParams params);
     void paint_text_shadow(int blur_radius, Gfx::IntRect bounding_rect, Gfx::IntRect text_rect, Gfx::GlyphRun const&, double glyph_run_scale, Color color, Gfx::IntPoint draw_location);
 
-    void fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius, RefPtr<DisplayList> text_clip = {});
-    void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius, RefPtr<DisplayList> text_clip = {});
-    void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius, RefPtr<DisplayList> text_clip = {});
+    void fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius);
+    void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius);
+    void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int top_left_radius, int top_right_radius, int bottom_right_radius, int bottom_left_radius);
 
     void draw_triangle_wave(Gfx::IntPoint a_p1, Gfx::IntPoint a_p2, Color color, int amplitude, int thickness);