From 1e7b17f15024d0618f1a1e17e3e927856febde28 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 5 Aug 2024 11:28:42 +0200 Subject: [PATCH] LibWeb: Don't crash on getClientRects() in document without navigable I previously believed there was no way a detached document should have layout information, but it turns out there is a way: getComputedStyle(). So we need to account for cases where we have a layout node, but no navigable, since that is a state we can get into at this moment. Fixes #354 --- .../getClientRects-in-detached-document.txt | 3 +++ .../getClientRects-in-detached-document.html | 16 ++++++++++++++++ Userland/Libraries/LibWeb/DOM/Element.cpp | 10 +++++----- 3 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/CSSOMView/getClientRects-in-detached-document.txt create mode 100644 Tests/LibWeb/Text/input/CSSOMView/getClientRects-in-detached-document.html diff --git a/Tests/LibWeb/Text/expected/CSSOMView/getClientRects-in-detached-document.txt b/Tests/LibWeb/Text/expected/CSSOMView/getClientRects-in-detached-document.txt new file mode 100644 index 00000000000..cbd504d0973 --- /dev/null +++ b/Tests/LibWeb/Text/expected/CSSOMView/getClientRects-in-detached-document.txt @@ -0,0 +1,3 @@ +[object CSSStyleDeclaration] +[object DOMRectList] +PASS (didn't crash) diff --git a/Tests/LibWeb/Text/input/CSSOMView/getClientRects-in-detached-document.html b/Tests/LibWeb/Text/input/CSSOMView/getClientRects-in-detached-document.html new file mode 100644 index 00000000000..6c139aa0751 --- /dev/null +++ b/Tests/LibWeb/Text/input/CSSOMView/getClientRects-in-detached-document.html @@ -0,0 +1,16 @@ + + diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index f9d034dea12..c453692eaed 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -949,7 +949,9 @@ JS::NonnullGCPtr Element::get_bounding_client_rect() const // https://drafts.csswg.org/cssom-view/#dom-element-getclientrects JS::NonnullGCPtr Element::get_client_rects() const { - Vector> rects; + auto navigable = document().navigable(); + if (!navigable) + return Geometry::DOMRectList::create(realm(), {}); // NOTE: Ensure that layout is up-to-date before looking at metrics. const_cast(document()).update_layout(); @@ -957,7 +959,7 @@ JS::NonnullGCPtr Element::get_client_rects() const // 1. If the element on which it was invoked does not have an associated layout box return an empty DOMRectList // object and stop this algorithm. if (!layout_node()) - return Geometry::DOMRectList::create(realm(), move(rects)); + return Geometry::DOMRectList::create(realm(), {}); // FIXME: 2. If the element has an associated SVG layout box return a DOMRectList object containing a single // DOMRect object that describes the bounding box of the element as defined by the SVG specification, @@ -970,9 +972,6 @@ JS::NonnullGCPtr Element::get_client_rects() const // 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 // are left in the final list. - const_cast(document()).update_layout(); - auto navigable = document().navigable(); - VERIFY(navigable); auto viewport_offset = navigable->viewport_scroll_offset(); // NOTE: Make sure CSS transforms are resolved before it is used to calculate the rect position. @@ -982,6 +981,7 @@ JS::NonnullGCPtr Element::get_client_rects() const CSSPixelPoint scroll_offset; auto const* paintable = this->paintable(); + Vector> rects; if (auto const* paintable_box = this->paintable_box()) { transform = Gfx::extract_2d_affine_transform(paintable_box->transform()); for (auto const* containing_block = paintable->containing_block(); !containing_block->is_viewport(); containing_block = containing_block->containing_block()) {