From f78eadf00f0b738ebd69a28e19890289cf184d9a Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Thu, 4 May 2023 08:48:53 -0400 Subject: [PATCH] LibWeb: Add an interface to be notified of Document state changes Some HTML elements, e.g. HTMLMediaElement, need to take action when the document becomes inactive. --- Userland/Libraries/LibWeb/CMakeLists.txt | 3 +- Userland/Libraries/LibWeb/DOM/Document.cpp | 21 ++++++++++++ Userland/Libraries/LibWeb/DOM/Document.h | 5 +++ .../Libraries/LibWeb/DOM/DocumentObserver.cpp | 32 +++++++++++++++++++ .../Libraries/LibWeb/DOM/DocumentObserver.h | 31 ++++++++++++++++++ Userland/Libraries/LibWeb/Forward.h | 1 + 6 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 Userland/Libraries/LibWeb/DOM/DocumentObserver.cpp create mode 100644 Userland/Libraries/LibWeb/DOM/DocumentObserver.h diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 946d6d32f1..42d47c9f0c 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -126,9 +126,10 @@ set(SOURCES DOM/DOMTokenList.cpp DOM/DOMTokenList.idl DOM/Document.cpp - DOM/DocumentLoading.cpp DOM/DocumentFragment.cpp DOM/DocumentLoadEventDelayer.cpp + DOM/DocumentLoading.cpp + DOM/DocumentObserver.cpp DOM/DocumentType.cpp DOM/Element.cpp DOM/ElementFactory.cpp diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 0709bef0b9..a2c780a57f 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -371,6 +372,9 @@ void Document::visit_edges(Cell::Visitor& visitor) for (auto& node_iterator : m_node_iterators) visitor.visit(node_iterator); + for (auto& document_observer : m_document_observers) + visitor.visit(document_observer); + for (auto& target : m_pending_scroll_event_targets) visitor.visit(target); for (auto& target : m_pending_scrollend_event_targets) @@ -2032,6 +2036,18 @@ void Document::unregister_node_iterator(Badge, NodeIterator& node_ VERIFY(was_removed); } +void Document::register_document_observer(Badge, DocumentObserver& document_observer) +{ + auto result = m_document_observers.set(document_observer); + VERIFY(result == AK::HashSetResult::InsertedNewEntry); +} + +void Document::unregister_document_observer(Badge, DocumentObserver& document_observer) +{ + bool was_removed = m_document_observers.remove(document_observer); + VERIFY(was_removed); +} + void Document::increment_number_of_things_delaying_the_load_event(Badge) { ++m_number_of_things_delaying_the_load_event; @@ -2437,6 +2453,11 @@ bool Document::is_allowed_to_use_feature(PolicyControlledFeature feature) const void Document::did_stop_being_active_document_in_browsing_context(Badge) { tear_down_layout_tree(); + + for (auto& document_observer : m_document_observers) { + if (document_observer->document_became_inactive) + document_observer->document_became_inactive(); + } } // https://w3c.github.io/editing/docs/execCommand/#querycommandsupported() diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h index f76ba77b46..b3a922200c 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.h +++ b/Userland/Libraries/LibWeb/DOM/Document.h @@ -394,6 +394,9 @@ public: void register_node_iterator(Badge, NodeIterator&); void unregister_node_iterator(Badge, NodeIterator&); + void register_document_observer(Badge, DocumentObserver&); + void unregister_document_observer(Badge, DocumentObserver&); + template void for_each_node_iterator(Callback callback) { @@ -588,6 +591,8 @@ private: HashTable> m_node_iterators; + HashTable> m_document_observers; + // https://html.spec.whatwg.org/multipage/dom.html#is-initial-about:blank bool m_is_initial_about_blank { false }; diff --git a/Userland/Libraries/LibWeb/DOM/DocumentObserver.cpp b/Userland/Libraries/LibWeb/DOM/DocumentObserver.cpp new file mode 100644 index 0000000000..7ca2642af9 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/DocumentObserver.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Web::DOM { + +DocumentObserver::DocumentObserver(JS::Realm& realm, DOM::Document& document) + : Bindings::PlatformObject(realm) + , m_document(document) +{ + m_document->register_document_observer({}, *this); +} + +void DocumentObserver::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_document); +} + +void DocumentObserver::finalize() +{ + Base::finalize(); + m_document->unregister_document_observer({}, *this); +} + +} diff --git a/Userland/Libraries/LibWeb/DOM/DocumentObserver.h b/Userland/Libraries/LibWeb/DOM/DocumentObserver.h new file mode 100644 index 0000000000..1378a2db05 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/DocumentObserver.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Web::DOM { + +class DocumentObserver final : public Bindings::PlatformObject { + WEB_PLATFORM_OBJECT(DocumentObserver, Bindings::PlatformObject); + +public: + JS::SafeFunction document_became_inactive; + +private: + explicit DocumentObserver(JS::Realm&, DOM::Document&); + + virtual void visit_edges(Cell::Visitor&) override; + virtual void finalize() override; + + JS::NonnullGCPtr m_document; +}; + +} diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 03df51f5a4..ba9687a466 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -189,6 +189,7 @@ class CustomEvent; class Document; class DocumentFragment; class DocumentLoadEventDelayer; +class DocumentObserver; class DocumentType; class DOMEventListener; class DOMImplementation;