LibWeb: Collect layout inspection data only when DevTools is connected
Grid and flex inspector payloads are only consumed by DevTools, but layout currently builds them for every page. Gate that collection on an active DevTools client so ordinary browsing avoids the extra CPU work and retained memory. DevTools may connect after the page has already completed layout, so force one catch-up layout pass when the first DevTools client attaches. After that, normal relayouts keep the data fresh until DevTools disconnects. Inspection requests only flush dirty layout instead of forcing repeated collection passes. When DevTools detaches, clear the stored inspection data and overlays.
This commit is contained in:
parent
8c60d20dfc
commit
26fdc5c09d
9 changed files with 75 additions and 12 deletions
|
|
@ -1779,7 +1779,11 @@ void Document::update_layout(UpdateLayoutReason reason)
|
|||
for (size_t layout_pass = 0; layout_pass < max_container_query_layout_passes; ++layout_pass) {
|
||||
update_style();
|
||||
|
||||
if (layout_is_up_to_date())
|
||||
auto const should_collect_devtools_layout_data = page().client().has_active_devtools_client();
|
||||
auto const force_devtools_layout_data_collection = should_collect_devtools_layout_data
|
||||
&& reason == UpdateLayoutReason::InspectDevToolsLayoutData;
|
||||
|
||||
if (layout_is_up_to_date() && !force_devtools_layout_data_collection)
|
||||
return;
|
||||
|
||||
auto svg_roots_to_relayout = move(m_svg_roots_needing_relayout);
|
||||
|
|
@ -1866,6 +1870,7 @@ void Document::update_layout(UpdateLayoutReason reason)
|
|||
|
||||
Layout::LayoutState layout_state;
|
||||
layout_state.ensure_capacity(layout_index_counter);
|
||||
layout_state.set_should_collect_devtools_layout_data(should_collect_devtools_layout_data);
|
||||
|
||||
{
|
||||
auto& viewport = static_cast<Layout::Viewport&>(*m_layout_root);
|
||||
|
|
@ -1963,6 +1968,22 @@ void Document::update_layout(UpdateLayoutReason reason)
|
|||
VERIFY(layout_is_up_to_date());
|
||||
}
|
||||
|
||||
void Document::clear_devtools_layout_inspection_data()
|
||||
{
|
||||
clear_grid_highlighted_node(nullptr);
|
||||
clear_flexbox_highlighted_node(nullptr);
|
||||
|
||||
auto paintable = this->paintable();
|
||||
if (!paintable)
|
||||
return;
|
||||
|
||||
paintable->for_each_in_subtree_of_type<Painting::PaintableBox>([](auto& paintable_box) {
|
||||
paintable_box.set_grid_layout_data(nullptr);
|
||||
paintable_box.set_flex_layout_data(nullptr);
|
||||
return TraversalDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
bool Document::layout_is_up_to_date() const
|
||||
{
|
||||
if (!navigable() || navigable()->active_document() != this)
|
||||
|
|
|
|||
|
|
@ -126,8 +126,7 @@ enum class InvalidateLayoutTreeReason {
|
|||
X(HostedDocumentBeforePaint) \
|
||||
X(InspectAccessibilityTree) \
|
||||
X(InspectDOMTree) \
|
||||
X(InspectFlexboxLayout) \
|
||||
X(InspectGridLayout) \
|
||||
X(InspectDevToolsLayoutData) \
|
||||
X(InternalsHitTest) \
|
||||
X(MediaQueryListMatches) \
|
||||
X(NavigableSelectedText) \
|
||||
|
|
@ -400,6 +399,7 @@ public:
|
|||
void update_layout(UpdateLayoutReason);
|
||||
void update_layout_if_needed_for_node(Node const&, UpdateLayoutReason);
|
||||
[[nodiscard]] bool layout_is_up_to_date() const;
|
||||
void clear_devtools_layout_inspection_data();
|
||||
void update_paint_and_hit_testing_properties_if_needed();
|
||||
void update_animated_style_if_needed();
|
||||
|
||||
|
|
|
|||
|
|
@ -247,7 +247,8 @@ void FlexFormattingContext::run(AvailableSpace const& available_space)
|
|||
resolve_baseline_aligned_items();
|
||||
}
|
||||
|
||||
save_flex_layout_data();
|
||||
if (m_state.should_collect_devtools_layout_data())
|
||||
save_flex_layout_data();
|
||||
}
|
||||
|
||||
void FlexFormattingContext::parent_context_did_dimension_child_root_box()
|
||||
|
|
|
|||
|
|
@ -2420,6 +2420,9 @@ void GridFormattingContext::resolve_track_spacing(GridDimension dimension)
|
|||
|
||||
void GridFormattingContext::save_grid_layout_data()
|
||||
{
|
||||
if (!m_state.should_collect_devtools_layout_data())
|
||||
return;
|
||||
|
||||
auto data = make<GridLayoutData>();
|
||||
data->direction = grid_container().computed_values().direction();
|
||||
data->is_subgrid = is_subgridded_axis(GridDimension::Column) || is_subgridded_axis(GridDimension::Row);
|
||||
|
|
|
|||
|
|
@ -392,6 +392,9 @@ struct LayoutState {
|
|||
|
||||
void ensure_capacity(u32 node_count);
|
||||
|
||||
void set_should_collect_devtools_layout_data(bool should_collect) { m_should_collect_devtools_layout_data = should_collect; }
|
||||
bool should_collect_devtools_layout_data() const { return m_should_collect_devtools_layout_data; }
|
||||
|
||||
UsedValues& get_mutable(NodeWithStyle const&);
|
||||
UsedValues const& get(NodeWithStyle const&) const;
|
||||
|
||||
|
|
@ -408,6 +411,7 @@ private:
|
|||
|
||||
PagedStore<UsedValues> m_used_values_store;
|
||||
GC::Ptr<Layout::NodeWithStyle const> m_subtree_root;
|
||||
bool m_should_collect_devtools_layout_data { false };
|
||||
};
|
||||
|
||||
inline CSSPixels clamp_to_max_dimension_value(CSSPixels value)
|
||||
|
|
|
|||
|
|
@ -414,6 +414,7 @@ public:
|
|||
virtual Page& page() = 0;
|
||||
virtual Page const& page() const = 0;
|
||||
virtual bool is_connection_open() const = 0;
|
||||
virtual bool has_active_devtools_client() const { return false; }
|
||||
virtual bool is_url_suitable_for_same_process_navigation([[maybe_unused]] URL::URL const& current_url, [[maybe_unused]] URL::URL const& target_url) const { return true; }
|
||||
virtual void request_new_process_for_navigation(URL::URL const&) { }
|
||||
virtual Gfx::Palette palette() const = 0;
|
||||
|
|
|
|||
|
|
@ -902,7 +902,7 @@ static void append_grid_layouts_for_node_and_frame_descendants(Web::DOM::Node& r
|
|||
if (!content_document->origin().is_same_origin_domain(navigable_container->document().origin()))
|
||||
return Web::TraversalDecision::Continue;
|
||||
|
||||
content_document->update_layout(Web::DOM::UpdateLayoutReason::InspectGridLayout);
|
||||
content_document->update_layout(Web::DOM::UpdateLayoutReason::Debugging);
|
||||
append_grid_layouts_for_node_and_frame_descendants(*content_document, grid_layouts);
|
||||
return Web::TraversalDecision::Continue;
|
||||
});
|
||||
|
|
@ -920,7 +920,7 @@ void ConnectionFromClient::inspect_grid_layouts(u64 page_id, Web::UniqueNodeID r
|
|||
return;
|
||||
}
|
||||
|
||||
root_node->document().update_layout(Web::DOM::UpdateLayoutReason::InspectGridLayout);
|
||||
root_node->document().update_layout(Web::DOM::UpdateLayoutReason::Debugging);
|
||||
|
||||
JsonArray grid_layouts;
|
||||
append_grid_layouts_for_node_and_frame_descendants(*root_node, grid_layouts);
|
||||
|
|
@ -940,7 +940,7 @@ void ConnectionFromClient::inspect_current_grid(u64 page_id, Web::UniqueNodeID n
|
|||
return;
|
||||
}
|
||||
|
||||
node->document().update_layout(Web::DOM::UpdateLayoutReason::InspectGridLayout);
|
||||
node->document().update_layout(Web::DOM::UpdateLayoutReason::Debugging);
|
||||
|
||||
for (auto const* current = node; current; current = current->parent_or_shadow_host_node()) {
|
||||
if (auto grid_layout = grid_layout_for_node(*current); grid_layout.has_value()) {
|
||||
|
|
@ -964,7 +964,7 @@ void ConnectionFromClient::inspect_current_flexbox(u64 page_id, Web::UniqueNodeI
|
|||
return;
|
||||
}
|
||||
|
||||
node->document().update_layout(Web::DOM::UpdateLayoutReason::InspectFlexboxLayout);
|
||||
node->document().update_layout(Web::DOM::UpdateLayoutReason::Debugging);
|
||||
|
||||
for (auto const* current = only_look_at_parents ? node->parent_or_shadow_host_node() : node; current; current = current->parent_or_shadow_host_node()) {
|
||||
if (auto flex_layout = flex_layout_for_node(*current); flex_layout.has_value()) {
|
||||
|
|
@ -1062,10 +1062,15 @@ void ConnectionFromClient::highlight_flexbox(u64 page_id, Web::UniqueNodeID node
|
|||
return;
|
||||
|
||||
auto* node = Web::DOM::Node::from_unique_id(node_id);
|
||||
if (!node || !node->layout_node())
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
node->document().set_flexbox_highlighted_node(node, flexbox_inspector_overlay_options_from_json(options));
|
||||
auto& document = node->document();
|
||||
document.update_layout(Web::DOM::UpdateLayoutReason::Debugging);
|
||||
if (!node->layout_node())
|
||||
return;
|
||||
|
||||
document.set_flexbox_highlighted_node(node, flexbox_inspector_overlay_options_from_json(options));
|
||||
}
|
||||
|
||||
void ConnectionFromClient::clear_flexbox_highlight(u64 page_id, Web::UniqueNodeID node_id)
|
||||
|
|
@ -1094,10 +1099,15 @@ void ConnectionFromClient::highlight_grid(u64 page_id, Web::UniqueNodeID node_id
|
|||
return;
|
||||
|
||||
auto* node = Web::DOM::Node::from_unique_id(node_id);
|
||||
if (!node || !node->layout_node())
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
node->document().set_grid_highlighted_node(node, grid_inspector_overlay_options_from_json(options));
|
||||
auto& document = node->document();
|
||||
document.update_layout(Web::DOM::UpdateLayoutReason::Debugging);
|
||||
if (!node->layout_node())
|
||||
return;
|
||||
|
||||
document.set_grid_highlighted_node(node, grid_inspector_overlay_options_from_json(options));
|
||||
}
|
||||
|
||||
void ConnectionFromClient::clear_grid_highlight(u64 page_id, Web::UniqueNodeID node_id)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <LibWeb/HTML/BrowsingContext.h>
|
||||
#include <LibWeb/HTML/EventLoop/EventLoop.h>
|
||||
#include <LibWeb/HTML/HTMLLinkElement.h>
|
||||
#include <LibWeb/HTML/Navigable.h>
|
||||
#include <LibWeb/HTML/Scripting/ClassicScript.h>
|
||||
#include <LibWeb/HTML/TraversableNavigable.h>
|
||||
#include <LibWeb/HighResolutionTime/TimeOrigin.h>
|
||||
|
|
@ -935,13 +936,34 @@ void PageClient::page_did_receive_network_response_body(u64 request_id, Readonly
|
|||
|
||||
void PageClient::did_connect_devtools_client()
|
||||
{
|
||||
auto was_first_devtools_client = !has_devtools_client();
|
||||
++m_devtools_client_count;
|
||||
|
||||
if (!was_first_devtools_client)
|
||||
return;
|
||||
|
||||
for (auto& navigable : Web::HTML::all_navigables()) {
|
||||
if (&navigable->page() != &page())
|
||||
continue;
|
||||
if (auto active_document = navigable->active_document())
|
||||
active_document->update_layout(Web::DOM::UpdateLayoutReason::InspectDevToolsLayoutData);
|
||||
}
|
||||
}
|
||||
|
||||
void PageClient::did_disconnect_devtools_client()
|
||||
{
|
||||
VERIFY(m_devtools_client_count > 0);
|
||||
--m_devtools_client_count;
|
||||
|
||||
if (has_devtools_client())
|
||||
return;
|
||||
|
||||
for (auto& navigable : Web::HTML::all_navigables()) {
|
||||
if (&navigable->page() != &page())
|
||||
continue;
|
||||
if (auto active_document = navigable->active_document())
|
||||
active_document->clear_devtools_layout_inspection_data();
|
||||
}
|
||||
}
|
||||
|
||||
void PageClient::page_did_finish_network_request(u64 request_id, u64 body_size, Requests::RequestTimingInfo const& timing_info, Optional<Requests::NetworkError> const& network_error)
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ public:
|
|||
void did_connect_devtools_client();
|
||||
void did_disconnect_devtools_client();
|
||||
bool has_devtools_client() const { return m_devtools_client_count > 0; }
|
||||
virtual bool has_active_devtools_client() const override { return has_devtools_client(); }
|
||||
|
||||
void initialize_js_console(Web::DOM::Document& document);
|
||||
void js_console_input(StringView js_source);
|
||||
|
|
|
|||
Loading…
Reference in a new issue