From c333042e630a225e726bce5c4978e6705b6d429d Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 5 Mar 2025 20:50:05 +0100 Subject: [PATCH] LibWeb: Add opt-in tracing of update_layout() calls with reason --- AK/Debug.h.in | 4 ++ Libraries/LibWeb/CSS/MediaQueryList.cpp | 2 +- .../CSS/ResolvedCSSStyleDeclaration.cpp | 2 +- Libraries/LibWeb/DOM/Document.cpp | 36 ++++++++--- Libraries/LibWeb/DOM/Document.h | 60 ++++++++++++++++++- Libraries/LibWeb/DOM/Element.cpp | 30 +++++----- Libraries/LibWeb/DOM/Node.cpp | 2 +- Libraries/LibWeb/DOM/Range.cpp | 2 +- .../LibWeb/HTML/CanvasRenderingContext2D.cpp | 2 +- Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp | 2 +- Libraries/LibWeb/HTML/HTMLElement.cpp | 12 ++-- Libraries/LibWeb/HTML/HTMLImageElement.cpp | 4 +- Libraries/LibWeb/HTML/HTMLInputElement.cpp | 4 +- Libraries/LibWeb/HTML/SourceSet.cpp | 2 +- Libraries/LibWeb/HTML/Window.cpp | 2 +- Libraries/LibWeb/Internals/Internals.cpp | 2 +- Libraries/LibWeb/Page/EventHandler.cpp | 12 ++-- Libraries/LibWeb/SVG/SVGDecodedImageData.cpp | 2 +- Libraries/LibWeb/SVG/SVGGraphicsElement.cpp | 2 +- Meta/CMake/all_the_debug_macros.cmake | 1 + Services/WebContent/ConnectionFromClient.cpp | 4 +- 21 files changed, 137 insertions(+), 52 deletions(-) diff --git a/AK/Debug.h.in b/AK/Debug.h.in index f661e850bef..2d94636b223 100644 --- a/AK/Debug.h.in +++ b/AK/Debug.h.in @@ -254,6 +254,10 @@ # cmakedefine01 TOKENIZER_TRACE_DEBUG #endif +#ifndef UPDATE_LAYOUT_DEBUG +# cmakedefine01 UPDATE_LAYOUT_DEBUG +#endif + #ifndef URL_PARSER_DEBUG # cmakedefine01 URL_PARSER_DEBUG #endif diff --git a/Libraries/LibWeb/CSS/MediaQueryList.cpp b/Libraries/LibWeb/CSS/MediaQueryList.cpp index eff66cc109e..de3acc23795 100644 --- a/Libraries/LibWeb/CSS/MediaQueryList.cpp +++ b/Libraries/LibWeb/CSS/MediaQueryList.cpp @@ -65,7 +65,7 @@ bool MediaQueryList::matches() const // NOTE: If our document is inside a frame, we need to update layout // since that may cause our frame (and thus viewport) to resize. if (auto container_document = m_document->container_document()) { - container_document->update_layout(); + container_document->update_layout(DOM::UpdateLayoutReason::MediaQueryListMatches); const_cast(this)->evaluate(); } diff --git a/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp b/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp index 5d8d2d314d4..afe377992ce 100644 --- a/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp +++ b/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp @@ -513,7 +513,7 @@ Optional ResolvedCSSStyleDeclaration::property(PropertyID propert // We may legitimately have no layout node if we're not visible, but this protects against situations // where we're requesting the computed style before layout has happened. if (!layout_node || property_affects_layout(property_id)) { - const_cast(m_element->document()).update_layout(); + const_cast(m_element->document()).update_layout(DOM::UpdateLayoutReason::ResolvedCSSStyleDeclarationProperty); layout_node = get_layout_node(); } else { // FIXME: If we had a way to update style for a single element, this would be a good place to use it. diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index b00b05d38a4..d94e72c3605 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -458,7 +458,7 @@ Document::Document(JS::Realm& realm, const URL::URL& url, TemporaryDocumentForFr if (!navigable || !navigable->is_focused()) return; - node->document().update_layout(); + node->document().update_layout(UpdateLayoutReason::CursorBlinkTimer); if (node->paintable()) { m_cursor_blink_state = !m_cursor_blink_state; @@ -1278,7 +1278,7 @@ static void propagate_overflow_to_viewport(Element& root_element, Layout::Viewpo overflow_origin_computed_values.set_overflow_y(CSS::Overflow::Visible); } -void Document::update_layout() +void Document::update_layout(UpdateLayoutReason reason) { auto navigable = this->navigable(); if (!navigable || navigable->active_document() != this) @@ -1287,7 +1287,7 @@ void Document::update_layout() // NOTE: If our parent document needs a relayout, we must do that *first*. // This is necessary as the parent layout may cause our viewport to change. if (navigable->container() && &navigable->container()->document() != this) - navigable->container()->document().update_layout(); + navigable->container()->document().update_layout(reason); update_style(); @@ -1303,6 +1303,8 @@ void Document::update_layout() auto* document_element = this->document_element(); auto viewport_rect = navigable->viewport_rect(); + auto timer = Core::ElapsedTimer::start_new(Core::TimerType::Precise); + if (!m_layout_root || needs_layout_tree_update() || child_needs_layout_tree_update() || needs_full_layout_tree_update()) { Layout::TreeBuilder tree_builder; m_layout_root = as(*tree_builder.build(*this)); @@ -1313,6 +1315,10 @@ void Document::update_layout() } set_needs_full_layout_tree_update(false); + + if constexpr (UPDATE_LAYOUT_DEBUG) { + dbgln("TREEBUILD {} µs", timer.elapsed_time().to_microseconds()); + } } // Assign each box that establishes a formatting context a list of absolutely positioned children it should take care of during layout @@ -1388,6 +1394,10 @@ void Document::update_layout() // after the viewport size change. if (auto window = this->window()) window->scroll_by(0, 0); + + if constexpr (UPDATE_LAYOUT_DEBUG) { + dbgln("LAYOUT {} {} µs", to_string(reason), timer.elapsed_time().to_microseconds()); + } } [[nodiscard]] static CSS::RequiredInvalidationAfterStyleChange update_style_recursively(Node& node, CSS::StyleComputer& style_computer, bool needs_inherited_style_update) @@ -5405,7 +5415,7 @@ WebIDL::ExceptionOr Document::set_design_mode(String const& design_mode) if (auto active_range = selection->range(); active_range) { TRY(active_range->set_start(*this, 0)); TRY(active_range->set_end(*this, 0)); - update_layout(); + update_layout(UpdateLayoutReason::DocumentSetDesignMode); } } // 3. Run the focusing steps for this's document element, if non-null. @@ -5432,7 +5442,7 @@ Element const* Document::element_from_point(double x, double y) return nullptr; // Ensure the layout tree exists prior to hit testing. - update_layout(); + update_layout(UpdateLayoutReason::DocumentElementFromPoint); // 2. If there is a box in the viewport that would be a target for hit testing at coordinates x,y, when applying the transforms // that apply to the descendants of the viewport, return the associated element and terminate these steps. @@ -5474,7 +5484,7 @@ GC::RootVector> Document::elements_from_point(double x, double return sequence; // Ensure the layout tree exists prior to hit testing. - update_layout(); + update_layout(UpdateLayoutReason::DocumentElementsFromPoint); // 3. For each box in the viewport, in paint order, starting with the topmost box, that would be a target for // hit testing at coordinates x,y even if nothing would be overlapping it, when applying the transforms that @@ -6002,7 +6012,7 @@ void Document::set_needs_to_refresh_scroll_state(bool b) Vector> Document::find_matching_text(String const& query, CaseSensitivity case_sensitivity) { // Ensure the layout tree exists before searching for text matches. - update_layout(); + update_layout(UpdateLayoutReason::DocumentFindMatchingText); if (!layout_node()) return {}; @@ -6393,4 +6403,16 @@ void Document::set_onvisibilitychange(WebIDL::CallbackType* value) set_event_handler_attribute(HTML::EventNames::visibilitychange, value); } +StringView to_string(UpdateLayoutReason reason) +{ + switch (reason) { +#define ENUMERATE_UPDATE_LAYOUT_REASON(e) \ + case UpdateLayoutReason::e: \ + return #e##sv; + ENUMERATE_UPDATE_LAYOUT_REASONS(ENUMERATE_UPDATE_LAYOUT_REASON) +#undef ENUMERATE_UPDATE_LAYOUT_REASON + } + VERIFY_NOT_REACHED(); +} + } diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index 2badbcc273c..a9e4be402e0 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -50,6 +50,64 @@ enum class QuirksMode { Yes }; +#define ENUMERATE_UPDATE_LAYOUT_REASONS(X) \ + X(CanvasRenderingContext2DSetFilter) \ + X(CursorBlinkTimer) \ + X(Debugging) \ + X(DocumentElementFromPoint) \ + X(DocumentElementsFromPoint) \ + X(DocumentFindMatchingText) \ + X(DocumentSetDesignMode) \ + X(ElementCheckVisibility) \ + X(ElementClientHeight) \ + X(ElementClientLeft) \ + X(ElementClientTop) \ + X(ElementClientWidth) \ + X(ElementGetClientRects) \ + X(ElementIsPotentiallyScrollable) \ + X(ElementScroll) \ + X(ElementScrollHeight) \ + X(ElementScrollIntoView) \ + X(ElementScrollLeft) \ + X(ElementScrollTop) \ + X(ElementScrollWidth) \ + X(ElementSetScrollLeft) \ + X(ElementSetScrollTop) \ + X(EventHandlerHandleDoubleClick) \ + X(EventHandlerHandleDragAndDrop) \ + X(EventHandlerHandleMouseDown) \ + X(EventHandlerHandleMouseMove) \ + X(EventHandlerHandleMouseUp) \ + X(EventHandlerHandleMouseWheel) \ + X(HTMLElementGetTheTextSteps) \ + X(HTMLElementOffsetHeight) \ + X(HTMLElementOffsetLeft) \ + X(HTMLElementOffsetParent) \ + X(HTMLElementOffsetTop) \ + X(HTMLElementOffsetWidth) \ + X(HTMLEventLoopRenderingUpdate) \ + X(HTMLImageElementHeight) \ + X(HTMLImageElementWidth) \ + X(HTMLInputElementHeight) \ + X(HTMLInputElementWidth) \ + X(InternalsHitTest) \ + X(MediaQueryListMatches) \ + X(NodeNameOrDescription) \ + X(RangeGetClientRects) \ + X(ResolvedCSSStyleDeclarationProperty) \ + X(SVGDecodedImageDataRender) \ + X(SVGGraphicsElementGetBBox) \ + X(SourceSetNormalizeSourceDensities) \ + X(WindowScroll) + +enum class UpdateLayoutReason { +#define ENUMERATE_UPDATE_LAYOUT_REASON(e) e, + ENUMERATE_UPDATE_LAYOUT_REASONS(ENUMERATE_UPDATE_LAYOUT_REASON) +#undef ENUMERATE_UPDATE_LAYOUT_REASON +}; + +[[nodiscard]] StringView to_string(UpdateLayoutReason); + // https://html.spec.whatwg.org/multipage/dom.html#document-load-timing-info struct DocumentLoadTimingInfo { // https://html.spec.whatwg.org/multipage/dom.html#navigation-start-time @@ -258,7 +316,7 @@ public: void obtain_theme_color(); void update_style(); - void update_layout(); + void update_layout(UpdateLayoutReason); void update_paint_and_hit_testing_properties_if_needed(); void update_animated_style_if_needed(); diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index 2c7b85805a7..92600d89849 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -994,7 +994,7 @@ GC::Ref Element::get_client_rects() const return Geometry::DOMRectList::create(realm(), {}); // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document()).update_layout(); + const_cast(document()).update_layout(UpdateLayoutReason::ElementGetClientRects); // 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. @@ -1047,7 +1047,7 @@ GC::Ref Element::get_client_rects() const int Element::client_top() const { // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document()).update_layout(); + const_cast(document()).update_layout(UpdateLayoutReason::ElementClientTop); // 1. If the element has no associated CSS layout box or if the CSS layout box is inline, return zero. if (!paintable_box()) @@ -1063,7 +1063,7 @@ int Element::client_top() const int Element::client_left() const { // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document()).update_layout(); + const_cast(document()).update_layout(UpdateLayoutReason::ElementClientLeft); // 1. If the element has no associated CSS layout box or if the CSS layout box is inline, return zero. if (!paintable_box()) @@ -1089,7 +1089,7 @@ int Element::client_width() const } // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document()).update_layout(); + const_cast(document()).update_layout(UpdateLayoutReason::ElementClientWidth); // 1. If the element has no associated CSS layout box or if the CSS layout box is inline, return zero. if (!paintable_box()) @@ -1114,7 +1114,7 @@ int Element::client_height() const } // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document()).update_layout(); + const_cast(document()).update_layout(UpdateLayoutReason::ElementClientHeight); // 1. If the element has no associated CSS layout box or if the CSS layout box is inline, return zero. if (!paintable_box()) @@ -1420,7 +1420,7 @@ void Element::set_tab_index(i32 tab_index) bool Element::is_potentially_scrollable() const { // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document()).update_layout(); + const_cast(document()).update_layout(UpdateLayoutReason::ElementIsPotentiallyScrollable); // An element body (which will be the body element) is potentially scrollable if all of the following conditions are true: VERIFY(is(this) || is(this)); @@ -1466,7 +1466,7 @@ double Element::scroll_top() const return window->scroll_y(); // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document).update_layout(); + const_cast(document).update_layout(UpdateLayoutReason::ElementScrollTop); // 7. If the element is the body element, document is in quirks mode, and the element is not potentially scrollable, return the value of scrollY on window. if (document.body() == this && document.in_quirks_mode() && !is_potentially_scrollable()) @@ -1508,7 +1508,7 @@ double Element::scroll_left() const return window->scroll_x(); // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document).update_layout(); + const_cast(document).update_layout(UpdateLayoutReason::ElementScrollLeft); // 7. If the element is the body element, document is in quirks mode, and the element is not potentially scrollable, return the value of scrollX on window. if (document.body() == this && document.in_quirks_mode() && !is_potentially_scrollable()) @@ -1557,7 +1557,7 @@ void Element::set_scroll_left(double x) } // NOTE: Ensure that layout is up-to-date before looking at metrics or scrolling the page. - const_cast(document).update_layout(); + const_cast(document).update_layout(UpdateLayoutReason::ElementSetScrollLeft); // 9. If the element is the body element, document is in quirks mode, and the element is not potentially scrollable, invoke scroll() on window with x as first argument and scrollY on window as second argument, and terminate these steps. if (document.body() == this && document.in_quirks_mode() && !is_potentially_scrollable()) { @@ -1614,7 +1614,7 @@ void Element::set_scroll_top(double y) } // NOTE: Ensure that layout is up-to-date before looking at metrics or scrolling the page. - const_cast(document).update_layout(); + const_cast(document).update_layout(UpdateLayoutReason::ElementSetScrollTop); // 9. If the element is the body element, document is in quirks mode, and the element is not potentially scrollable, invoke scroll() on window with scrollX as first argument and y as second argument, and terminate these steps. if (document.body() == this && document.in_quirks_mode() && !is_potentially_scrollable()) { @@ -1659,7 +1659,7 @@ int Element::scroll_width() const return max(viewport_scroll_width, viewport_width); // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document).update_layout(); + const_cast(document).update_layout(UpdateLayoutReason::ElementScrollWidth); // 5. If the element is the body element, document is in quirks mode and the element is not potentially scrollable, // return max(viewport scrolling area width, viewport width). @@ -1698,7 +1698,7 @@ int Element::scroll_height() const return max(viewport_scroll_height, viewport_height); // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document).update_layout(); + const_cast(document).update_layout(UpdateLayoutReason::ElementScrollHeight); // 5. If the element is the body element, document is in quirks mode and the element is not potentially scrollable, // return max(viewport scrolling area height, viewport height). @@ -2180,7 +2180,7 @@ ErrorOr Element::scroll_into_view(Optional options) { // NOTE: Ensure that layout is up-to-date before looking at metrics. - document().update_layout(); + document().update_layout(UpdateLayoutReason::ElementCheckVisibility); // 1. If this does not have an associated box, return false. if (!paintable_box()) diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index 9e240fc5934..588e20897f9 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -2745,7 +2745,7 @@ ErrorOr Node::name_or_description(NameOrDescription target, Document con if (!child_node->is_element() && !child_node->is_text()) continue; bool should_add_space = true; - const_cast(document).update_layout(); + const_cast(document).update_layout(DOM::UpdateLayoutReason::NodeNameOrDescription); auto const* layout_node = child_node->layout_node(); if (layout_node) { auto display = layout_node->display(); diff --git a/Libraries/LibWeb/DOM/Range.cpp b/Libraries/LibWeb/DOM/Range.cpp index 4050e3bea7b..98a73eef119 100644 --- a/Libraries/LibWeb/DOM/Range.cpp +++ b/Libraries/LibWeb/DOM/Range.cpp @@ -1157,7 +1157,7 @@ GC::Ref Range::get_client_rects() if (!start_container()->document().navigable()) return Geometry::DOMRectList::create(realm(), {}); - start_container()->document().update_layout(); + start_container()->document().update_layout(DOM::UpdateLayoutReason::RangeGetClientRects); update_associated_selection(); Vector> rects; // FIXME: take Range collapsed into consideration diff --git a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index e76cc69aeaf..ccdaf0a72a1 100644 --- a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -962,7 +962,7 @@ void CanvasRenderingContext2D::set_filter(String filter) drawing_state().filters.grow_capacity(filter_value_list.size()); // Note: The layout must be updated to make sure the canvas's layout node isn't null. - canvas_element().document().update_layout(); + canvas_element().document().update_layout(DOM::UpdateLayoutReason::CanvasRenderingContext2DSetFilter); auto layout_node = canvas_element().layout_node(); // 4. Set this's current filter to the given value. diff --git a/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp b/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp index a9ecd1c1087..a22f5454de5 100644 --- a/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp +++ b/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp @@ -400,7 +400,7 @@ void EventLoop::update_the_rendering() while (true) { // 1. Recalculate styles and update layout for doc. // NOTE: Recalculation of styles is handled by update_layout() - document->update_layout(); + document->update_layout(DOM::UpdateLayoutReason::HTMLEventLoopRenderingUpdate); // 2. Let hadInitialVisibleContentVisibilityDetermination be false. bool had_initial_visible_content_visibility_determination = false; diff --git a/Libraries/LibWeb/HTML/HTMLElement.cpp b/Libraries/LibWeb/HTML/HTMLElement.cpp index ffe81f37f65..188743b00c5 100644 --- a/Libraries/LibWeb/HTML/HTMLElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLElement.cpp @@ -368,7 +368,7 @@ static Vector> rendered_text_collection_ String HTMLElement::get_the_text_steps() { // 1. If element is not being rendered or if the user agent is a non-CSS user agent, then return element's descendant text content. - document().update_layout(); + document().update_layout(DOM::UpdateLayoutReason::HTMLElementGetTheTextSteps); if (!layout_node()) return descendant_text_content(); @@ -444,7 +444,7 @@ String HTMLElement::outer_text() // https://www.w3.org/TR/cssom-view-1/#dom-htmlelement-offsetparent GC::Ptr HTMLElement::offset_parent() const { - const_cast(document()).update_layout(); + const_cast(document()).update_layout(DOM::UpdateLayoutReason::HTMLElementOffsetParent); // 1. If any of the following holds true return null and terminate this algorithm: // - The element does not have an associated CSS layout box. @@ -491,7 +491,7 @@ int HTMLElement::offset_top() const return 0; // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document()).update_layout(); + const_cast(document()).update_layout(DOM::UpdateLayoutReason::HTMLElementOffsetTop); if (!paintable_box()) return 0; @@ -533,7 +533,7 @@ int HTMLElement::offset_left() const return 0; // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document()).update_layout(); + const_cast(document()).update_layout(DOM::UpdateLayoutReason::HTMLElementOffsetLeft); if (!paintable_box()) return 0; @@ -571,7 +571,7 @@ int HTMLElement::offset_left() const int HTMLElement::offset_width() const { // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document()).update_layout(); + const_cast(document()).update_layout(DOM::UpdateLayoutReason::HTMLElementOffsetWidth); // 1. If the element does not have any associated box return zero and terminate this algorithm. auto const* box = paintable_box(); @@ -590,7 +590,7 @@ int HTMLElement::offset_width() const int HTMLElement::offset_height() const { // NOTE: Ensure that layout is up-to-date before looking at metrics. - const_cast(document()).update_layout(); + const_cast(document()).update_layout(DOM::UpdateLayoutReason::HTMLElementOffsetHeight); // 1. If the element does not have any associated box return zero and terminate this algorithm. auto const* box = paintable_box(); diff --git a/Libraries/LibWeb/HTML/HTMLImageElement.cpp b/Libraries/LibWeb/HTML/HTMLImageElement.cpp index 3fbdb14651f..29eaf73e522 100644 --- a/Libraries/LibWeb/HTML/HTMLImageElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLImageElement.cpp @@ -204,7 +204,7 @@ void HTMLImageElement::set_visible_in_viewport(bool) // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-width WebIDL::UnsignedLong HTMLImageElement::width() const { - const_cast(document()).update_layout(); + const_cast(document()).update_layout(DOM::UpdateLayoutReason::HTMLImageElementWidth); // Return the rendered width of the image, in CSS pixels, if the image is being rendered. if (auto* paintable_box = this->paintable_box()) @@ -235,7 +235,7 @@ WebIDL::ExceptionOr HTMLImageElement::set_width(WebIDL::UnsignedLong width // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-height WebIDL::UnsignedLong HTMLImageElement::height() const { - const_cast(document()).update_layout(); + const_cast(document()).update_layout(DOM::UpdateLayoutReason::HTMLImageElementHeight); // Return the rendered height of the image, in CSS pixels, if the image is being rendered. if (auto* paintable_box = this->paintable_box()) diff --git a/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Libraries/LibWeb/HTML/HTMLInputElement.cpp index de894d89be0..2480d631bed 100644 --- a/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -2029,7 +2029,7 @@ WebIDL::ExceptionOr HTMLInputElement::set_size(WebIDL::UnsignedLong value) // https://html.spec.whatwg.org/multipage/input.html#dom-input-height WebIDL::UnsignedLong HTMLInputElement::height() const { - const_cast(document()).update_layout(); + const_cast(document()).update_layout(DOM::UpdateLayoutReason::HTMLInputElementHeight); // When the input element's type attribute is not in the Image Button state, then no image is available. if (type_state() != TypeAttributeState::ImageButton) @@ -2064,7 +2064,7 @@ WebIDL::ExceptionOr HTMLInputElement::set_height(WebIDL::UnsignedLong valu // https://html.spec.whatwg.org/multipage/input.html#dom-input-width WebIDL::UnsignedLong HTMLInputElement::width() const { - const_cast(document()).update_layout(); + const_cast(document()).update_layout(DOM::UpdateLayoutReason::HTMLInputElementWidth); // When the input element's type attribute is not in the Image Button state, then no image is available. if (type_state() != TypeAttributeState::ImageButton) diff --git a/Libraries/LibWeb/HTML/SourceSet.cpp b/Libraries/LibWeb/HTML/SourceSet.cpp index 570908df430..f4ecc14d1f6 100644 --- a/Libraries/LibWeb/HTML/SourceSet.cpp +++ b/Libraries/LibWeb/HTML/SourceSet.cpp @@ -402,7 +402,7 @@ void SourceSet::normalize_source_densities(DOM::Element const& element) // HACK: Flush any pending layouts here so we get an up-to-date length resolution context. // FIXME: We should have a way to build a LengthResolutionContext for any DOM node without going through the layout tree. - const_cast(element.document()).update_layout(); + const_cast(element.document()).update_layout(DOM::UpdateLayoutReason::SourceSetNormalizeSourceDensities); if (element.layout_node()) { CSS::CalculationResolutionContext context { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*element.layout_node()) }; return m_source_size.resolved(context).value_or(CSS::Length::make_auto()); diff --git a/Libraries/LibWeb/HTML/Window.cpp b/Libraries/LibWeb/HTML/Window.cpp index 7e49b592e73..98398578c71 100644 --- a/Libraries/LibWeb/HTML/Window.cpp +++ b/Libraries/LibWeb/HTML/Window.cpp @@ -1422,7 +1422,7 @@ void Window::scroll(ScrollToOptions const& options) VERIFY(document); // Make sure layout is up-to-date before looking at scrollable overflow metrics. - document->update_layout(); + document->update_layout(DOM::UpdateLayoutReason::WindowScroll); VERIFY(document->paintable_box()); auto scrolling_area = document->paintable_box()->scrollable_overflow_rect()->to_type(); diff --git a/Libraries/LibWeb/Internals/Internals.cpp b/Libraries/LibWeb/Internals/Internals.cpp index 0e205a7a8cd..88defe719c7 100644 --- a/Libraries/LibWeb/Internals/Internals.cpp +++ b/Libraries/LibWeb/Internals/Internals.cpp @@ -69,7 +69,7 @@ JS::Object* Internals::hit_test(double x, double y) // NOTE: Force a layout update just before hit testing. This is because the current layout tree, which is required // for stacking context traversal, might not exist if this call occurs between the tear_down_layout_tree() // and update_layout() calls - active_document.update_layout(); + active_document.update_layout(DOM::UpdateLayoutReason::InternalsHitTest); auto result = active_document.paintable_box()->hit_test({ x, y }, Painting::HitTestType::Exact); if (result.has_value()) { auto hit_tеsting_result = JS::Object::create(realm(), nullptr); diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp index dc70e97e3db..4b6b126cf62 100644 --- a/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -365,7 +365,7 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS if (!m_navigable->active_document()->is_fully_active()) return EventResult::Dropped; - m_navigable->active_document()->update_layout(); + m_navigable->active_document()->update_layout(DOM::UpdateLayoutReason::EventHandlerHandleMouseWheel); if (!paint_root()) return EventResult::Dropped; @@ -431,7 +431,7 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix if (!m_navigable->active_document()->is_fully_active()) return EventResult::Dropped; - m_navigable->active_document()->update_layout(); + m_navigable->active_document()->update_layout(DOM::UpdateLayoutReason::EventHandlerHandleMouseUp); if (!paint_root()) return EventResult::Dropped; @@ -575,7 +575,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP if (!m_navigable->active_document()->is_fully_active()) return EventResult::Dropped; - m_navigable->active_document()->update_layout(); + m_navigable->active_document()->update_layout(DOM::UpdateLayoutReason::EventHandlerHandleMouseDown); if (!paint_root()) return EventResult::Dropped; @@ -699,7 +699,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP if (!m_navigable->active_document()->is_fully_active()) return EventResult::Dropped; - m_navigable->active_document()->update_layout(); + m_navigable->active_document()->update_layout(DOM::UpdateLayoutReason::EventHandlerHandleMouseMove); if (!paint_root()) return EventResult::Dropped; @@ -846,7 +846,7 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS auto& document = *m_navigable->active_document(); - document.update_layout(); + document.update_layout(DOM::UpdateLayoutReason::EventHandlerHandleDoubleClick); if (!paint_root()) return EventResult::Dropped; @@ -924,7 +924,7 @@ EventResult EventHandler::handle_drag_and_drop_event(DragEvent::Type type, CSSPi return EventResult::Dropped; auto& document = *m_navigable->active_document(); - document.update_layout(); + document.update_layout(DOM::UpdateLayoutReason::EventHandlerHandleDragAndDrop); if (!paint_root()) return EventResult::Dropped; diff --git a/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp b/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp index bced5f35736..d7cd6fa9d34 100644 --- a/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp +++ b/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp @@ -94,7 +94,7 @@ RefPtr SVGDecodedImageData::render(Gfx::IntSize size) const auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied, size).release_value_but_fixme_should_propagate_errors(); VERIFY(m_document->navigable()); m_document->navigable()->set_viewport_size(size.to_type()); - m_document->update_layout(); + m_document->update_layout(DOM::UpdateLayoutReason::SVGDecodedImageDataRender); auto display_list = m_document->record_display_list({}); if (!display_list) diff --git a/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp b/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp index a814961fba7..aa0aa49163e 100644 --- a/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp +++ b/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp @@ -362,7 +362,7 @@ GC::Ref SVGGraphicsElement::get_b_box(Optional(document()).update_layout(); + const_cast(document()).update_layout(DOM::UpdateLayoutReason::SVGGraphicsElementGetBBox); if (!layout_node()) return Geometry::DOMRect::create(realm()); // Invert the SVG -> screen space transform. diff --git a/Meta/CMake/all_the_debug_macros.cmake b/Meta/CMake/all_the_debug_macros.cmake index 6fccf30c0c8..c0b3389bd2c 100644 --- a/Meta/CMake/all_the_debug_macros.cmake +++ b/Meta/CMake/all_the_debug_macros.cmake @@ -59,6 +59,7 @@ set(TIFF_DEBUG ON) set(TIME_ZONE_DEBUG ON) set(TLS_DEBUG ON) set(TOKENIZER_TRACE_DEBUG ON) +set(UPDATE_LAYOUT_DEBUG ON) set(URL_PARSER_DEBUG ON) set(UTF8_DEBUG ON) set(VPX_DEBUG ON) diff --git a/Services/WebContent/ConnectionFromClient.cpp b/Services/WebContent/ConnectionFromClient.cpp index aa624802dbb..be2a780433a 100644 --- a/Services/WebContent/ConnectionFromClient.cpp +++ b/Services/WebContent/ConnectionFromClient.cpp @@ -886,7 +886,7 @@ static void append_layout_tree(Web::Page& page, StringBuilder& builder) return; } - document->update_layout(); + document->update_layout(Web::DOM::UpdateLayoutReason::Debugging); auto* layout_root = document->layout_node(); if (!layout_root) { @@ -905,7 +905,7 @@ static void append_paint_tree(Web::Page& page, StringBuilder& builder) return; } - document->update_layout(); + document->update_layout(Web::DOM::UpdateLayoutReason::Debugging); auto* layout_root = document->layout_node(); if (!layout_root) {