1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "DebuggerNotificationObserver.h"
9 #include "DebuggerNotification.h"
10 #include "nsIGlobalObject.h"
11 #include "WrapperFactory.h"
13 namespace mozilla::dom
{
15 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DebuggerNotificationObserver
,
16 mOwnerGlobal
, mEventListenerCallbacks
)
18 NS_IMPL_CYCLE_COLLECTING_ADDREF(DebuggerNotificationObserver
)
19 NS_IMPL_CYCLE_COLLECTING_RELEASE(DebuggerNotificationObserver
)
21 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DebuggerNotificationObserver
)
22 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
25 /* static */ already_AddRefed
<DebuggerNotificationObserver
>
26 DebuggerNotificationObserver::Constructor(GlobalObject
& aGlobal
,
28 nsCOMPtr
<nsIGlobalObject
> globalInterface(
29 do_QueryInterface(aGlobal
.GetAsSupports()));
30 if (NS_WARN_IF(!globalInterface
)) {
31 aRv
.Throw(NS_ERROR_FAILURE
);
35 RefPtr
<DebuggerNotificationObserver
> observer(
36 new DebuggerNotificationObserver(globalInterface
));
37 return observer
.forget();
40 DebuggerNotificationObserver::DebuggerNotificationObserver(
41 nsIGlobalObject
* aOwnerGlobal
)
42 : mOwnerGlobal(aOwnerGlobal
) {}
44 JSObject
* DebuggerNotificationObserver::WrapObject(
45 JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
46 return DebuggerNotificationObserver_Binding::Wrap(aCx
, this, aGivenProto
);
49 static already_AddRefed
<DebuggerNotificationManager
> GetManager(
50 JSContext
* aCx
, JS::Handle
<JSObject
*> aDebuggeeGlobal
) {
51 // The debuggee global here is likely a debugger-compartment cross-compartment
52 // wrapper for the debuggee global object, so we need to unwrap it to get
53 // the real debuggee-compartment global object.
54 JS::Rooted
<JSObject
*> debuggeeGlobalRooted(
55 aCx
, js::UncheckedUnwrap(aDebuggeeGlobal
, false));
57 if (!debuggeeGlobalRooted
) {
61 nsCOMPtr
<nsIGlobalObject
> debuggeeGlobalObject(
62 xpc::NativeGlobal(debuggeeGlobalRooted
));
63 if (!debuggeeGlobalObject
) {
67 RefPtr
<DebuggerNotificationManager
> manager(
68 debuggeeGlobalObject
->GetOrCreateDebuggerNotificationManager());
69 return manager
.forget();
72 bool DebuggerNotificationObserver::Connect(
73 JSContext
* aCx
, JS::Handle
<JSObject
*> aDebuggeeGlobal
, ErrorResult
& aRv
) {
74 RefPtr
<DebuggerNotificationManager
> manager(GetManager(aCx
, aDebuggeeGlobal
));
77 aRv
.Throw(NS_ERROR_FAILURE
);
81 return manager
->Attach(this);
84 bool DebuggerNotificationObserver::Disconnect(
85 JSContext
* aCx
, JS::Handle
<JSObject
*> aDebuggeeGlobal
, ErrorResult
& aRv
) {
86 RefPtr
<DebuggerNotificationManager
> manager(GetManager(aCx
, aDebuggeeGlobal
));
89 aRv
.Throw(NS_ERROR_FAILURE
);
93 return manager
->Detach(this);
96 bool DebuggerNotificationObserver::AddListener(
97 DebuggerNotificationCallback
& aHandlerFn
) {
98 const auto [begin
, end
] = mEventListenerCallbacks
.NonObservingRange();
99 if (std::any_of(begin
, end
,
100 [&](const RefPtr
<DebuggerNotificationCallback
>& callback
) {
101 return *callback
== aHandlerFn
;
106 RefPtr
<DebuggerNotificationCallback
> handlerFn(&aHandlerFn
);
107 mEventListenerCallbacks
.AppendElement(handlerFn
);
111 bool DebuggerNotificationObserver::RemoveListener(
112 DebuggerNotificationCallback
& aHandlerFn
) {
113 for (nsTObserverArray
<RefPtr
<DebuggerNotificationCallback
>>::ForwardIterator
114 iter(mEventListenerCallbacks
);
116 if (*iter
.GetNext().get() == aHandlerFn
) {
125 bool DebuggerNotificationObserver::HasListeners() {
126 return !mEventListenerCallbacks
.IsEmpty();
129 void DebuggerNotificationObserver::NotifyListeners(
130 DebuggerNotification
* aNotification
) {
131 if (!HasListeners()) {
135 // Since we want the notification objects to live in the same compartment
136 // as the observer, we create a new instance of the notification before
137 // an observer dispatches the event listeners.
138 RefPtr
<DebuggerNotification
> debuggerNotification(
139 aNotification
->CloneInto(mOwnerGlobal
));
141 for (RefPtr
<DebuggerNotificationCallback
> callback
:
142 mEventListenerCallbacks
.ForwardRange()) {
143 callback
->Call(*debuggerNotification
);
147 } // namespace mozilla::dom