diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 6cbaa010782..46b39f01cc2 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -506,6 +506,7 @@ void Document::visit_edges(Cell::Visitor& visitor) visitor.visit(m_scripts_to_execute_as_soon_as_possible); visitor.visit(m_node_iterators); visitor.visit(m_document_observers); + visitor.visit(m_document_observers_being_notified); visitor.visit(m_pending_scroll_event_targets); visitor.visit(m_pending_scrollend_event_targets); visitor.visit(m_resize_observers); @@ -2440,10 +2441,10 @@ void Document::update_readiness(HTML::DocumentReadyState readiness_value) } } - for (auto document_observer : m_document_observers) { - if (document_observer->document_readiness_observer()) - document_observer->document_readiness_observer()->function()(m_readiness); - } + notify_each_document_observer([&](auto const& document_observer) { + return document_observer.document_readiness_observer(); + }, + m_readiness); } // https://html.spec.whatwg.org/multipage/dom.html#dom-document-lastmodified @@ -2507,11 +2508,9 @@ void Document::completely_finish_loading() return; ScopeGuard notify_observers = [this] { - auto observers_to_notify = m_document_observers.values(); - for (auto& document_observer : observers_to_notify) { - if (document_observer->document_completely_loaded()) - document_observer->document_completely_loaded()->function()(); - } + notify_each_document_observer([&](auto const& document_observer) { + return document_observer.document_completely_loaded(); + }); }; // 1. Assert: document's browsing context is non-null. @@ -2777,10 +2776,10 @@ void Document::update_the_visibility_state(HTML::VisibilityState visibility_stat m_visibility_state = visibility_state; // 3. Run any page visibility change steps which may be defined in other specifications, with visibility state and document. - for (auto document_observer : m_document_observers) { - if (document_observer->document_visibility_state_observer()) - document_observer->document_visibility_state_observer()->function()(m_visibility_state); - } + notify_each_document_observer([&](auto const& document_observer) { + return document_observer.document_visibility_state_observer(); + }, + m_visibility_state); // 4. Fire an event named visibilitychange at document, with its bubbles attribute initialized to true. auto event = DOM::Event::create(realm(), HTML::EventNames::visibilitychange); @@ -3090,10 +3089,10 @@ void Document::set_page_showing(bool page_showing) m_page_showing = page_showing; - for (auto document_observer : m_document_observers) { - if (document_observer->document_page_showing_observer()) - document_observer->document_page_showing_observer()->function()(m_page_showing); - } + notify_each_document_observer([&](auto const& document_observer) { + return document_observer.document_page_showing_observer(); + }, + m_page_showing); } void Document::invalidate_stacking_context_tree() @@ -3773,11 +3772,9 @@ void Document::did_stop_being_active_document_in_navigable() { tear_down_layout_tree(); - auto observers_to_notify = m_document_observers.values(); - for (auto& document_observer : observers_to_notify) { - if (document_observer->document_became_inactive()) - document_observer->document_became_inactive()->function()(); - } + notify_each_document_observer([&](auto const& document_observer) { + return document_observer.document_became_inactive(); + }); if (m_animation_driver_timer) m_animation_driver_timer->stop(); diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index c5d6ad140fc..261e2b620f7 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -787,6 +787,21 @@ private: void dispatch_events_for_animation_if_necessary(GC::Ref); + template + void notify_each_document_observer(GetNotifier&& get_notifier, Args&&... args) + { + ScopeGuard guard { [&]() { m_document_observers_being_notified.clear_with_capacity(); } }; + m_document_observers_being_notified.ensure_capacity(m_document_observers.size()); + + for (auto observer : m_document_observers) + m_document_observers_being_notified.unchecked_append(observer); + + for (auto document_observer : m_document_observers_being_notified) { + if (auto notifier = get_notifier(*document_observer)) + notifier->function()(forward(args)...); + } + } + GC::Ref m_page; OwnPtr m_style_computer; GC::Ptr m_style_sheets; @@ -897,6 +912,7 @@ private: HashTable> m_node_iterators; HashTable> m_document_observers; + Vector> m_document_observers_being_notified; // https://html.spec.whatwg.org/multipage/dom.html#is-initial-about:blank bool m_is_initial_about_blank { false };