diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/debugger | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/debugger')
-rw-r--r-- | dom/debugger/CallbackDebuggerNotification.cpp | 33 | ||||
-rw-r--r-- | dom/debugger/CallbackDebuggerNotification.h | 77 | ||||
-rw-r--r-- | dom/debugger/DebuggerNotification.cpp | 36 | ||||
-rw-r--r-- | dom/debugger/DebuggerNotification.h | 70 | ||||
-rw-r--r-- | dom/debugger/DebuggerNotificationManager.cpp | 59 | ||||
-rw-r--r-- | dom/debugger/DebuggerNotificationManager.h | 64 | ||||
-rw-r--r-- | dom/debugger/DebuggerNotificationObserver.cpp | 147 | ||||
-rw-r--r-- | dom/debugger/DebuggerNotificationObserver.h | 60 | ||||
-rw-r--r-- | dom/debugger/EventCallbackDebuggerNotification.cpp | 63 | ||||
-rw-r--r-- | dom/debugger/EventCallbackDebuggerNotification.h | 94 | ||||
-rw-r--r-- | dom/debugger/moz.build | 26 |
11 files changed, 729 insertions, 0 deletions
diff --git a/dom/debugger/CallbackDebuggerNotification.cpp b/dom/debugger/CallbackDebuggerNotification.cpp new file mode 100644 index 0000000000..73a3837163 --- /dev/null +++ b/dom/debugger/CallbackDebuggerNotification.cpp @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CallbackDebuggerNotification.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_INHERITED(CallbackDebuggerNotification, + DebuggerNotification) + +NS_IMPL_ADDREF_INHERITED(CallbackDebuggerNotification, DebuggerNotification) +NS_IMPL_RELEASE_INHERITED(CallbackDebuggerNotification, DebuggerNotification) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CallbackDebuggerNotification) +NS_INTERFACE_MAP_END_INHERITING(DebuggerNotification) + +JSObject* CallbackDebuggerNotification::WrapObject( + JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { + return CallbackDebuggerNotification_Binding::Wrap(aCx, this, aGivenProto); +} + +already_AddRefed<DebuggerNotification> CallbackDebuggerNotification::CloneInto( + nsIGlobalObject* aNewOwner) const { + RefPtr<CallbackDebuggerNotification> notification( + new CallbackDebuggerNotification(mDebuggeeGlobal, mType, mPhase, + aNewOwner)); + return notification.forget(); +} + +} // namespace mozilla::dom diff --git a/dom/debugger/CallbackDebuggerNotification.h b/dom/debugger/CallbackDebuggerNotification.h new file mode 100644 index 0000000000..8059ac9ed4 --- /dev/null +++ b/dom/debugger/CallbackDebuggerNotification.h @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_CallbackDebuggerNotification_h +#define mozilla_dom_CallbackDebuggerNotification_h + +#include "DebuggerNotification.h" +#include "DebuggerNotificationManager.h" + +namespace mozilla::dom { + +class CallbackDebuggerNotification : public DebuggerNotification { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CallbackDebuggerNotification, + DebuggerNotification) + + CallbackDebuggerNotification(nsIGlobalObject* aDebuggeeGlobal, + DebuggerNotificationType aType, + CallbackDebuggerNotificationPhase aPhase, + nsIGlobalObject* aOwnerGlobal = nullptr) + : DebuggerNotification(aDebuggeeGlobal, aType, aOwnerGlobal), + mPhase(aPhase) {} + + // nsWrapperCache + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + + already_AddRefed<DebuggerNotification> CloneInto( + nsIGlobalObject* aNewOwner) const override; + + CallbackDebuggerNotificationPhase Phase() const { return mPhase; } + + protected: + ~CallbackDebuggerNotification() = default; + + CallbackDebuggerNotificationPhase mPhase; +}; + +class MOZ_RAII CallbackDebuggerNotificationGuard final { + public: + MOZ_CAN_RUN_SCRIPT CallbackDebuggerNotificationGuard( + nsIGlobalObject* aDebuggeeGlobal, DebuggerNotificationType aType) + : mDebuggeeGlobal(aDebuggeeGlobal), mType(aType) { + Dispatch(CallbackDebuggerNotificationPhase::Pre); + } + CallbackDebuggerNotificationGuard(const CallbackDebuggerNotificationGuard&) = + delete; + CallbackDebuggerNotificationGuard(CallbackDebuggerNotificationGuard&&) = + delete; + CallbackDebuggerNotificationGuard& operator=( + const CallbackDebuggerNotificationGuard&) = delete; + CallbackDebuggerNotificationGuard& operator=( + CallbackDebuggerNotificationGuard&&) = delete; + + MOZ_CAN_RUN_SCRIPT ~CallbackDebuggerNotificationGuard() { + Dispatch(CallbackDebuggerNotificationPhase::Post); + } + + private: + MOZ_CAN_RUN_SCRIPT void Dispatch(CallbackDebuggerNotificationPhase aPhase) { + auto manager = DebuggerNotificationManager::ForDispatch(mDebuggeeGlobal); + if (MOZ_UNLIKELY(manager)) { + manager->Dispatch<CallbackDebuggerNotification>(mType, aPhase); + } + } + + nsIGlobalObject* mDebuggeeGlobal; + DebuggerNotificationType mType; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_CallbackDebuggerNotification_h diff --git a/dom/debugger/DebuggerNotification.cpp b/dom/debugger/DebuggerNotification.cpp new file mode 100644 index 0000000000..f78454e7d4 --- /dev/null +++ b/dom/debugger/DebuggerNotification.cpp @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DebuggerNotification.h" + +#include "DebuggerNotificationManager.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DebuggerNotification, mDebuggeeGlobal, + mOwnerGlobal) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(DebuggerNotification) +NS_IMPL_CYCLE_COLLECTING_RELEASE(DebuggerNotification) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DebuggerNotification) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +JSObject* DebuggerNotification::WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) { + return DebuggerNotification_Binding::Wrap(aCx, this, aGivenProto); +} + +already_AddRefed<DebuggerNotification> DebuggerNotification::CloneInto( + nsIGlobalObject* aNewOwner) const { + RefPtr<DebuggerNotification> notification( + new DebuggerNotification(mDebuggeeGlobal, mType, aNewOwner)); + return notification.forget(); +} + +} // namespace mozilla::dom diff --git a/dom/debugger/DebuggerNotification.h b/dom/debugger/DebuggerNotification.h new file mode 100644 index 0000000000..a0d443c27c --- /dev/null +++ b/dom/debugger/DebuggerNotification.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_DebuggerNotification_h +#define mozilla_dom_DebuggerNotification_h + +#include "DebuggerNotificationManager.h" +#include "mozilla/dom/DebuggerNotificationBinding.h" +#include "nsIGlobalObject.h" +#include "nsISupports.h" +#include "nsWrapperCache.h" + +namespace mozilla::dom { + +class DebuggerNotification : public nsISupports, public nsWrapperCache { + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(DebuggerNotification) + + DebuggerNotification(nsIGlobalObject* aDebuggeeGlobal, + DebuggerNotificationType aType, + nsIGlobalObject* aOwnerGlobal = nullptr) + : mType(aType), + mDebuggeeGlobal(aDebuggeeGlobal), + mOwnerGlobal(aOwnerGlobal) {} + + nsIGlobalObject* GetParentObject() const { + MOZ_ASSERT(mOwnerGlobal, + "Notification must be cloned into an observer global before " + "being wrapped"); + return mOwnerGlobal; + } + + DebuggerNotificationType Type() const { return mType; } + + void GetGlobal(JSContext* aCx, JS::MutableHandle<JSObject*> aResult) { + aResult.set(mDebuggeeGlobal->GetGlobalJSObject()); + } + + virtual already_AddRefed<DebuggerNotification> CloneInto( + nsIGlobalObject* aNewOwner) const; + + // nsWrapperCache + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + + protected: + virtual ~DebuggerNotification() = default; + + DebuggerNotificationType mType; + nsCOMPtr<nsIGlobalObject> mDebuggeeGlobal; + + private: + nsCOMPtr<nsIGlobalObject> mOwnerGlobal; +}; + +MOZ_CAN_RUN_SCRIPT inline void DebuggerNotificationDispatch( + nsIGlobalObject* aDebuggeeGlobal, DebuggerNotificationType aType) { + auto manager = DebuggerNotificationManager::ForDispatch(aDebuggeeGlobal); + if (MOZ_UNLIKELY(manager)) { + manager->Dispatch<DebuggerNotification>(aType); + } +} + +} // namespace mozilla::dom + +#endif // mozilla_dom_DebuggerNotification_h diff --git a/dom/debugger/DebuggerNotificationManager.cpp b/dom/debugger/DebuggerNotificationManager.cpp new file mode 100644 index 0000000000..773fdc0c5a --- /dev/null +++ b/dom/debugger/DebuggerNotificationManager.cpp @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DebuggerNotificationManager.h" + +#include "nsIGlobalObject.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION(DebuggerNotificationManager, mDebuggeeGlobal, + mNotificationObservers) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(DebuggerNotificationManager) +NS_IMPL_CYCLE_COLLECTING_RELEASE(DebuggerNotificationManager) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DebuggerNotificationManager) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DebuggerNotificationManager) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +bool DebuggerNotificationManager::Attach( + DebuggerNotificationObserver* aObserver) { + RefPtr<DebuggerNotificationObserver> ptr(aObserver); + + if (mNotificationObservers.Contains(ptr)) { + return false; + } + + mNotificationObservers.AppendElement(ptr); + return true; +} +bool DebuggerNotificationManager::Detach( + DebuggerNotificationObserver* aObserver) { + RefPtr<DebuggerNotificationObserver> ptr(aObserver); + + return mNotificationObservers.RemoveElement(ptr); +} + +bool DebuggerNotificationManager::HasListeners() { + const auto [begin, end] = mNotificationObservers.NonObservingRange(); + return std::any_of(begin, end, [](const auto& observer) { + return observer->HasListeners(); + }); +} + +void DebuggerNotificationManager::NotifyListeners( + DebuggerNotification* aNotification) { + for (RefPtr<DebuggerNotificationObserver> observer : + mNotificationObservers.ForwardRange()) { + observer->NotifyListeners(aNotification); + } +} + +} // namespace mozilla::dom diff --git a/dom/debugger/DebuggerNotificationManager.h b/dom/debugger/DebuggerNotificationManager.h new file mode 100644 index 0000000000..f68b2b3836 --- /dev/null +++ b/dom/debugger/DebuggerNotificationManager.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_DebuggerNotificationManager_h +#define mozilla_dom_DebuggerNotificationManager_h + +#include "DebuggerNotificationObserver.h" +#include "nsCycleCollectionParticipant.h" +#include "nsIGlobalObject.h" +#include "nsISupports.h" +#include "nsTObserverArray.h" + +namespace mozilla::dom { + +class DebuggerNotification; +class DebuggerNotificationObserver; + +class DebuggerNotificationManager final : public nsISupports { + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DebuggerNotificationManager) + + static RefPtr<DebuggerNotificationManager> ForDispatch( + nsIGlobalObject* aDebuggeeGlobal) { + if (MOZ_UNLIKELY(!aDebuggeeGlobal)) { + return nullptr; + } + auto managerPtr = aDebuggeeGlobal->GetExistingDebuggerNotificationManager(); + if (MOZ_LIKELY(!managerPtr) || !managerPtr->HasListeners()) { + return nullptr; + } + + return managerPtr; + } + + explicit DebuggerNotificationManager(nsIGlobalObject* aDebuggeeGlobal) + : mDebuggeeGlobal(aDebuggeeGlobal), mNotificationObservers() {} + + bool Attach(DebuggerNotificationObserver* aObserver); + bool Detach(DebuggerNotificationObserver* aObserver); + + bool HasListeners(); + + template <typename T, typename... Args> + MOZ_CAN_RUN_SCRIPT void Dispatch(Args... aArgs) { + RefPtr<DebuggerNotification> notification(new T(mDebuggeeGlobal, aArgs...)); + NotifyListeners(notification); + } + + private: + ~DebuggerNotificationManager() = default; + + MOZ_CAN_RUN_SCRIPT void NotifyListeners(DebuggerNotification* aNotification); + + nsCOMPtr<nsIGlobalObject> mDebuggeeGlobal; + nsTObserverArray<RefPtr<DebuggerNotificationObserver>> mNotificationObservers; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_DebuggerNotificationManager_h diff --git a/dom/debugger/DebuggerNotificationObserver.cpp b/dom/debugger/DebuggerNotificationObserver.cpp new file mode 100644 index 0000000000..b821003070 --- /dev/null +++ b/dom/debugger/DebuggerNotificationObserver.cpp @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DebuggerNotificationObserver.h" + +#include "DebuggerNotification.h" +#include "nsIGlobalObject.h" +#include "WrapperFactory.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DebuggerNotificationObserver, + mOwnerGlobal, mEventListenerCallbacks) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(DebuggerNotificationObserver) +NS_IMPL_CYCLE_COLLECTING_RELEASE(DebuggerNotificationObserver) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DebuggerNotificationObserver) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY +NS_INTERFACE_MAP_END + +/* static */ already_AddRefed<DebuggerNotificationObserver> +DebuggerNotificationObserver::Constructor(GlobalObject& aGlobal, + ErrorResult& aRv) { + nsCOMPtr<nsIGlobalObject> globalInterface( + do_QueryInterface(aGlobal.GetAsSupports())); + if (NS_WARN_IF(!globalInterface)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + RefPtr<DebuggerNotificationObserver> observer( + new DebuggerNotificationObserver(globalInterface)); + return observer.forget(); +} + +DebuggerNotificationObserver::DebuggerNotificationObserver( + nsIGlobalObject* aOwnerGlobal) + : mEventListenerCallbacks(), mOwnerGlobal(aOwnerGlobal) {} + +JSObject* DebuggerNotificationObserver::WrapObject( + JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { + return DebuggerNotificationObserver_Binding::Wrap(aCx, this, aGivenProto); +} + +static already_AddRefed<DebuggerNotificationManager> GetManager( + JSContext* aCx, JS::Handle<JSObject*> aDebuggeeGlobal) { + // The debuggee global here is likely a debugger-compartment cross-compartment + // wrapper for the debuggee global object, so we need to unwrap it to get + // the real debuggee-compartment global object. + JS::Rooted<JSObject*> debuggeeGlobalRooted( + aCx, js::UncheckedUnwrap(aDebuggeeGlobal, false)); + + if (!debuggeeGlobalRooted) { + return nullptr; + } + + nsCOMPtr<nsIGlobalObject> debuggeeGlobalObject( + xpc::NativeGlobal(debuggeeGlobalRooted)); + if (!debuggeeGlobalObject) { + return nullptr; + } + + RefPtr<DebuggerNotificationManager> manager( + debuggeeGlobalObject->GetOrCreateDebuggerNotificationManager()); + return manager.forget(); +} + +bool DebuggerNotificationObserver::Connect( + JSContext* aCx, JS::Handle<JSObject*> aDebuggeeGlobal, ErrorResult& aRv) { + RefPtr<DebuggerNotificationManager> manager(GetManager(aCx, aDebuggeeGlobal)); + + if (!manager) { + aRv.Throw(NS_ERROR_FAILURE); + return false; + } + + return manager->Attach(this); +} + +bool DebuggerNotificationObserver::Disconnect( + JSContext* aCx, JS::Handle<JSObject*> aDebuggeeGlobal, ErrorResult& aRv) { + RefPtr<DebuggerNotificationManager> manager(GetManager(aCx, aDebuggeeGlobal)); + + if (!manager) { + aRv.Throw(NS_ERROR_FAILURE); + return false; + } + + return manager->Detach(this); +} + +bool DebuggerNotificationObserver::AddListener( + DebuggerNotificationCallback& aHandlerFn) { + const auto [begin, end] = mEventListenerCallbacks.NonObservingRange(); + if (std::any_of(begin, end, + [&](const RefPtr<DebuggerNotificationCallback>& callback) { + return *callback == aHandlerFn; + })) { + return false; + } + + RefPtr<DebuggerNotificationCallback> handlerFn(&aHandlerFn); + mEventListenerCallbacks.AppendElement(handlerFn); + return true; +} + +bool DebuggerNotificationObserver::RemoveListener( + DebuggerNotificationCallback& aHandlerFn) { + for (nsTObserverArray<RefPtr<DebuggerNotificationCallback>>::ForwardIterator + iter(mEventListenerCallbacks); + iter.HasMore();) { + if (*iter.GetNext().get() == aHandlerFn) { + iter.Remove(); + return true; + } + } + + return false; +} + +bool DebuggerNotificationObserver::HasListeners() { + return !mEventListenerCallbacks.IsEmpty(); +} + +void DebuggerNotificationObserver::NotifyListeners( + DebuggerNotification* aNotification) { + if (!HasListeners()) { + return; + } + + // Since we want the notification objects to live in the same compartment + // as the observer, we create a new instance of the notification before + // an observer dispatches the event listeners. + RefPtr<DebuggerNotification> debuggerNotification( + aNotification->CloneInto(mOwnerGlobal)); + + for (RefPtr<DebuggerNotificationCallback> callback : + mEventListenerCallbacks.ForwardRange()) { + callback->Call(*debuggerNotification); + } +} + +} // namespace mozilla::dom diff --git a/dom/debugger/DebuggerNotificationObserver.h b/dom/debugger/DebuggerNotificationObserver.h new file mode 100644 index 0000000000..743268f2a7 --- /dev/null +++ b/dom/debugger/DebuggerNotificationObserver.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_DebuggerNotificationObserver_h +#define mozilla_dom_DebuggerNotificationObserver_h + +#include "DebuggerNotificationManager.h" +#include "mozilla/dom/DebuggerNotificationObserverBinding.h" +#include "mozilla/RefPtr.h" +#include "nsTObserverArray.h" +#include "nsWrapperCache.h" + +class nsIGlobalObject; + +namespace mozilla::dom { + +class DebuggerNotification; + +class DebuggerNotificationObserver final : public nsISupports, + public nsWrapperCache { + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(DebuggerNotificationObserver) + + static already_AddRefed<DebuggerNotificationObserver> Constructor( + GlobalObject& aGlobal, ErrorResult& aRv); + + nsIGlobalObject* GetParentObject() const { return mOwnerGlobal; } + + // nsWrapperCache + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + + bool Connect(JSContext* aCx, JS::Handle<JSObject*> aDebuggeeGlobal, + ErrorResult& aRv); + bool Disconnect(JSContext* aCx, JS::Handle<JSObject*> aDebuggeeGlobal, + ErrorResult& aRv); + + bool AddListener(DebuggerNotificationCallback& aHandlerFn); + bool RemoveListener(DebuggerNotificationCallback& aHandlerFn); + + bool HasListeners(); + + MOZ_CAN_RUN_SCRIPT void NotifyListeners(DebuggerNotification* aNotification); + + private: + explicit DebuggerNotificationObserver(nsIGlobalObject* aOwnerGlobal); + ~DebuggerNotificationObserver() = default; + + nsTObserverArray<RefPtr<DebuggerNotificationCallback>> + mEventListenerCallbacks; + nsCOMPtr<nsIGlobalObject> mOwnerGlobal; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_DebuggerNotificationObserver_h diff --git a/dom/debugger/EventCallbackDebuggerNotification.cpp b/dom/debugger/EventCallbackDebuggerNotification.cpp new file mode 100644 index 0000000000..049d57f868 --- /dev/null +++ b/dom/debugger/EventCallbackDebuggerNotification.cpp @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "EventCallbackDebuggerNotification.h" + +#include "DebuggerNotificationManager.h" +#include "mozilla/dom/EventTarget.h" +#include "mozilla/dom/Worker.h" +#include "mozilla/dom/XMLHttpRequestEventTarget.h" +#include "nsIGlobalObject.h" +#include "nsINode.h" +#include "nsQueryObject.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_INHERITED(EventCallbackDebuggerNotification, + CallbackDebuggerNotification, mEvent) + +NS_IMPL_ADDREF_INHERITED(EventCallbackDebuggerNotification, + CallbackDebuggerNotification) +NS_IMPL_RELEASE_INHERITED(EventCallbackDebuggerNotification, + CallbackDebuggerNotification) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventCallbackDebuggerNotification) +NS_INTERFACE_MAP_END_INHERITING(CallbackDebuggerNotification) + +JSObject* EventCallbackDebuggerNotification::WrapObject( + JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { + return EventCallbackDebuggerNotification_Binding::Wrap(aCx, this, + aGivenProto); +} + +already_AddRefed<DebuggerNotification> +EventCallbackDebuggerNotification::CloneInto(nsIGlobalObject* aNewOwner) const { + RefPtr<EventCallbackDebuggerNotification> notification( + new EventCallbackDebuggerNotification(mDebuggeeGlobal, mType, mEvent, + mTargetType, mPhase, aNewOwner)); + return notification.forget(); +} + +void EventCallbackDebuggerNotificationGuard::DispatchToManager( + const RefPtr<DebuggerNotificationManager>& aManager, + CallbackDebuggerNotificationPhase aPhase) { + if (!mEventTarget) { + MOZ_ASSERT(false, "target should exist"); + return; + } + + Maybe<EventCallbackDebuggerNotificationType> notificationType( + mEventTarget->GetDebuggerNotificationType()); + + if (notificationType) { + aManager->Dispatch<EventCallbackDebuggerNotification>( + DebuggerNotificationType::DomEvent, + // The DOM event will always be live during event dispatch. + MOZ_KnownLive(mEvent), *notificationType, aPhase); + } +} + +} // namespace mozilla::dom diff --git a/dom/debugger/EventCallbackDebuggerNotification.h b/dom/debugger/EventCallbackDebuggerNotification.h new file mode 100644 index 0000000000..b4f85e5624 --- /dev/null +++ b/dom/debugger/EventCallbackDebuggerNotification.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_EventCallbackDebuggerNotification_h +#define mozilla_dom_EventCallbackDebuggerNotification_h + +#include "CallbackDebuggerNotification.h" +#include "DebuggerNotificationManager.h" +#include "mozilla/dom/Event.h" +#include "mozilla/RefPtr.h" + +namespace mozilla::dom { + +class EventCallbackDebuggerNotification : public CallbackDebuggerNotification { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(EventCallbackDebuggerNotification, + CallbackDebuggerNotification) + + EventCallbackDebuggerNotification( + nsIGlobalObject* aDebuggeeGlobal, DebuggerNotificationType aType, + Event* aEvent, EventCallbackDebuggerNotificationType aTargetType, + CallbackDebuggerNotificationPhase aPhase, + nsIGlobalObject* aOwnerGlobal = nullptr) + : CallbackDebuggerNotification(aDebuggeeGlobal, aType, aPhase, + aOwnerGlobal), + mEvent(aEvent), + mTargetType(aTargetType) {} + + // nsWrapperCache + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + + already_AddRefed<DebuggerNotification> CloneInto( + nsIGlobalObject* aNewOwner) const override; + + mozilla::dom::Event* Event() const { return mEvent; } + EventCallbackDebuggerNotificationType TargetType() const { + return mTargetType; + } + + private: + ~EventCallbackDebuggerNotification() = default; + + RefPtr<mozilla::dom::Event> mEvent; + EventCallbackDebuggerNotificationType mTargetType; +}; + +class MOZ_RAII EventCallbackDebuggerNotificationGuard final { + public: + MOZ_CAN_RUN_SCRIPT_BOUNDARY explicit EventCallbackDebuggerNotificationGuard( + mozilla::dom::EventTarget* aEventTarget, mozilla::dom::Event* aEvent) + : mDebuggeeGlobal(aEventTarget ? aEventTarget->GetOwnerGlobal() + : nullptr), + mEventTarget(aEventTarget), + mEvent(aEvent) { + Dispatch(CallbackDebuggerNotificationPhase::Pre); + } + EventCallbackDebuggerNotificationGuard( + const EventCallbackDebuggerNotificationGuard&) = delete; + EventCallbackDebuggerNotificationGuard( + EventCallbackDebuggerNotificationGuard&&) = delete; + EventCallbackDebuggerNotificationGuard& operator=( + const EventCallbackDebuggerNotificationGuard&) = delete; + EventCallbackDebuggerNotificationGuard& operator=( + EventCallbackDebuggerNotificationGuard&&) = delete; + + MOZ_CAN_RUN_SCRIPT_BOUNDARY ~EventCallbackDebuggerNotificationGuard() { + Dispatch(CallbackDebuggerNotificationPhase::Post); + } + + private: + MOZ_CAN_RUN_SCRIPT void Dispatch(CallbackDebuggerNotificationPhase aPhase) { + auto manager = DebuggerNotificationManager::ForDispatch(mDebuggeeGlobal); + if (MOZ_UNLIKELY(manager)) { + DispatchToManager(manager, aPhase); + } + } + + MOZ_CAN_RUN_SCRIPT void DispatchToManager( + const RefPtr<DebuggerNotificationManager>& aManager, + CallbackDebuggerNotificationPhase aPhase); + + nsIGlobalObject* mDebuggeeGlobal; + mozilla::dom::EventTarget* mEventTarget; + mozilla::dom::Event* mEvent; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_EventCallbackDebuggerNotification_h diff --git a/dom/debugger/moz.build b/dom/debugger/moz.build new file mode 100644 index 0000000000..879c3ec237 --- /dev/null +++ b/dom/debugger/moz.build @@ -0,0 +1,26 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +with Files("**"): + BUG_COMPONENT = ("DevTools", "Debugger") + +EXPORTS.mozilla.dom += [ + "CallbackDebuggerNotification.h", + "DebuggerNotification.h", + "DebuggerNotificationManager.h", + "DebuggerNotificationObserver.h", + "EventCallbackDebuggerNotification.h", +] + +UNIFIED_SOURCES += [ + "CallbackDebuggerNotification.cpp", + "DebuggerNotification.cpp", + "DebuggerNotificationManager.cpp", + "DebuggerNotificationObserver.cpp", + "EventCallbackDebuggerNotification.cpp", +] + +FINAL_LIBRARY = "xul" |