diff --git a/Libraries/LibWeb/Painting/Command.h b/Libraries/LibWeb/Painting/Command.h index fca91076711..e085ab80881 100644 --- a/Libraries/LibWeb/Painting/Command.h +++ b/Libraries/LibWeb/Painting/Command.h @@ -105,6 +105,8 @@ struct Translate { struct AddClipRect { Gfx::IntRect rect; + [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } + bool is_clip_or_mask() const { return true; } void translate_by(Gfx::IntPoint const& offset) { rect.translate_by(offset); } }; @@ -349,6 +351,7 @@ struct AddRoundedRectClip { CornerClip corner_clip; [[nodiscard]] Gfx::IntRect bounding_rect() const { return border_rect; } + bool is_clip_or_mask() const { return true; } void translate_by(Gfx::IntPoint const& offset) { border_rect.translate_by(offset); } }; @@ -358,6 +361,7 @@ struct AddMask { Gfx::IntRect rect; [[nodiscard]] Gfx::IntRect bounding_rect() const { return rect; } + bool is_clip_or_mask() const { return true; } void translate_by(Gfx::IntPoint const& offset) { diff --git a/Libraries/LibWeb/Painting/DisplayList.cpp b/Libraries/LibWeb/Painting/DisplayList.cpp index 4883944a206..b7b0f89173d 100644 --- a/Libraries/LibWeb/Painting/DisplayList.cpp +++ b/Libraries/LibWeb/Painting/DisplayList.cpp @@ -24,6 +24,17 @@ static Optional command_bounding_rectangle(Command const& command) }); } +static bool command_is_clip_or_mask(Command const& command) +{ + return command.visit( + [&](auto const& command) -> bool { + if constexpr (requires { command.is_clip_or_mask(); }) + return command.is_clip_or_mask(); + else + return false; + }); +} + void DisplayListPlayer::execute(DisplayList& display_list) { auto const& commands = display_list.commands(); @@ -60,6 +71,15 @@ void DisplayListPlayer::execute(DisplayList& display_list) auto bounding_rect = command_bounding_rectangle(command); if (bounding_rect.has_value() && (bounding_rect->is_empty() || would_be_fully_clipped_by_painter(*bounding_rect))) { + // Any clip or mask that's located outside of the visible region is equivalent to a simple clip-rect, + // so replace it with one to avoid doing unnecessary work. + if (command_is_clip_or_mask(command)) { + if (command.has()) { + add_clip_rect(command.get()); + } else { + add_clip_rect({ bounding_rect.release_value() }); + } + } continue; } diff --git a/Tests/LibWeb/Ref/expected/clip-offscreen-ref.html b/Tests/LibWeb/Ref/expected/clip-offscreen-ref.html new file mode 100644 index 00000000000..397a3461531 --- /dev/null +++ b/Tests/LibWeb/Ref/expected/clip-offscreen-ref.html @@ -0,0 +1,2 @@ + +(This space intentionally left blank) diff --git a/Tests/LibWeb/Ref/input/clip-offscreen.html b/Tests/LibWeb/Ref/input/clip-offscreen.html new file mode 100644 index 00000000000..943192b0a7e --- /dev/null +++ b/Tests/LibWeb/Ref/input/clip-offscreen.html @@ -0,0 +1,57 @@ + + + +
+
+ 01) Overflow
+ 02) Overflow
+ 03) Overflow
+ 04) Overflow
+ 05) Overflow
+ 06) Overflow
+ 07) Overflow
+ 08) Overflow
+ 09) Overflow
+ 10) Overflow
+
+
+ +
+
+ 01) Border-radius overflow
+ 02) Border-radius overflow
+ 03) Border-radius overflow
+ 04) Border-radius overflow
+ 05) Border-radius overflow
+ 06) Border-radius overflow
+ 07) Border-radius overflow
+ 08) Border-radius overflow
+ 09) Border-radius overflow
+ 10) Border-radius overflow
+
+
+ +
+
+ 01) Masked overflow
+ 02) Masked overflow
+ 03) Masked overflow
+ 04) Masked overflow
+ 05) Masked overflow
+ 06) Masked overflow
+ 07) Masked overflow
+ 08) Masked overflow
+ 09) Masked overflow
+ 10) Masked overflow
+
+
+ +(This space intentionally left blank)