From ee4ba7617ce8e99df953cff0b345974eb1f7098e Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Wed, 25 Jan 2023 02:57:50 +0300 Subject: [PATCH] LibWeb: Fix clip of hidden overflow when translated boxes are involved There is a problem with current approach where overflow clip rectange is calculated by aggregating intersection of absolute padding boxes of boxes in containing block chain that resulting rectangle doesn't respect transform properties. To solve this problem `PaintableBox` is changed to store clip rectangle saved from painter because it does respect transform properties of all previously applied clip rectangles. --- Userland/Libraries/LibGfx/Painter.h | 1 + .../LibWeb/Painting/PaintableBox.cpp | 37 ++++++++----------- .../Libraries/LibWeb/Painting/PaintableBox.h | 4 +- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/Userland/Libraries/LibGfx/Painter.h b/Userland/Libraries/LibGfx/Painter.h index 5f4804ca01..e1f9c542fa 100644 --- a/Userland/Libraries/LibGfx/Painter.h +++ b/Userland/Libraries/LibGfx/Painter.h @@ -177,6 +177,7 @@ public: } IntRect clip_rect() const { return state().clip_rect; } + void set_clip_rect(IntRect const& rect) { state().clip_rect = rect; } int scale() const { return state().scale; } diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index 9e9c9bf866..f63cbd709f 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -313,24 +313,8 @@ BorderRadiiData PaintableBox::normalized_border_radii_data(ShrinkRadiiForBorders return border_radius_data; } -Optional PaintableBox::clip_rect() const +Optional PaintableBox::clip_rect() const { - if (!m_clip_rect.has_value()) { - if (containing_block() && containing_block()->paint_box()) - m_clip_rect = containing_block()->paint_box()->clip_rect(); - - auto overflow_x = computed_values().overflow_x(); - auto overflow_y = computed_values().overflow_y(); - - if (overflow_x == CSS::Overflow::Hidden && overflow_y == CSS::Overflow::Hidden) { - if (m_clip_rect.has_value()) { - m_clip_rect->intersect(absolute_padding_box_rect()); - } else { - m_clip_rect = absolute_padding_box_rect(); - } - } - } - return m_clip_rect; } @@ -339,27 +323,36 @@ void PaintableBox::before_children_paint(PaintContext& context, PaintPhase phase if (!AK::first_is_one_of(phase, PaintPhase::Background, PaintPhase::Border, PaintPhase::Foreground)) return; - // FIXME: Support more overflow variations. - auto clip_rect = this->clip_rect(); + auto clip_rect = context.painter().clip_rect(); + if (containing_block() && containing_block()->paint_box()) { + if (containing_block()->paint_box()->clip_rect().has_value()) { + clip_rect = *containing_block()->paint_box()->clip_rect(); + } + } + context.painter().set_clip_rect(clip_rect); + auto overflow_x = computed_values().overflow_x(); auto overflow_y = computed_values().overflow_y(); auto clip_overflow = [&] { if (!m_clipping_overflow) { context.painter().save(); - context.painter().add_clip_rect(context.rounded_device_rect(*clip_rect).to_type()); + context.painter().add_clip_rect(context.rounded_device_rect(absolute_padding_box_rect()).to_type()); m_clipping_overflow = true; } }; - if (clip_rect.has_value()) { + // FIXME: Support more overflow variations. + if (overflow_x == CSS::Overflow::Hidden && overflow_y == CSS::Overflow::Hidden) { clip_overflow(); } + m_clip_rect = context.painter().clip_rect(); + if (overflow_y == CSS::Overflow::Hidden || overflow_x == CSS::Overflow::Hidden) { auto border_radii_data = normalized_border_radii_data(ShrinkRadiiForBorders::Yes); if (border_radii_data.has_any_radius()) { - auto corner_clipper = BorderRadiusCornerClipper::create(context, context.rounded_device_rect(*clip_rect), border_radii_data, CornerClip::Outside, BorderRadiusCornerClipper::UseCachedBitmap::No); + auto corner_clipper = BorderRadiusCornerClipper::create(context, context.rounded_device_rect(absolute_padding_box_rect()), border_radii_data, CornerClip::Outside, BorderRadiusCornerClipper::UseCachedBitmap::No); if (corner_clipper.is_error()) { dbgln("Failed to create overflow border-radius corner clipper: {}", corner_clipper.error()); return; diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h index 170041772e..eb3b8125d5 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h @@ -98,7 +98,7 @@ public: return m_overflow_data->scrollable_overflow_rect; } - Optional clip_rect() const; + Optional clip_rect() const; void set_overflow_data(Optional data) { m_overflow_data = move(data); } void set_containing_line_box_fragment(Optional); @@ -157,7 +157,7 @@ private: Optional mutable m_absolute_rect; Optional mutable m_absolute_paint_rect; - Optional mutable m_clip_rect; + Gfx::IntRect mutable m_clip_rect; mutable bool m_clipping_overflow { false }; Optional mutable m_overflow_corner_radius_clipper;