From 414e0cc9302e4934e907bd8e68445134ae44eacd Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 17 Apr 2025 13:53:01 +0200 Subject: [PATCH] LibWeb: Use optimized invalidation for focus-related pseudo classes --- Libraries/LibWeb/DOM/Document.cpp | 30 ++++++++++++++++++++++++++---- Libraries/LibWeb/DOM/Document.h | 2 +- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 65521843b3a..56071a95bc3 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -2452,7 +2452,7 @@ void Document::update_active_element() return; } -void Document::set_focused_element(Element* element) +void Document::set_focused_element(GC::Ptr element) { if (m_focused_element.ptr() == element) return; @@ -2462,10 +2462,32 @@ void Document::set_focused_element(Element* element) if (old_focused_element) old_focused_element->did_lose_focus(); - m_focused_element = element; + auto* common_ancestor = find_common_ancestor(old_focused_element, element); - if (auto* invalidation_target = find_common_ancestor(old_focused_element, m_focused_element) ?: this) - invalidation_target->invalidate_style(StyleInvalidationReason::FocusedElementChange); + GC::Ptr old_focused_node_root = nullptr; + GC::Ptr new_focused_node_root = nullptr; + if (old_focused_element) + old_focused_node_root = old_focused_element->root(); + if (element) + new_focused_node_root = element->root(); + if (old_focused_node_root != new_focused_node_root) { + if (old_focused_node_root) { + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_element, *old_focused_node_root, element); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_element, *old_focused_node_root, element); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_element, *old_focused_node_root, element); + } + if (new_focused_node_root) { + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_element, *new_focused_node_root, element); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_element, *new_focused_node_root, element); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_element, *new_focused_node_root, element); + } + } else { + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_element, *common_ancestor, element); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_element, *common_ancestor, element); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_element, *common_ancestor, element); + } + + m_focused_element = element; if (m_focused_element) m_focused_element->did_receive_focus(); diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index e7d7174695a..87243c65e17 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -428,7 +428,7 @@ public: Element* focused_element() { return m_focused_element.ptr(); } Element const* focused_element() const { return m_focused_element.ptr(); } - void set_focused_element(Element*); + void set_focused_element(GC::Ptr); Element const* active_element() const { return m_active_element.ptr(); }