diff options
author | Andreas Kling <kling@serenityos.org> | 2022-09-19 20:50:33 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-09-20 10:32:14 +0200 |
commit | d4acdac3175da4edf0ca88c246a9e58307e3eefd (patch) | |
tree | c56fc149669558ce170029bf2aabdcfa64513c32 /Userland/Libraries | |
parent | 5908873b45ecf6dd43411b7df55701576b8e63a6 (diff) | |
download | serenity-d4acdac3175da4edf0ca88c246a9e58307e3eefd.zip |
LibWeb+WebContent+Browser: Plumb visibility state from GUI to web pages
OOPWV now reacts to show/hide events and informs LibWeb about the state
change. This makes visibilitychange events fire when switching tabs. :^)
Diffstat (limited to 'Userland/Libraries')
9 files changed, 125 insertions, 11 deletions
diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 35b6444e34..8397ef9e93 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -647,6 +647,8 @@ void Document::set_title(String const& title) void Document::attach_to_browsing_context(Badge<HTML::BrowsingContext>, HTML::BrowsingContext& browsing_context) { m_browsing_context = browsing_context; + + update_the_visibility_state(browsing_context.system_visibility_state()); } void Document::detach_from_browsing_context(Badge<HTML::BrowsingContext>, HTML::BrowsingContext& browsing_context) @@ -1587,11 +1589,17 @@ bool Document::hidden() const // https://html.spec.whatwg.org/multipage/interaction.html#dom-document-visibilitystate String Document::visibility_state() const { - return m_visibility_state; + switch (m_visibility_state) { + case HTML::VisibilityState::Hidden: + return "hidden"sv; + case HTML::VisibilityState::Visible: + return "visible"sv; + } + VERIFY_NOT_REACHED(); } // https://html.spec.whatwg.org/multipage/interaction.html#update-the-visibility-state -void Document::update_the_visibility_state(String visibility_state) +void Document::update_the_visibility_state(HTML::VisibilityState visibility_state) { // 1. If document's visibility state equals visibilityState, then return. if (m_visibility_state == visibility_state) @@ -1985,4 +1993,25 @@ HTML::PolicyContainer Document::policy_container() const return m_policy_container; } +// https://html.spec.whatwg.org/multipage/browsers.html#list-of-the-descendant-browsing-contexts +Vector<NonnullRefPtr<HTML::BrowsingContext>> Document::list_of_descendant_browsing_contexts() const +{ + // 1. Let list be an empty list. + Vector<NonnullRefPtr<HTML::BrowsingContext>> list; + + // 2. For each browsing context container container, + // whose nested browsing context is non-null and whose shadow-including root is d, in shadow-including tree order: + + // NOTE: We already store our browsing contexts in a tree structure, so we can simply collect all the descendants + // of this document's browsing context. + if (browsing_context()) { + browsing_context()->for_each_in_subtree([&](auto& context) { + list.append(context); + return IterationDecision::Continue; + }); + } + + return list; +} + } diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h index 8be46b9dc1..230d810f71 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.h +++ b/Userland/Libraries/LibWeb/DOM/Document.h @@ -31,6 +31,7 @@ #include <LibWeb/HTML/Origin.h> #include <LibWeb/HTML/SandboxingFlagSet.h> #include <LibWeb/HTML/Scripting/Environments.h> +#include <LibWeb/HTML/VisibilityState.h> #include <LibWeb/HTML/Window.h> namespace Web::DOM { @@ -319,7 +320,7 @@ public: String visibility_state() const; // https://html.spec.whatwg.org/multipage/interaction.html#update-the-visibility-state - void update_the_visibility_state(String visibility_state); + void update_the_visibility_state(HTML::VisibilityState); void run_the_resize_steps(); void run_the_scroll_steps(); @@ -382,6 +383,9 @@ public: // https://html.spec.whatwg.org/multipage/dom.html#concept-document-policy-container HTML::PolicyContainer policy_container() const; + // https://html.spec.whatwg.org/multipage/browsers.html#list-of-the-descendant-browsing-contexts + Vector<NonnullRefPtr<HTML::BrowsingContext>> list_of_descendant_browsing_contexts() const; + protected: virtual void visit_edges(Cell::Visitor&) override; @@ -527,7 +531,7 @@ private: HTML::PolicyContainer m_policy_container; // https://html.spec.whatwg.org/multipage/interaction.html#visibility-state - String m_visibility_state { "hidden" }; + HTML::VisibilityState m_visibility_state { HTML::VisibilityState::Hidden }; }; } diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp index cb0e82e47b..f25f38c466 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp @@ -1113,7 +1113,7 @@ DOM::ExceptionOr<void> BrowsingContext::traverse_the_history(size_t entry_index, new_document->set_page_showing(true); // 3. Update the visibility state of newDocument to "hidden". - new_document->update_the_visibility_state("hidden"); + new_document->update_the_visibility_state(VisibilityState::Hidden); // 4. Fire a page transition event named pageshow at newDocument's relevant global object with true. auto& window = verify_cast<HTML::Window>(relevant_global_object(*new_document)); @@ -1248,18 +1248,55 @@ BrowsingContext const* BrowsingContext::the_one_permitted_sandboxed_navigator() } // https://html.spec.whatwg.org/multipage/browsers.html#document-family -bool BrowsingContext::document_family_contains(DOM::Document const& document) const +Vector<JS::Handle<DOM::Document>> BrowsingContext::document_family() const { - HashTable<DOM::Document const*> family; - + HashTable<DOM::Document*> documents; for (auto& entry : m_session_history) { if (!entry.document) continue; - if (family.set(entry.document) == AK::HashSetResult::ReplacedExistingEntry) + if (documents.set(entry.document.ptr()) == AK::HashSetResult::ReplacedExistingEntry) continue; - // FIXME: The document family of a Document object consists of the union of all the document families of the browsing contexts in the list of the descendant browsing contexts of the Document object. + for (auto& context : entry.document->list_of_descendant_browsing_contexts()) { + for (auto& document : context->document_family()) { + documents.set(document.ptr()); + } + } + } + + Vector<JS::Handle<DOM::Document>> family; + for (auto* document : documents) { + family.append(*document); } + return family; +} + +// https://html.spec.whatwg.org/multipage/browsers.html#document-family +bool BrowsingContext::document_family_contains(DOM::Document const& document) const +{ + return document_family().first_matching([&](auto& entry) { return entry.ptr() == &document; }).has_value(); +} + +VisibilityState BrowsingContext::system_visibility_state() const +{ + return m_system_visibility_state; +} - return family.contains(&document); +// https://html.spec.whatwg.org/multipage/interaction.html#system-visibility-state +void BrowsingContext::set_system_visibility_state(VisibilityState visibility_state) +{ + if (m_system_visibility_state == visibility_state) + return; + m_system_visibility_state = visibility_state; + + // When a user-agent determines that the system visibility state for top-level browsing context context + // has changed to newState, it must queue a task on the user interaction task source to update + // the visibility state of all the Document objects in the top-level browsing context's document family with newState. + auto document_family = top_level_browsing_context().document_family(); + queue_global_task(Task::Source::UserInteraction, Bindings::main_thread_vm().current_realm()->global_object(), [visibility_state, document_family = move(document_family)]() mutable { + for (auto& document : document_family) { + document->update_the_visibility_state(visibility_state); + } + }); } + } diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h index ac841455b2..05c986f636 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h @@ -18,6 +18,7 @@ #include <LibWeb/HTML/HistoryHandlingBehavior.h> #include <LibWeb/HTML/Origin.h> #include <LibWeb/HTML/SessionHistoryEntry.h> +#include <LibWeb/HTML/VisibilityState.h> #include <LibWeb/Loader/FrameLoader.h> #include <LibWeb/Page/EventHandler.h> #include <LibWeb/Platform/Timer.h> @@ -158,8 +159,12 @@ public: // https://html.spec.whatwg.org/multipage/browsing-the-web.html#traverse-the-history DOM::ExceptionOr<void> traverse_the_history(size_t entry_index, HistoryHandlingBehavior = HistoryHandlingBehavior::Default, bool explicit_history_navigation = false); + Vector<JS::Handle<DOM::Document>> document_family() const; bool document_family_contains(DOM::Document const&) const; + VisibilityState system_visibility_state() const; + void set_system_visibility_state(VisibilityState); + private: explicit BrowsingContext(Page&, HTML::BrowsingContextContainer*); @@ -205,6 +210,9 @@ private: // https://html.spec.whatwg.org/multipage/browsers.html#tlbc-group RefPtr<BrowsingContextGroup> m_group; + + // https://html.spec.whatwg.org/multipage/interaction.html#system-visibility-state + VisibilityState m_system_visibility_state { VisibilityState::Hidden }; }; HTML::Origin determine_the_origin(BrowsingContext const& browsing_context, Optional<AK::URL> url, SandboxingFlagSet sandbox_flags, Optional<HTML::Origin> invocation_origin); diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.cpp b/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.cpp index 52ad2f8abf..48ed8132a4 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.cpp +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.cpp @@ -18,6 +18,12 @@ namespace Web::HTML { +HashTable<BrowsingContextContainer*>& BrowsingContextContainer::all_instances() +{ + static HashTable<BrowsingContextContainer*> set; + return set; +} + BrowsingContextContainer::BrowsingContextContainer(DOM::Document& document, DOM::QualifiedName qualified_name) : HTMLElement(document, move(qualified_name)) { diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.h b/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.h index 7009a3867a..f1b14c246a 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.h +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContextContainer.h @@ -16,6 +16,8 @@ class BrowsingContextContainer : public HTMLElement { public: virtual ~BrowsingContextContainer() override; + static HashTable<BrowsingContextContainer*>& all_instances(); + BrowsingContext* nested_browsing_context() { return m_nested_browsing_context; } BrowsingContext const* nested_browsing_context() const { return m_nested_browsing_context; } diff --git a/Userland/Libraries/LibWeb/HTML/VisibilityState.h b/Userland/Libraries/LibWeb/HTML/VisibilityState.h new file mode 100644 index 0000000000..002f893748 --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/VisibilityState.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +namespace Web::HTML { + +enum VisibilityState { + Hidden, + Visible, +}; + +} diff --git a/Userland/Libraries/LibWebView/OutOfProcessWebView.cpp b/Userland/Libraries/LibWebView/OutOfProcessWebView.cpp index 88bb329817..4ece205b89 100644 --- a/Userland/Libraries/LibWebView/OutOfProcessWebView.cpp +++ b/Userland/Libraries/LibWebView/OutOfProcessWebView.cpp @@ -540,4 +540,14 @@ void OutOfProcessWebView::focusout_event(GUI::FocusEvent&) client().async_set_has_focus(false); } +void OutOfProcessWebView::show_event(GUI::ShowEvent&) +{ + client().async_set_system_visibility_state(true); +} + +void OutOfProcessWebView::hide_event(GUI::HideEvent&) +{ + client().async_set_system_visibility_state(false); +} + } diff --git a/Userland/Libraries/LibWebView/OutOfProcessWebView.h b/Userland/Libraries/LibWebView/OutOfProcessWebView.h index 2132fbf290..d5990d8ebb 100644 --- a/Userland/Libraries/LibWebView/OutOfProcessWebView.h +++ b/Userland/Libraries/LibWebView/OutOfProcessWebView.h @@ -131,6 +131,8 @@ private: virtual void screen_rects_change_event(GUI::ScreenRectsChangeEvent&) override; virtual void focusin_event(GUI::FocusEvent&) override; virtual void focusout_event(GUI::FocusEvent&) override; + virtual void show_event(GUI::ShowEvent&) override; + virtual void hide_event(GUI::HideEvent&) override; // ^AbstractScrollableWidget virtual void did_scroll() override; |