From fb2166f19c389ccc29ba94aa03a736e02a80ee12 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Tue, 30 Jan 2024 12:08:53 +0100 Subject: [PATCH] LibWeb: Account for CSS transform in Element::getClientRects() --- ...get-bounding-client-rect-css-transform.txt | 1 + ...et-bounding-client-rect-css-transform.html | 30 +++++++++++++++++++ Userland/Libraries/LibWeb/DOM/Element.cpp | 17 +++++++++-- 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/element-get-bounding-client-rect-css-transform.txt create mode 100644 Tests/LibWeb/Text/input/element-get-bounding-client-rect-css-transform.html diff --git a/Tests/LibWeb/Text/expected/element-get-bounding-client-rect-css-transform.txt b/Tests/LibWeb/Text/expected/element-get-bounding-client-rect-css-transform.txt new file mode 100644 index 0000000000..10297861d2 --- /dev/null +++ b/Tests/LibWeb/Text/expected/element-get-bounding-client-rect-css-transform.txt @@ -0,0 +1 @@ + {"x":68,"y":118,"width":100,"height":100,"top":118,"right":168,"bottom":218,"left":68} diff --git a/Tests/LibWeb/Text/input/element-get-bounding-client-rect-css-transform.html b/Tests/LibWeb/Text/input/element-get-bounding-client-rect-css-transform.html new file mode 100644 index 0000000000..0774a2ada9 --- /dev/null +++ b/Tests/LibWeb/Text/input/element-get-bounding-client-rect-css-transform.html @@ -0,0 +1,30 @@ + + +
+
+
+
+
+ + diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index 76945fc283..5cde4c6fe2 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -900,7 +900,7 @@ JS::NonnullGCPtr Element::get_client_rects() const // 3. Return a DOMRectList object containing DOMRect objects in content order, one for each box fragment, // describing its border area (including those with a height or width of zero) with the following constraints: - // FIXME: - Apply the transforms that apply to the element and its ancestors. + // - Apply the transforms that apply to the element and its ancestors. // FIXME: - If the element on which the method was invoked has a computed value for the display property of table // or inline-table include both the table box and the caption box, if any, but not the anonymous container box. // FIXME: - Replace each anonymous block box with its child box(es) and repeat this until no anonymous block boxes @@ -908,16 +908,27 @@ JS::NonnullGCPtr Element::get_client_rects() const const_cast(document()).update_layout(); VERIFY(document().navigable()); auto viewport_offset = document().navigable()->viewport_scroll_offset(); + + Gfx::AffineTransform transform; + for (auto const* containing_block = this->layout_node(); containing_block; containing_block = containing_block->containing_block()) { + Gfx::AffineTransform containing_block_transform; + if (containing_block->paintable() && containing_block->paintable()->is_paintable_box()) { + auto const& containing_block_paintable_box = static_cast(*containing_block->paintable()); + containing_block_transform = Gfx::extract_2d_affine_transform(containing_block_paintable_box.transform()); + } + transform = transform.multiply(containing_block_transform); + } + auto const* paintable = this->paintable(); if (auto const* paintable_box = this->paintable_box()) { auto absolute_rect = paintable_box->absolute_border_box_rect(); absolute_rect.translate_by(-viewport_offset.x(), -viewport_offset.y()); - rects.append(Geometry::DOMRect::create(realm(), absolute_rect.to_type())); + rects.append(Geometry::DOMRect::create(realm(), transform.map(absolute_rect.to_type()))); } else if (paintable && is(*paintable)) { auto const& inline_paintable = static_cast(*paintable); auto absolute_rect = inline_paintable.bounding_rect(); absolute_rect.translate_by(-viewport_offset.x(), -viewport_offset.y()); - rects.append(Geometry::DOMRect::create(realm(), absolute_rect.to_type())); + rects.append(Geometry::DOMRect::create(realm(), transform.map(absolute_rect.to_type()))); } else if (paintable) { dbgln("FIXME: Failed to get client rects for element ({})", debug_description()); }