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));
}