tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DebuggerNotificationObserver.cpp (4746B)


      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/. */
      6 
      7 #include "DebuggerNotificationObserver.h"
      8 
      9 #include "DebuggerNotification.h"
     10 #include "WrapperFactory.h"
     11 #include "nsIGlobalObject.h"
     12 
     13 namespace mozilla::dom {
     14 
     15 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DebuggerNotificationObserver,
     16                                      mOwnerGlobal, mEventListenerCallbacks)
     17 
     18 NS_IMPL_CYCLE_COLLECTING_ADDREF(DebuggerNotificationObserver)
     19 NS_IMPL_CYCLE_COLLECTING_RELEASE(DebuggerNotificationObserver)
     20 
     21 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DebuggerNotificationObserver)
     22  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     23 NS_INTERFACE_MAP_END
     24 
     25 /* static */ already_AddRefed<DebuggerNotificationObserver>
     26 DebuggerNotificationObserver::Constructor(GlobalObject& aGlobal,
     27                                          ErrorResult& aRv) {
     28  nsCOMPtr<nsIGlobalObject> globalInterface(
     29      do_QueryInterface(aGlobal.GetAsSupports()));
     30  if (NS_WARN_IF(!globalInterface)) {
     31    aRv.Throw(NS_ERROR_FAILURE);
     32    return nullptr;
     33  }
     34 
     35  RefPtr<DebuggerNotificationObserver> observer(
     36      new DebuggerNotificationObserver(globalInterface));
     37  return observer.forget();
     38 }
     39 
     40 DebuggerNotificationObserver::DebuggerNotificationObserver(
     41    nsIGlobalObject* aOwnerGlobal)
     42    : mOwnerGlobal(aOwnerGlobal) {}
     43 
     44 JSObject* DebuggerNotificationObserver::WrapObject(
     45    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
     46  return DebuggerNotificationObserver_Binding::Wrap(aCx, this, aGivenProto);
     47 }
     48 
     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));
     56 
     57  if (!debuggeeGlobalRooted) {
     58    return nullptr;
     59  }
     60 
     61  nsCOMPtr<nsIGlobalObject> debuggeeGlobalObject(
     62      xpc::NativeGlobal(debuggeeGlobalRooted));
     63  if (!debuggeeGlobalObject) {
     64    return nullptr;
     65  }
     66 
     67  RefPtr<DebuggerNotificationManager> manager(
     68      debuggeeGlobalObject->GetOrCreateDebuggerNotificationManager());
     69  return manager.forget();
     70 }
     71 
     72 bool DebuggerNotificationObserver::Connect(
     73    JSContext* aCx, JS::Handle<JSObject*> aDebuggeeGlobal, ErrorResult& aRv) {
     74  RefPtr<DebuggerNotificationManager> manager(GetManager(aCx, aDebuggeeGlobal));
     75 
     76  if (!manager) {
     77    aRv.Throw(NS_ERROR_FAILURE);
     78    return false;
     79  }
     80 
     81  return manager->Attach(this);
     82 }
     83 
     84 bool DebuggerNotificationObserver::Disconnect(
     85    JSContext* aCx, JS::Handle<JSObject*> aDebuggeeGlobal, ErrorResult& aRv) {
     86  RefPtr<DebuggerNotificationManager> manager(GetManager(aCx, aDebuggeeGlobal));
     87 
     88  if (!manager) {
     89    aRv.Throw(NS_ERROR_FAILURE);
     90    return false;
     91  }
     92 
     93  return manager->Detach(this);
     94 }
     95 
     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;
    102                  })) {
    103    return false;
    104  }
    105 
    106  RefPtr<DebuggerNotificationCallback> handlerFn(&aHandlerFn);
    107  mEventListenerCallbacks.AppendElement(handlerFn);
    108  return true;
    109 }
    110 
    111 bool DebuggerNotificationObserver::RemoveListener(
    112    DebuggerNotificationCallback& aHandlerFn) {
    113  for (nsTObserverArray<RefPtr<DebuggerNotificationCallback>>::ForwardIterator
    114           iter(mEventListenerCallbacks);
    115       iter.HasMore();) {
    116    if (*iter.GetNext().get() == aHandlerFn) {
    117      iter.Remove();
    118      return true;
    119    }
    120  }
    121 
    122  return false;
    123 }
    124 
    125 bool DebuggerNotificationObserver::HasListeners() {
    126  return !mEventListenerCallbacks.IsEmpty();
    127 }
    128 
    129 void DebuggerNotificationObserver::NotifyListeners(
    130    DebuggerNotification* aNotification) {
    131  if (!HasListeners()) {
    132    return;
    133  }
    134 
    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));
    140 
    141  for (RefPtr<DebuggerNotificationCallback> callback :
    142       mEventListenerCallbacks.ForwardRange()) {
    143    callback->Call(*debuggerNotification);
    144  }
    145 }
    146 
    147 }  // namespace mozilla::dom