| // Copyright 2021 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MODALCLOSEWATCHER_MODAL_CLOSE_WATCHER_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_MODULES_MODALCLOSEWATCHER_MODAL_CLOSE_WATCHER_H_ |
| |
| #include "third_party/blink/public/mojom/modal_close_watcher/modal_close_listener.mojom-blink.h" |
| #include "third_party/blink/renderer/core/dom/events/event_target.h" |
| #include "third_party/blink/renderer/core/dom/events/native_event_listener.h" |
| #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" |
| #include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h" |
| #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h" |
| #include "third_party/blink/renderer/platform/supplementable.h" |
| |
| namespace blink { |
| |
| class ModalCloseWatcher final : public EventTargetWithInlineData, |
| public ExecutionContextClient { |
| DEFINE_WRAPPERTYPEINFO(); |
| |
| public: |
| static ModalCloseWatcher* Create(ScriptState*, ExceptionState&); |
| explicit ModalCloseWatcher(LocalDOMWindow*); |
| void Trace(Visitor*) const override; |
| |
| bool IsClosed() const { return state_ == State::kClosed; } |
| |
| void signalClosed(); |
| void destroy(); |
| |
| DEFINE_ATTRIBUTE_EVENT_LISTENER(beforeclose, kBeforeclose) |
| DEFINE_ATTRIBUTE_EVENT_LISTENER(close, kClose) |
| |
| // EventTargetWithInlineData overrides: |
| const AtomicString& InterfaceName() const final; |
| ExecutionContext* GetExecutionContext() const final { |
| return ExecutionContextClient::GetExecutionContext(); |
| } |
| |
| private: |
| void Close(); |
| |
| // If multiple ModalCloseWatchers are active in a given window, they form a |
| // stack, and a close signal will pop the top watcher. If the stack is empty, |
| // the first ModalCloseWatcher is "free", but creating a new |
| // ModalCloseWatcher when the stack is non-empty requires a user activation. |
| class WatcherStack final : public NativeEventListener, |
| public Supplement<LocalDOMWindow>, |
| public mojom::blink::ModalCloseListener { |
| public: |
| static const char kSupplementName[]; |
| |
| static WatcherStack& From(LocalDOMWindow&); |
| explicit WatcherStack(LocalDOMWindow&); |
| |
| void Add(ModalCloseWatcher*); |
| void Remove(ModalCloseWatcher*); |
| bool HasActiveWatcher() { return !watchers_.IsEmpty(); } |
| |
| void Trace(Visitor*) const final; |
| |
| private: |
| // NativeEventListener override: |
| void Invoke(ExecutionContext*, Event*) final; |
| |
| // mojom::blink::ModalCloseListener override: |
| void Signal() final { watchers_.back()->signalClosed(); } |
| |
| HeapLinkedHashSet<Member<ModalCloseWatcher>> watchers_; |
| |
| // Holds a pipe which the service uses to notify this object |
| // when the idle state has changed. |
| HeapMojoReceiver<mojom::blink::ModalCloseListener, WatcherStack> receiver_; |
| }; |
| |
| enum class State { kActive, kModal, kClosed }; |
| State state_ = State::kActive; |
| bool dispatching_beforeclose_ = false; |
| }; |
| |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MODALCLOSEWATCHER_MODAL_CLOSE_WATCHER_H_ |