Bug 1529345 - Part 2: Add Gecko infrastructure for receiving notifications about debugger-related events. r=jimb,smaug

Differential Revision: https://phabricator.services.mozilla.com/D30565

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Logan Smyth 2019-06-17 04:36:29 +00:00
parent 6edbe83c24
commit a1de03c27b
31 changed files with 1056 additions and 10 deletions

View File

@ -44,6 +44,8 @@ auto MAXBYTE;
auto MAXWORD;
auto MAXDWORD;
auto ERROR;
auto DELETE;
auto READ_CONTROL;
auto WRITE_DAC;

View File

@ -17,8 +17,10 @@
#include "nsHistory.h"
#include "nsDOMNavigationTiming.h"
#include "nsIDOMStorageManager.h"
#include "mozilla/dom/CallbackDebuggerNotification.h"
#include "mozilla/dom/ContentFrameMessageManager.h"
#include "mozilla/dom/CSPEvalChecker.h"
#include "mozilla/dom/DebuggerNotification.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/DOMJSProxyHandler.h"
#include "mozilla/dom/EventTarget.h"
@ -1370,6 +1372,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDebuggerNotificationManager)
// Traverse stuff from nsPIDOMWindow
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
@ -1468,6 +1472,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDebuggerNotificationManager)
// Unlink stuff from nsPIDOMWindow
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
@ -3289,6 +3295,9 @@ int32_t nsGlobalWindowInner::RequestAnimationFrame(
js::NotifyAnimationActivity(GetWrapperPreserveColor());
}
DebuggerNotificationDispatch(this,
DebuggerNotificationType::RequestAnimationFrame);
int32_t handle;
aError = mDoc->ScheduleFrameRequestCallback(aCallback, &handle);
return handle;
@ -3300,6 +3309,9 @@ void nsGlobalWindowInner::CancelAnimationFrame(int32_t aHandle,
return;
}
DebuggerNotificationDispatch(this,
DebuggerNotificationType::CancelAnimationFrame);
mDoc->CancelFrameRequestCallback(aHandle);
}
@ -3730,12 +3742,16 @@ void nsGlobalWindowInner::MozScrollSnap() {
}
void nsGlobalWindowInner::ClearTimeout(int32_t aHandle) {
DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearTimeout);
if (aHandle > 0) {
mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
}
}
void nsGlobalWindowInner::ClearInterval(int32_t aHandle) {
DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearInterval);
if (aHandle > 0) {
mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
}
@ -4003,6 +4019,20 @@ EventListenerManager* nsGlobalWindowInner::GetExistingListenerManager() const {
return mListenerManager;
}
mozilla::dom::DebuggerNotificationManager*
nsGlobalWindowInner::GetOrCreateDebuggerNotificationManager() {
if (!mDebuggerNotificationManager) {
mDebuggerNotificationManager = new DebuggerNotificationManager(this);
}
return mDebuggerNotificationManager;
}
mozilla::dom::DebuggerNotificationManager*
nsGlobalWindowInner::GetExistingDebuggerNotificationManager() {
return mDebuggerNotificationManager;
}
//*****************************************************************************
// nsGlobalWindowInner::nsPIDOMWindow
//*****************************************************************************
@ -5758,10 +5788,15 @@ int32_t nsGlobalWindowInner::SetTimeoutOrInterval(
}
if (inner != this) {
return inner->SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments,
aIsInterval, aError);
RefPtr<nsGlobalWindowInner> innerRef(inner);
return innerRef->SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments,
aIsInterval, aError);
}
DebuggerNotificationDispatch(
this, aIsInterval ? DebuggerNotificationType::SetInterval
: DebuggerNotificationType::SetTimeout);
if (!GetContextInternal() || !HasJSGlobal()) {
// This window was already closed, or never properly initialized,
// don't let a timer be scheduled on such a window.
@ -5796,10 +5831,15 @@ int32_t nsGlobalWindowInner::SetTimeoutOrInterval(JSContext* aCx,
}
if (inner != this) {
return inner->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval,
aError);
RefPtr<nsGlobalWindowInner> innerRef(inner);
return innerRef->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval,
aError);
}
DebuggerNotificationDispatch(
this, aIsInterval ? DebuggerNotificationType::SetInterval
: DebuggerNotificationType::SetTimeout);
if (!GetContextInternal() || !HasJSGlobal()) {
// This window was already closed, or never properly initialized,
// don't let a timer be scheduled on such a window.
@ -5857,8 +5897,17 @@ bool nsGlobalWindowInner::RunTimeoutHandler(Timeout* aTimeout,
reason = "setTimeout handler";
}
RefPtr<TimeoutHandler> handler(timeout->mScriptHandler);
bool abortIntervalHandler = !handler->Call(reason);
bool abortIntervalHandler;
{
RefPtr<TimeoutHandler> handler(timeout->mScriptHandler);
CallbackDebuggerNotificationGuard guard(
this, timeout->mIsInterval
? DebuggerNotificationType::SetIntervalCallback
: DebuggerNotificationType::SetTimeoutCallback);
abortIntervalHandler = !handler->Call(reason);
}
// If we received an uncatchable exception, do not schedule the timeout again.
// This allows the slow script dialog to break easy DoS attacks like
// setInterval(function() { while(1); }, 100);

View File

@ -36,6 +36,7 @@
#include "prclist.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ChromeMessageBroadcaster.h"
#include "mozilla/dom/DebuggerNotificationManager.h"
#include "mozilla/dom/NavigatorBinding.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
@ -284,6 +285,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override;
mozilla::Maybe<mozilla::dom::EventCallbackDebuggerNotificationType>
GetDebuggerNotificationType() const override {
return mozilla::Some(
mozilla::dom::EventCallbackDebuggerNotificationType::Global);
}
bool ComputeDefaultWantsUntrusted(mozilla::ErrorResult& aRv) final;
virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() override;
@ -317,6 +324,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
virtual bool IsFrozen() const override;
void SyncStateFromParentWindow();
mozilla::dom::DebuggerNotificationManager*
GetOrCreateDebuggerNotificationManager() override;
mozilla::dom::DebuggerNotificationManager*
GetExistingDebuggerNotificationManager() override;
mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const override;
mozilla::Maybe<mozilla::dom::ClientState> GetClientState() const;
mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController()
@ -681,23 +694,35 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
const mozilla::dom::WindowPostMessageOptions& aOptions,
nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& aError);
MOZ_CAN_RUN_SCRIPT
int32_t SetTimeout(JSContext* aCx, mozilla::dom::Function& aFunction,
int32_t aTimeout,
const mozilla::dom::Sequence<JS::Value>& aArguments,
mozilla::ErrorResult& aError);
MOZ_CAN_RUN_SCRIPT
int32_t SetTimeout(JSContext* aCx, const nsAString& aHandler,
int32_t aTimeout,
const mozilla::dom::Sequence<JS::Value>& /* unused */,
mozilla::ErrorResult& aError);
MOZ_CAN_RUN_SCRIPT
void ClearTimeout(int32_t aHandle);
MOZ_CAN_RUN_SCRIPT
int32_t SetInterval(JSContext* aCx, mozilla::dom::Function& aFunction,
const int32_t aTimeout,
const mozilla::dom::Sequence<JS::Value>& aArguments,
mozilla::ErrorResult& aError);
MOZ_CAN_RUN_SCRIPT
int32_t SetInterval(JSContext* aCx, const nsAString& aHandler,
const int32_t aTimeout,
const mozilla::dom::Sequence<JS::Value>& /* unused */,
mozilla::ErrorResult& aError);
MOZ_CAN_RUN_SCRIPT
void ClearInterval(int32_t aHandle);
void GetOrigin(nsAString& aOrigin);
void Atob(const nsAString& aAsciiBase64String, nsAString& aBinaryData,
@ -794,8 +819,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
void SetOuterHeight(JSContext* aCx, JS::Handle<JS::Value> aValue,
mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& aError);
MOZ_CAN_RUN_SCRIPT
int32_t RequestAnimationFrame(mozilla::dom::FrameRequestCallback& aCallback,
mozilla::ErrorResult& aError);
MOZ_CAN_RUN_SCRIPT
void CancelAnimationFrame(int32_t aHandle, mozilla::ErrorResult& aError);
uint32_t RequestIdleCallback(JSContext* aCx,
@ -1059,10 +1088,13 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
public:
// Timeout Functions
// |interval| is in milliseconds.
MOZ_CAN_RUN_SCRIPT
int32_t SetTimeoutOrInterval(
JSContext* aCx, mozilla::dom::Function& aFunction, int32_t aTimeout,
const mozilla::dom::Sequence<JS::Value>& aArguments, bool aIsInterval,
mozilla::ErrorResult& aError);
MOZ_CAN_RUN_SCRIPT
int32_t SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler,
int32_t aTimeout, bool aIsInterval,
mozilla::ErrorResult& aError);
@ -1317,6 +1349,9 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
nsCOMPtr<nsIPrincipal> mDocumentStoragePrincipal;
nsCOMPtr<nsIContentSecurityPolicy> mDocumentCsp;
RefPtr<mozilla::dom::DebuggerNotificationManager>
mDebuggerNotificationManager;
// mBrowserChild is only ever populated in the content process.
nsCOMPtr<nsIBrowserChild> mBrowserChild;

View File

@ -35,6 +35,7 @@ namespace mozilla {
class DOMEventTargetHelper;
namespace dom {
class VoidFunction;
class DebuggerNotificationManager;
class ServiceWorker;
class ServiceWorkerRegistration;
class ServiceWorkerRegistrationDescriptor;
@ -131,6 +132,16 @@ class nsIGlobalObject : public nsISupports,
virtual bool IsInSyncOperation() { return false; }
virtual mozilla::dom::DebuggerNotificationManager*
GetOrCreateDebuggerNotificationManager() {
return nullptr;
}
virtual mozilla::dom::DebuggerNotificationManager*
GetExistingDebuggerNotificationManager() {
return nullptr;
}
virtual mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const;
virtual mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController()

View File

@ -940,6 +940,12 @@ class nsINode : public mozilla::dom::EventTarget {
const override;
virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override;
mozilla::Maybe<mozilla::dom::EventCallbackDebuggerNotificationType>
GetDebuggerNotificationType() const override {
return mozilla::Some(
mozilla::dom::EventCallbackDebuggerNotificationType::Node);
}
bool ComputeDefaultWantsUntrusted(mozilla::ErrorResult& aRv) final;
virtual bool IsApzAware() const override;

View File

@ -201,6 +201,13 @@ DOMInterfaces = {
'implicitJSContext': ['define'],
},
'DebuggerNotification': {
'concrete': True,
},
'CallbackDebuggerNotification': {
'concrete': True,
},
'DedicatedWorkerGlobalScope': {
'headerFile': 'mozilla/dom/WorkerScope.h',
},

View File

@ -0,0 +1,57 @@
/* 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/. */
enum DebuggerNotificationType {
// DebuggerNotification
"setTimeout",
"clearTimeout",
"setInterval",
"clearInterval",
"requestAnimationFrame",
"cancelAnimationFrame",
// CallbackDebuggerNotification
"setTimeoutCallback",
"setIntervalCallback",
"requestAnimationFrameCallback",
// EventCallbackDebuggerNotification
"domEvent",
};
[ChromeOnly]
interface DebuggerNotification {
readonly attribute DebuggerNotificationType type;
// The global object that has triggered the notification.
readonly attribute object global;
};
// For DOM events, we send notifications just before, and just after the
// event handler has been dispatched so that listeners
enum CallbackDebuggerNotificationPhase {
"pre",
"post",
};
// A base notification type for notifications that are dispatched as pairs with
// a before and after notification.
[ChromeOnly]
interface CallbackDebuggerNotification : DebuggerNotification {
readonly attribute CallbackDebuggerNotificationPhase phase;
};
enum EventCallbackDebuggerNotificationType {
"global",
"node",
"xhr",
"worker",
};
// A notification that about the engine calling a DOM event handler.
[ChromeOnly]
interface EventCallbackDebuggerNotification : CallbackDebuggerNotification {
readonly attribute Event event;
readonly attribute EventCallbackDebuggerNotificationType targetType;
};

View File

@ -0,0 +1,28 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
callback DebuggerNotificationCallback = void (DebuggerNotification n);
[ChromeOnly, Constructor, Exposed=(Window, Worker)]
interface DebuggerNotificationObserver {
// Throws if the object is not a browser global or does not support
// debugger notifications.
// Returns false if already connected to this global.
[Throws]
boolean connect(object global);
// Throws if the object is not a browser global or does not support
// debugger notifications.
// Returns false if not connected to this global.
[Throws]
boolean disconnect(object global);
// Returns false if listener already added.
boolean addListener(DebuggerNotificationCallback handler);
// Returns false if listener was not found.
boolean removeListener(DebuggerNotificationCallback handler);
};

View File

@ -35,6 +35,8 @@ PREPROCESSED_WEBIDL_FILES = [
WEBIDL_FILES = [
'BrowsingContext.webidl',
'ChannelWrapper.webidl',
'DebuggerNotification.webidl',
'DebuggerNotificationObserver.webidl',
'DocumentL10n.webidl',
'DominatorTree.webidl',
'DOMLocalization.webidl',

View File

@ -0,0 +1,35 @@
/* -*- 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 {
namespace 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 dom
} // namespace mozilla

View File

@ -0,0 +1,79 @@
/* -*- 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 {
namespace 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 dom
} // namespace mozilla
#endif // mozilla_dom_CallbackDebuggerNotification_h

View File

@ -0,0 +1,38 @@
/* -*- 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 {
namespace 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 dom
} // namespace mozilla

View File

@ -0,0 +1,72 @@
/* -*- 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 {
namespace dom {
class DebuggerNotification : public nsISupports, public nsWrapperCache {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_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 dom
} // namespace mozilla
#endif // mozilla_dom_DebuggerNotification_h

View File

@ -0,0 +1,72 @@
/* -*- 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 "mozilla/ScopeExit.h"
#include "nsIGlobalObject.h"
namespace mozilla {
namespace 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() {
nsTObserverArray<RefPtr<DebuggerNotificationObserver>>::ForwardIterator iter(
mNotificationObservers);
while (iter.HasMore()) {
RefPtr<DebuggerNotificationObserver> observer(iter.GetNext());
if (observer->HasListeners()) {
return true;
}
}
return false;
}
void DebuggerNotificationManager::NotifyListeners(
DebuggerNotification* aNotification) {
nsTObserverArray<RefPtr<DebuggerNotificationObserver>>::ForwardIterator iter(
mNotificationObservers);
while (iter.HasMore()) {
RefPtr<DebuggerNotificationObserver> observer(iter.GetNext());
observer->NotifyListeners(aNotification);
}
}
} // namespace dom
} // namespace mozilla

View File

@ -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/. */
#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 {
namespace dom {
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 dom
} // namespace mozilla
#endif // mozilla_dom_DebuggerNotificationManager_h

View File

@ -0,0 +1,152 @@
/* -*- 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 {
namespace 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) {
nsTObserverArray<RefPtr<DebuggerNotificationCallback>>::ForwardIterator iter(
mEventListenerCallbacks);
while (iter.HasMore()) {
if (*iter.GetNext().get() == aHandlerFn) {
return false;
}
}
RefPtr<DebuggerNotificationCallback> handlerFn(&aHandlerFn);
mEventListenerCallbacks.AppendElement(handlerFn);
return true;
}
bool DebuggerNotificationObserver::RemoveListener(
DebuggerNotificationCallback& aHandlerFn) {
nsTObserverArray<RefPtr<DebuggerNotificationCallback>>::ForwardIterator iter(
mEventListenerCallbacks);
for (uint32_t i = 0; iter.HasMore(); i++) {
if (*iter.GetNext().get() == aHandlerFn) {
mEventListenerCallbacks.RemoveElementAt(i);
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));
nsTObserverArray<RefPtr<DebuggerNotificationCallback>>::ForwardIterator iter(
mEventListenerCallbacks);
while (iter.HasMore()) {
RefPtr<DebuggerNotificationCallback> cb(iter.GetNext());
cb->Call(*debuggerNotification);
}
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,62 @@
/* -*- 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 {
namespace dom {
class DebuggerNotification;
class DebuggerNotificationObserver final : public nsISupports,
public nsWrapperCache {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_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 dom
} // namespace mozilla
#endif // mozilla_dom_DebuggerNotificationObserver_h

View File

@ -0,0 +1,65 @@
/* -*- 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 {
namespace 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 dom
} // namespace mozilla

View File

@ -0,0 +1,96 @@
/* -*- 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 {
namespace 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 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 ~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 dom
} // namespace mozilla
#endif // mozilla_dom_EventCallbackDebuggerNotification_h

26
dom/debugger/moz.build Normal file
View File

@ -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'

View File

@ -20,6 +20,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/PresShell.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/EventCallbackDebuggerNotification.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/EventTargetBinding.h"
@ -1014,6 +1015,7 @@ nsresult EventListenerManager::HandleEventSubType(Listener* aListener,
}
if (NS_SUCCEEDED(result)) {
EventCallbackDebuggerNotificationGuard dbgGuard(aCurrentTarget, aDOMEvent);
nsAutoMicroTask mt;
// Event::currentTarget is set in EventDispatcher.

View File

@ -8,6 +8,7 @@
#define mozilla_dom_EventTarget_h_
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/DebuggerNotificationBinding.h"
#include "mozilla/dom/Nullable.h"
#include "nsISupports.h"
#include "nsWrapperCache.h"
@ -195,6 +196,11 @@ class EventTarget : public nsISupports, public nsWrapperCache {
*/
virtual EventListenerManager* GetExistingListenerManager() const = 0;
virtual Maybe<EventCallbackDebuggerNotificationType>
GetDebuggerNotificationType() const {
return Nothing();
}
// Called from AsyncEventDispatcher to notify it is running.
virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) {}

View File

@ -7,10 +7,6 @@
#include "mozilla/dom/HTMLTrackElement.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLMediaElement.h"
#ifdef XP_WIN
// HTMLTrackElement.webidl defines ERROR, but so does windows.h:
# undef ERROR
#endif
#include "WebVTTListener.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/dom/HTMLTrackElementBinding.h"

View File

@ -44,6 +44,7 @@ DIRS += [
'commandhandler',
'credentialmanagement',
'crypto',
'debugger',
'encoding',
'events',
'fetch',

View File

@ -9,6 +9,7 @@
#include "RuntimeService.h"
#include "jsapi.h"
#include "mozilla/dom/DebuggerNotificationObserverBinding.h"
#include "mozilla/dom/RegisterWorkerBindings.h"
#include "mozilla/dom/RegisterWorkerDebuggerBindings.h"
#include "mozilla/OSFileConstants.h"
@ -52,6 +53,10 @@ bool WorkerPrivate::RegisterDebuggerBindings(JSContext* aCx,
return false;
}
if (!DebuggerNotificationObserver_Binding::GetConstructorObject(aCx)) {
return false;
}
if (!JS_DefineDebuggerObject(aCx, aGlobal)) {
return false;
}

View File

@ -8,6 +8,7 @@
#define mozilla_dom_Worker_h
#include "mozilla/Attributes.h"
#include "mozilla/dom/DebuggerNotificationBinding.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/RefPtr.h"
#include "mozilla/WeakPtr.h"
@ -38,6 +39,11 @@ class Worker : public DOMEventTargetHelper, public SupportsWeakPtr<Worker> {
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
Maybe<EventCallbackDebuggerNotificationType> GetDebuggerNotificationType()
const override {
return Some(EventCallbackDebuggerNotificationType::Worker);
}
void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable, ErrorResult& aRv);

View File

@ -17,6 +17,7 @@
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPrefs.h"
#include "mozilla/dom/BlobURLProtocolHandler.h"
#include "mozilla/dom/CallbackDebuggerNotification.h"
#include "mozilla/dom/ClientManager.h"
#include "mozilla/dom/ClientSource.h"
#include "mozilla/dom/ClientState.h"
@ -4309,6 +4310,12 @@ bool WorkerPrivate::RunExpiredTimeouts(JSContext* aCx) {
}
RefPtr<TimeoutHandler> handler(info->mHandler);
RefPtr<WorkerGlobalScope> scope(this->GlobalScope());
CallbackDebuggerNotificationGuard guard(
scope, info->mIsInterval
? DebuggerNotificationType::SetIntervalCallback
: DebuggerNotificationType::SetTimeoutCallback);
if (!handler->Call(reason)) {
retval = false;
break;

View File

@ -14,6 +14,7 @@
#include "mozilla/dom/ClientState.h"
#include "mozilla/dom/Console.h"
#include "mozilla/dom/CSPEvalChecker.h"
#include "mozilla/dom/DebuggerNotification.h"
#include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
#include "mozilla/dom/Fetch.h"
#include "mozilla/dom/FunctionBinding.h"
@ -140,6 +141,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDebuggerNotificationManager)
tmp->TraverseHostObjectURIs(cb);
tmp->mWorkerPrivate->TraverseTimeouts(cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -154,6 +156,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope,
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDebuggerNotificationManager)
tmp->UnlinkHostObjectURIs();
tmp->mWorkerPrivate->UnlinkTimeouts();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -303,6 +306,9 @@ int32_t WorkerGlobalScope::SetTimeout(JSContext* aCx, const nsAString& aHandler,
void WorkerGlobalScope::ClearTimeout(int32_t aHandle) {
mWorkerPrivate->AssertIsOnWorkerThread();
DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearTimeout);
mWorkerPrivate->ClearTimeout(aHandle);
}
@ -323,6 +329,9 @@ int32_t WorkerGlobalScope::SetInterval(JSContext* aCx,
void WorkerGlobalScope::ClearInterval(int32_t aHandle) {
mWorkerPrivate->AssertIsOnWorkerThread();
DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearInterval);
mWorkerPrivate->ClearTimeout(aHandle);
}
@ -331,6 +340,10 @@ int32_t WorkerGlobalScope::SetTimeoutOrInterval(
const Sequence<JS::Value>& aArguments, bool aIsInterval, ErrorResult& aRv) {
mWorkerPrivate->AssertIsOnWorkerThread();
DebuggerNotificationDispatch(
this, aIsInterval ? DebuggerNotificationType::SetInterval
: DebuggerNotificationType::SetTimeout);
nsTArray<JS::Heap<JS::Value>> args;
if (!args.AppendElements(aArguments, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
@ -350,6 +363,10 @@ int32_t WorkerGlobalScope::SetTimeoutOrInterval(JSContext* aCx,
ErrorResult& aRv) {
mWorkerPrivate->AssertIsOnWorkerThread();
DebuggerNotificationDispatch(
this, aIsInterval ? DebuggerNotificationType::SetInterval
: DebuggerNotificationType::SetTimeout);
bool allowEval = false;
aRv =
CSPEvalChecker::CheckForWorker(aCx, mWorkerPrivate, aHandler, &allowEval);
@ -500,6 +517,20 @@ AbstractThread* WorkerGlobalScope::AbstractMainThreadFor(
MOZ_CRASH("AbstractMainThreadFor not supported for workers.");
}
mozilla::dom::DebuggerNotificationManager*
WorkerGlobalScope::GetOrCreateDebuggerNotificationManager() {
if (!mDebuggerNotificationManager) {
mDebuggerNotificationManager = new DebuggerNotificationManager(this);
}
return mDebuggerNotificationManager;
}
mozilla::dom::DebuggerNotificationManager*
WorkerGlobalScope::GetExistingDebuggerNotificationManager() {
return mDebuggerNotificationManager;
}
Maybe<ClientInfo> WorkerGlobalScope::GetClientInfo() const {
return mWorkerPrivate->GetClientInfo();
}

View File

@ -10,6 +10,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/DebuggerNotificationManager.h"
#include "mozilla/dom/Headers.h"
#include "mozilla/dom/RequestBinding.h"
#include "nsWeakReference.h"
@ -60,6 +61,8 @@ class WorkerGlobalScope : public DOMEventTargetHelper,
RefPtr<IDBFactory> mIndexedDB;
RefPtr<cache::CacheStorage> mCacheStorage;
nsCOMPtr<nsISerialEventTarget> mSerialEventTarget;
RefPtr<mozilla::dom::DebuggerNotificationManager>
mDebuggerNotificationManager;
uint32_t mWindowInteractionsAllowed;
@ -69,10 +72,12 @@ class WorkerGlobalScope : public DOMEventTargetHelper,
explicit WorkerGlobalScope(WorkerPrivate* aWorkerPrivate);
virtual ~WorkerGlobalScope();
MOZ_CAN_RUN_SCRIPT
int32_t SetTimeoutOrInterval(JSContext* aCx, Function& aHandler,
const int32_t aTimeout,
const Sequence<JS::Value>& aArguments,
bool aIsInterval, ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT
int32_t SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler,
const int32_t aTimeout, bool aIsInterval,
ErrorResult& aRv);
@ -115,19 +120,25 @@ class WorkerGlobalScope : public DOMEventTargetHelper,
void ImportScripts(JSContext* aCx, const Sequence<nsString>& aScriptURLs,
ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT
int32_t SetTimeout(JSContext* aCx, Function& aHandler, const int32_t aTimeout,
const Sequence<JS::Value>& aArguments, ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT
int32_t SetTimeout(JSContext* aCx, const nsAString& aHandler,
const int32_t aTimeout,
const Sequence<JS::Value>& /* unused */, ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT
void ClearTimeout(int32_t aHandle);
MOZ_CAN_RUN_SCRIPT
int32_t SetInterval(JSContext* aCx, Function& aHandler,
const int32_t aTimeout,
const Sequence<JS::Value>& aArguments, ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT
int32_t SetInterval(JSContext* aCx, const nsAString& aHandler,
const int32_t aTimeout,
const Sequence<JS::Value>& /* unused */,
ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT
void ClearInterval(int32_t aHandle);
void GetOrigin(nsAString& aOrigin) const;
@ -191,6 +202,18 @@ class WorkerGlobalScope : public DOMEventTargetHelper,
AbstractThread* AbstractMainThreadFor(TaskCategory aCategory) override;
mozilla::dom::DebuggerNotificationManager*
GetOrCreateDebuggerNotificationManager() override;
mozilla::dom::DebuggerNotificationManager*
GetExistingDebuggerNotificationManager() override;
mozilla::Maybe<mozilla::dom::EventCallbackDebuggerNotificationType>
GetDebuggerNotificationType() const override {
return mozilla::Some(
mozilla::dom::EventCallbackDebuggerNotificationType::Global);
}
Maybe<ClientInfo> GetClientInfo() const override;
Maybe<ClientState> GetClientState() const;

View File

@ -26,6 +26,11 @@ class XMLHttpRequestEventTarget : public DOMEventTargetHelper {
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XMLHttpRequestEventTarget,
DOMEventTargetHelper)
mozilla::Maybe<EventCallbackDebuggerNotificationType>
GetDebuggerNotificationType() const override {
return mozilla::Some(EventCallbackDebuggerNotificationType::Xhr);
}
IMPL_EVENT_HANDLER(loadstart)
IMPL_EVENT_HANDLER(progress)
IMPL_EVENT_HANDLER(abort)

View File

@ -52,6 +52,7 @@
#include "nsViewManager.h"
#include "GeckoProfiler.h"
#include "nsNPAPIPluginInstance.h"
#include "mozilla/dom/CallbackDebuggerNotification.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/Selection.h"
@ -1695,6 +1696,12 @@ void nsRefreshDriver::RunFrameRequestCallbacks(TimeStamp aNowTime) {
callback.mHandle)) {
continue;
}
nsCOMPtr<nsIGlobalObject> global(innerWindow ? innerWindow->AsGlobal()
: nullptr);
CallbackDebuggerNotificationGuard guard(
global, DebuggerNotificationType::RequestAnimationFrameCallback);
// MOZ_KnownLive is OK, because the stack array frameRequestCallbacks
// keeps callback alive and the mCallback strong reference can't be
// mutated by the call.