summaryrefslogtreecommitdiffstats
path: root/dom/debugger
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/debugger/CallbackDebuggerNotification.cpp33
-rw-r--r--dom/debugger/CallbackDebuggerNotification.h77
-rw-r--r--dom/debugger/DebuggerNotification.cpp36
-rw-r--r--dom/debugger/DebuggerNotification.h70
-rw-r--r--dom/debugger/DebuggerNotificationManager.cpp59
-rw-r--r--dom/debugger/DebuggerNotificationManager.h64
-rw-r--r--dom/debugger/DebuggerNotificationObserver.cpp147
-rw-r--r--dom/debugger/DebuggerNotificationObserver.h60
-rw-r--r--dom/debugger/EventCallbackDebuggerNotification.cpp63
-rw-r--r--dom/debugger/EventCallbackDebuggerNotification.h94
-rw-r--r--dom/debugger/moz.build26
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"