LibWeb: Remove CSS transform from InlinePaintable's clip rectangle

Fixes bug when CSS transform is applied twice to clip rect:
- While calculating absolute clip rectangles in `refresh_clip_state()`
- While executing `PushStackingContext` painting command.

Duplicated transform is already removed for PaintableBox and this change
adds this for InlinePaintable.
This commit is contained in:
Aliaksandr Kalenik 2024-04-26 18:04:15 +02:00 committed by Andreas Kling
parent 13422b5116
commit dc4192c149
7 changed files with 51 additions and 13 deletions

View file

@ -0,0 +1,13 @@
<!doctype html>
<link rel="match" href="reference/inline-paintable-inside-translated-container-ref.html" />
<style>
body {
transform: translateY(100px);
position: absolute;
margin: 0;
}
div {
overflow: hidden;
outline: 1px solid black;
}
</style><body><div><span>hello

View file

@ -0,0 +1,11 @@
<!doctype html>
<link rel="match" href="reference/inline-paintable-inside-translated-container-ref.html" />
<style>
body {
margin-top: 100px;
margin-left: 0px;
}
span {
outline: 1px solid black;
}
</style><body><div><span>hello

View file

@ -46,8 +46,16 @@ Optional<CSSPixelPoint> InlinePaintable::enclosing_scroll_frame_offset() const
Optional<CSSPixelRect> InlinePaintable::clip_rect() const
{
if (m_enclosing_clip_frame)
return m_enclosing_clip_frame->rect();
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.
auto combined_transform = compute_combined_css_transform();
rect.translate_by(-combined_transform.translation().to_type<CSSPixels>());
return rect;
}
return {};
}

View file

@ -174,4 +174,19 @@ CSSPixelPoint Paintable::box_type_agnostic_position() const
return position;
}
Gfx::AffineTransform Paintable::compute_combined_css_transform() const
{
Gfx::AffineTransform combined_transform;
if (is_paintable_box()) {
auto const& paintable_box = static_cast<PaintableBox const&>(*this);
auto affine_transform = Gfx::extract_2d_affine_transform(paintable_box.transform());
combined_transform = combined_transform.multiply(affine_transform);
}
for (auto const* ancestor = this->containing_block(); ancestor; ancestor = ancestor->containing_block()) {
auto affine_transform = Gfx::extract_2d_affine_transform(ancestor->transform());
combined_transform = combined_transform.multiply(affine_transform);
}
return combined_transform;
}
}

View file

@ -218,6 +218,8 @@ public:
SelectionState selection_state() const { return m_selection_state; }
void set_selection_state(SelectionState state) { m_selection_state = state; }
Gfx::AffineTransform compute_combined_css_transform() const;
protected:
explicit Paintable(Layout::Node const&);

View file

@ -164,16 +164,6 @@ CSSPixelRect PaintableBox::compute_absolute_padding_rect_with_css_transform_appl
return padding_rect;
}
Gfx::AffineTransform PaintableBox::compute_combined_css_transform() const
{
Gfx::AffineTransform combined_transform;
for (auto const* ancestor = this; ancestor; ancestor = ancestor->containing_block()) {
auto affine_transform = Gfx::extract_2d_affine_transform(ancestor->transform());
combined_transform = combined_transform.multiply(affine_transform);
}
return combined_transform;
}
CSSPixelRect PaintableBox::absolute_rect() const
{
if (!m_absolute_rect.has_value())

View file

@ -203,7 +203,6 @@ public:
CSSPixels outline_offset() const { return m_outline_offset; }
CSSPixelRect compute_absolute_padding_rect_with_css_transform_applied() const;
Gfx::AffineTransform compute_combined_css_transform() const;
Optional<CSSPixelRect> get_clip_rect() const;