From 49a7a0f378ad9b29aefca3576f2fb5bdb193f98f Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 3 Jan 2025 14:46:24 +0100 Subject: [PATCH] LibWeb: Avoid invalidation on .textContent setter no-op When setting the textContent of an element with no children to null or the empty string, nothing happens. Even so, we were still invalidating style, layout and collections, causing pointless churn. Skipping invalidation in this case also revealed that we were missing invalidation when changing the selected state of HTMLOptionElement. This was all caught by existing tests already in-tree. :^) --- Libraries/LibWeb/DOM/Node.cpp | 4 ++++ Libraries/LibWeb/DOM/Node.h | 1 + Libraries/LibWeb/HTML/HTMLOptionElement.cpp | 3 +++ 3 files changed, 8 insertions(+) diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index c794c510325..40718469da4 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -202,6 +202,10 @@ void Node::set_text_content(Optional const& maybe_content) // If DocumentFragment or Element, string replace all with the given value within this. if (is(this) || is(this)) { + // OPTIMIZATION: Replacing nothing with nothing is a no-op. Avoid all invalidation in this case. + if (!first_child() && content.is_empty()) { + return; + } string_replace_all(content); } diff --git a/Libraries/LibWeb/DOM/Node.h b/Libraries/LibWeb/DOM/Node.h index 5b97aafe0bc..c2b6c796eca 100644 --- a/Libraries/LibWeb/DOM/Node.h +++ b/Libraries/LibWeb/DOM/Node.h @@ -74,6 +74,7 @@ enum class IsDescendant { X(HTMLIFrameElementGeometryChange) \ X(HTMLInputElementSetChecked) \ X(HTMLObjectElementUpdateLayoutAndChildObjects) \ + X(HTMLOptionElementSelectedChange) \ X(HTMLSelectElementSetIsOpen) \ X(Hover) \ X(MediaQueryChangedMatchState) \ diff --git a/Libraries/LibWeb/HTML/HTMLOptionElement.cpp b/Libraries/LibWeb/HTML/HTMLOptionElement.cpp index 8dc7be8a547..123edf60f8a 100644 --- a/Libraries/LibWeb/HTML/HTMLOptionElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLOptionElement.cpp @@ -68,6 +68,9 @@ void HTMLOptionElement::set_selected(bool selected) void HTMLOptionElement::set_selected_internal(bool selected) { + if (m_selected != selected) + invalidate_style(DOM::StyleInvalidationReason::HTMLOptionElementSelectedChange); + m_selected = selected; if (selected) m_selectedness_update_index = m_next_selectedness_update_index++;