diff --git a/Tests/LibWeb/Ref/reference/scrollable-contains-rotated-boxes-ref.html b/Tests/LibWeb/Ref/reference/scrollable-contains-rotated-boxes-ref.html new file mode 100644 index 00000000000..641a33c0d80 --- /dev/null +++ b/Tests/LibWeb/Ref/reference/scrollable-contains-rotated-boxes-ref.html @@ -0,0 +1,46 @@ + + + + + + +
+
+
+
+
+
+
+
+
+ + diff --git a/Tests/LibWeb/Ref/scrollable-contains-rotated-boxes.html b/Tests/LibWeb/Ref/scrollable-contains-rotated-boxes.html new file mode 100644 index 00000000000..1be3336f657 --- /dev/null +++ b/Tests/LibWeb/Ref/scrollable-contains-rotated-boxes.html @@ -0,0 +1,47 @@ + + + + + + +
+
+
+
+
+
+
+
+
+ + diff --git a/Userland/Libraries/LibWeb/Layout/Node.h b/Userland/Libraries/LibWeb/Layout/Node.h index 95899e59ba0..5598ab0722f 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.h +++ b/Userland/Libraries/LibWeb/Layout/Node.h @@ -172,6 +172,8 @@ public: // https://www.w3.org/TR/CSS22/visuren.html#positioning-scheme bool is_in_flow() const { return !is_out_of_flow(); } + bool has_css_transform() const { return computed_values().transformations().size() > 0; } + protected: Node(DOM::Document&, DOM::Node*); diff --git a/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp b/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp index cb99bf4ea18..40ae66f8b96 100644 --- a/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp +++ b/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp @@ -24,16 +24,8 @@ Optional ClippableAndScrollable::enclosing_scroll_frame_offset() Optional ClippableAndScrollable::clip_rect() const { - if (m_enclosing_clip_frame) { - auto rect = m_enclosing_clip_frame->rect(); - // NOTE: Since the painting command executor applies a CSS transform and the clip rect is calculated - // with this transform taken into account, we need to remove the transform from the clip rect. - // Otherwise, the transform will be applied twice to the clip rect. - // Similarly, for hit-testing, the transform must be removed from the clip rectangle since the position - // includes the transform. - rect.translate_by(-m_combined_css_transform.translation().to_type()); - return rect; - } + if (m_enclosing_clip_frame) + return m_enclosing_clip_frame->rect(); return {}; } diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index f6fdf29a312..f38e828f6d7 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -158,13 +158,12 @@ CSSPixelRect PaintableBox::compute_absolute_rect() const return rect; } -CSSPixelRect PaintableBox::compute_absolute_padding_rect_with_css_transform_applied() const +CSSPixelRect PaintableBox::compute_absolute_padding_rect_with_scroll_offset_applied() const { auto rect = absolute_rect(); auto scroll_offset = this->enclosing_scroll_frame_offset(); if (scroll_offset.has_value()) rect.translate_by(scroll_offset.value()); - rect.translate_by(combined_css_transform().translation().to_type()); CSSPixelRect padding_rect; padding_rect.set_x(rect.x() - box_model().padding.left); @@ -233,7 +232,9 @@ void PaintableBox::before_paint(PaintContext& context, [[maybe_unused]] PaintPha if (!is_visible()) return; - apply_clip_overflow_rect(context, phase); + if (!has_css_transform()) { + apply_clip_overflow_rect(context, phase); + } apply_scroll_offset(context, phase); } @@ -243,7 +244,9 @@ void PaintableBox::after_paint(PaintContext& context, [[maybe_unused]] PaintPhas return; reset_scroll_offset(context, phase); - clear_clip_overflow_rect(context, phase); + if (!has_css_transform()) { + clear_clip_overflow_rect(context, phase); + } } bool PaintableBox::is_scrollable(ScrollDirection direction) const @@ -533,14 +536,12 @@ void PaintableBox::apply_clip_overflow_rect(PaintContext& context, PaintPhase ph context.display_list_recorder().save(); context.display_list_recorder().add_clip_rect(context.enclosing_device_rect(overflow_clip_rect).to_type()); auto const& border_radii_clips = this->border_radii_clips(); - auto const& combined_transform = combined_css_transform(); for (size_t corner_clip_index = 0; corner_clip_index < border_radii_clips.size(); ++corner_clip_index) { auto const& corner_clip = border_radii_clips[corner_clip_index]; auto corners = corner_clip.radii.as_corners(context); if (!corners.has_any_radius()) continue; - auto rect = corner_clip.rect.translated(-combined_transform.translation().to_type()); - context.display_list_recorder().add_rounded_rect_clip(corner_clip.radii.as_corners(context), context.rounded_device_rect(rect).to_type(), CornerClip::Outside); + context.display_list_recorder().add_rounded_rect_clip(corner_clip.radii.as_corners(context), context.rounded_device_rect(corner_clip.rect).to_type(), CornerClip::Outside); } } } diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h index b75f9d2c8d7..1ab4ef67187 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h @@ -113,6 +113,8 @@ public: [[nodiscard]] bool has_scrollable_overflow() const { return m_overflow_data->has_scrollable_overflow; } + bool has_css_transform() const { return computed_values().transformations().size() > 0; } + [[nodiscard]] Optional scrollable_overflow_rect() const { if (!m_overflow_data.has_value()) @@ -199,7 +201,7 @@ public: void set_outline_offset(CSSPixels outline_offset) { m_outline_offset = outline_offset; } CSSPixels outline_offset() const { return m_outline_offset; } - CSSPixelRect compute_absolute_padding_rect_with_css_transform_applied() const; + CSSPixelRect compute_absolute_padding_rect_with_scroll_offset_applied() const; Optional get_clip_rect() const; diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp index 6aa591d1553..016722619ea 100644 --- a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp +++ b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp @@ -316,12 +316,18 @@ void StackingContext::paint(PaintContext& context) const } } + auto has_css_transform = paintable().is_paintable_box() && paintable_box().has_css_transform(); context.display_list_recorder().save(); + if (has_css_transform) { + paintable_box().apply_clip_overflow_rect(context, PaintPhase::Foreground); + } if (paintable().is_paintable_box() && paintable_box().scroll_frame_id().has_value()) context.display_list_recorder().set_scroll_frame_id(*paintable_box().scroll_frame_id()); context.display_list_recorder().push_stacking_context(push_stacking_context_params); paint_internal(context); context.display_list_recorder().pop_stacking_context(); + if (has_css_transform) + paintable_box().clear_clip_overflow_rect(context, PaintPhase::Foreground); context.display_list_recorder().restore(); } diff --git a/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp b/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp index 957c369abdc..cc0be41a4cd 100644 --- a/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp @@ -119,6 +119,9 @@ void ViewportPaintable::assign_clip_frames() } break; } + if (block->has_css_transform()) { + break; + } } return TraversalDecision::Continue; }); @@ -164,14 +167,17 @@ void ViewportPaintable::refresh_clip_state() }; clip_frame.clear_border_radii_clips(); if (overflow_x != CSS::Overflow::Visible && overflow_y != CSS::Overflow::Visible) { - auto overflow_clip_rect = paintable_box.compute_absolute_padding_rect_with_css_transform_applied(); + auto overflow_clip_rect = paintable_box.compute_absolute_padding_rect_with_scroll_offset_applied(); add_border_radii_clip(overflow_clip_rect, paintable_box.normalized_border_radii_data(ShrinkRadiiForBorders::Yes)); for (auto const* block = &paintable_box.layout_box(); !block->is_viewport(); block = block->containing_block()) { + if (block->has_css_transform()) { + break; + } auto const& block_paintable_box = *block->paintable_box(); auto block_overflow_x = block_paintable_box.computed_values().overflow_x(); auto block_overflow_y = block_paintable_box.computed_values().overflow_y(); if (block_overflow_x != CSS::Overflow::Visible && block_overflow_y != CSS::Overflow::Visible) { - auto rect = block_paintable_box.compute_absolute_padding_rect_with_css_transform_applied(); + auto rect = block_paintable_box.compute_absolute_padding_rect_with_scroll_offset_applied(); overflow_clip_rect.intersect(rect); add_border_radii_clip(rect, block_paintable_box.normalized_border_radii_data(ShrinkRadiiForBorders::Yes)); }