Bug 1131882 - Associate ServiceWorkers with underlying ServiceWorkerInfo. r=baku

This allows controller to track state too, and provides better encapsulation.
1) Move SW setup to SWM. RuntimeService now only creates the underlying SharedWorker.
2) Require a SWInfo to create a SW. The SW holds a refptr to the info.
This commit is contained in:
Nikhil Marathe 2015-02-19 08:40:21 -08:00
parent d7b7d3930a
commit e594858c5d
8 changed files with 157 additions and 199 deletions

View File

@ -59,7 +59,6 @@
#endif
#include "Principal.h"
#include "ServiceWorker.h"
#include "SharedWorker.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
@ -2249,61 +2248,6 @@ RuntimeService::ResumeWorkersForWindow(nsPIDOMWindow* aWindow)
}
}
nsresult
RuntimeService::CreateServiceWorker(const GlobalObject& aGlobal,
const nsAString& aScriptURL,
const nsACString& aScope,
ServiceWorker** aServiceWorker)
{
nsresult rv;
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
MOZ_ASSERT(window);
nsRefPtr<SharedWorker> sharedWorker;
rv = CreateSharedWorkerInternal(aGlobal, aScriptURL, aScope,
WorkerTypeService,
getter_AddRefs(sharedWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsRefPtr<ServiceWorker> serviceWorker =
new ServiceWorker(window, sharedWorker);
serviceWorker->mURL = aScriptURL;
serviceWorker.forget(aServiceWorker);
return rv;
}
nsresult
RuntimeService::CreateServiceWorkerFromLoadInfo(JSContext* aCx,
WorkerLoadInfo* aLoadInfo,
const nsAString& aScriptURL,
const nsACString& aScope,
ServiceWorker** aServiceWorker)
{
nsRefPtr<SharedWorker> sharedWorker;
nsresult rv = CreateSharedWorkerFromLoadInfo(aCx, aLoadInfo, aScriptURL, aScope,
WorkerTypeService,
getter_AddRefs(sharedWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsRefPtr<ServiceWorker> serviceWorker =
new ServiceWorker(nullptr, sharedWorker);
serviceWorker->mURL = aScriptURL;
serviceWorker.forget(aServiceWorker);
return rv;
}
nsresult
RuntimeService::CreateSharedWorkerInternal(const GlobalObject& aGlobal,
const nsAString& aScriptURL,

View File

@ -22,7 +22,6 @@ class nsPIDOMWindow;
BEGIN_WORKERS_NAMESPACE
class ServiceWorker;
class SharedWorker;
class WorkerThread;
@ -146,17 +145,25 @@ public:
}
nsresult
CreateServiceWorker(const GlobalObject& aGlobal,
const nsAString& aScriptURL,
const nsACString& aScope,
ServiceWorker** aServiceWorker);
CreateSharedWorkerForServiceWorker(const GlobalObject& aGlobal,
const nsAString& aScriptURL,
const nsACString& aScope,
SharedWorker** aSharedWorker)
{
return CreateSharedWorkerInternal(aGlobal, aScriptURL, aScope,
WorkerTypeService, aSharedWorker);
}
nsresult
CreateServiceWorkerFromLoadInfo(JSContext* aCx,
WorkerLoadInfo* aLoadInfo,
const nsAString& aScriptURL,
const nsACString& aScope,
ServiceWorker** aServiceWorker);
CreateSharedWorkerForServiceWorkerFromLoadInfo(JSContext* aCx,
WorkerLoadInfo* aLoadInfo,
const nsAString& aScriptURL,
const nsACString& aScope,
SharedWorker** aSharedWorker)
{
return CreateSharedWorkerFromLoadInfo(aCx, aLoadInfo, aScriptURL, aScope,
WorkerTypeService, aSharedWorker);
}
void
ForgetSharedWorker(WorkerPrivate* aWorkerPrivate);

View File

@ -6,6 +6,7 @@
#include "ServiceWorker.h"
#include "nsPIDOMWindow.h"
#include "ServiceWorkerManager.h"
#include "SharedWorker.h"
#include "WorkerPrivate.h"
@ -38,18 +39,24 @@ ServiceWorkerVisible(JSContext* aCx, JSObject* aObj)
}
ServiceWorker::ServiceWorker(nsPIDOMWindow* aWindow,
ServiceWorkerInfo* aInfo,
SharedWorker* aSharedWorker)
: DOMEventTargetHelper(aWindow),
mState(ServiceWorkerState::Installing),
mInfo(aInfo),
mSharedWorker(aSharedWorker)
{
AssertIsOnMainThread();
MOZ_ASSERT(aInfo);
MOZ_ASSERT(mSharedWorker);
// This will update our state too.
mInfo->AppendWorker(this);
}
ServiceWorker::~ServiceWorker()
{
AssertIsOnMainThread();
mInfo->RemoveWorker(this);
}
NS_IMPL_ADDREF_INHERITED(ServiceWorker, DOMEventTargetHelper)
@ -69,6 +76,12 @@ ServiceWorker::WrapObject(JSContext* aCx)
return ServiceWorkerBinding::Wrap(aCx, this);
}
void
ServiceWorker::GetScriptURL(nsString& aURL) const
{
CopyUTF8toUTF16(mInfo->ScriptSpec(), aURL);
}
void
ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
@ -95,6 +108,16 @@ ServiceWorker::GetWorkerPrivate() const
return mSharedWorker->GetWorkerPrivate();
}
void
ServiceWorker::QueueStateChangeEvent(ServiceWorkerState aState)
{
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableMethodWithArg<ServiceWorkerState>(this,
&ServiceWorker::DispatchStateChange,
aState);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
}
} // namespace workers
} // namespace dom
} // namespace mozilla

View File

@ -19,6 +19,8 @@ class Promise;
namespace workers {
class ServiceWorkerInfo;
class ServiceWorkerManager;
class SharedWorker;
bool
@ -26,7 +28,7 @@ ServiceWorkerVisible(JSContext* aCx, JSObject* aObj);
class ServiceWorker MOZ_FINAL : public DOMEventTargetHelper
{
friend class RuntimeService;
friend class ServiceWorkerManager;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorker, DOMEventTargetHelper)
@ -50,16 +52,17 @@ public:
}
void
GetScriptURL(nsString& aURL) const
GetScriptURL(nsString& aURL) const;
void
DispatchStateChange(ServiceWorkerState aState)
{
aURL = mURL;
SetState(aState);
DOMEventTargetHelper::DispatchTrustedEvent(NS_LITERAL_STRING("statechange"));
}
void
DispatchStateChange()
{
DOMEventTargetHelper::DispatchTrustedEvent(NS_LITERAL_STRING("statechange"));
}
QueueStateChangeEvent(ServiceWorkerState aState);
#ifdef XP_WIN
#undef PostMessage
@ -74,14 +77,15 @@ public:
GetWorkerPrivate() const;
private:
// This class can only be created from the RuntimeService.
ServiceWorker(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker);
// This class can only be created from the ServiceWorkerManager.
ServiceWorker(nsPIDOMWindow* aWindow, ServiceWorkerInfo* aInfo,
SharedWorker* aSharedWorker);
// This class is reference-counted and will be destroyed from Release().
~ServiceWorker();
ServiceWorkerState mState;
nsString mURL;
const nsRefPtr<ServiceWorkerInfo> mInfo;
// To allow ServiceWorkers to potentially drop the backing DOMEventTargetHelper and
// re-instantiate it later, they simply own a SharedWorker member that

View File

@ -567,10 +567,11 @@ public:
// errors. Ideally we should just pass this worker on to ContinueInstall.
MOZ_ASSERT(!swm->mSetOfScopesBeingUpdated.Contains(mRegistration->mScope));
swm->mSetOfScopesBeingUpdated.Put(mRegistration->mScope, true);
nsRefPtr<ServiceWorkerInfo> dummyInfo =
new ServiceWorkerInfo(mRegistration, mRegistration->mScriptSpec);
nsRefPtr<ServiceWorker> serviceWorker;
rv = swm->CreateServiceWorker(mRegistration->mPrincipal,
mRegistration->mScriptSpec,
mRegistration->mScope,
dummyInfo,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -639,8 +640,7 @@ public:
nsRefPtr<ServiceWorker> serviceWorker;
nsresult rv =
swm->CreateServiceWorker(mRegistration->mPrincipal,
mRegistration->mInstallingWorker->ScriptSpec(),
mRegistration->mScope,
mRegistration->mInstallingWorker,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -784,13 +784,8 @@ private:
mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Redundant);
}
// Although the spec first sets waiting worker and then updates its state,
// our ServiceWorkerInfo does not hold a list of associated ServiceWorker
// objects in content JS. This means if we want to fire an event on
// ServiceWorkerRegistration.installing, we need to do it first, before
// swapping it with waiting worker.
mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Installed);
mRegistration->mWaitingWorker = mRegistration->mInstallingWorker.forget();
mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Installed);
swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
WhichServiceWorker::INSTALLING_WORKER | WhichServiceWorker::WAITING_WORKER);
@ -1150,8 +1145,7 @@ ServiceWorkerRegistrationInfo::Activate()
nsRefPtr<ServiceWorker> serviceWorker;
nsresult rv =
swm->CreateServiceWorker(mPrincipal,
mActiveWorker->ScriptSpec(),
mScope,
mActiveWorker,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
nsCOMPtr<nsIRunnable> r =
@ -1708,54 +1702,16 @@ ServiceWorkerRegistrationInfo::FinishActivate(bool aSuccess)
}
}
void
ServiceWorkerRegistrationInfo::QueueStateChangeEvent(ServiceWorkerInfo* aInfo,
ServiceWorkerState aState) const
{
AssertIsOnMainThread();
MOZ_ASSERT(aInfo);
MOZ_ASSERT(aInfo == mInstallingWorker ||
aInfo == mWaitingWorker ||
aInfo == mActiveWorker);
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
WhichServiceWorker whichOne;
if (aInfo == mInstallingWorker) {
whichOne = WhichServiceWorker::INSTALLING_WORKER;
} else if (aInfo == mWaitingWorker) {
whichOne = WhichServiceWorker::WAITING_WORKER;
} else if (aInfo == mActiveWorker) {
whichOne = WhichServiceWorker::ACTIVE_WORKER;
} else {
MOZ_CRASH("Hit unexpected case");
}
// Refactor this iteration pattern across this and 2 other call-sites.
nsTObserverArray<ServiceWorkerRegistration*>::ForwardIterator it(swm->mServiceWorkerRegistrations);
while (it.HasMore()) {
nsRefPtr<ServiceWorkerRegistration> target = it.GetNext();
nsAutoString regScope;
target->GetScope(regScope);
MOZ_ASSERT(!regScope.IsEmpty());
NS_ConvertUTF16toUTF8 utf8Scope(regScope);
if (utf8Scope.Equals(mScope)) {
target->QueueStateChangeEvent(whichOne, aState);
}
}
}
NS_IMETHODIMP
ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
const nsACString& aScriptSpec,
const nsACString& aScope,
ServiceWorkerInfo* aInfo,
ServiceWorker** aServiceWorker)
{
AssertIsOnMainThread();
MOZ_ASSERT(aWindow);
RuntimeService* rs = RuntimeService::GetOrCreateService();
nsRefPtr<ServiceWorker> serviceWorker;
nsRefPtr<SharedWorker> sharedWorker;
AutoJSAPI jsapi;
jsapi.Init(aWindow);
@ -1764,15 +1720,18 @@ ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(aWindow);
JS::Rooted<JSObject*> jsGlobal(cx, sgo->GetGlobalJSObject());
GlobalObject global(cx, jsGlobal);
nsresult rv = rs->CreateServiceWorker(global,
NS_ConvertUTF8toUTF16(aScriptSpec),
aScope,
getter_AddRefs(serviceWorker));
nsresult rv = rs->CreateSharedWorkerForServiceWorker(global,
NS_ConvertUTF8toUTF16(aInfo->ScriptSpec()),
aInfo->Scope(),
getter_AddRefs(sharedWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsRefPtr<ServiceWorker> serviceWorker =
new ServiceWorker(aWindow, aInfo, sharedWorker);
serviceWorker.forget(aServiceWorker);
return rv;
}
@ -2073,7 +2032,7 @@ ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow,
AssertIsOnMainThread();
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
if (!window) {
if (NS_WARN_IF(!window)) {
return NS_ERROR_FAILURE;
}
@ -2100,7 +2059,7 @@ ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow,
////////////////////////////////////////////
nsRefPtr<ServiceWorkerRegistrationInfo> registration = GetRegistration(scope);
if (!registration) {
if (NS_WARN_IF(!registration)) {
return NS_ERROR_FAILURE;
}
@ -2115,14 +2074,13 @@ ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow,
MOZ_CRASH("Invalid worker type");
}
if (!info) {
if (NS_WARN_IF(!info)) {
return NS_ERROR_DOM_NOT_FOUND_ERR;
}
nsRefPtr<ServiceWorker> serviceWorker;
rv = CreateServiceWorkerForWindow(window,
info->ScriptSpec(),
registration->mScope,
info,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -2321,8 +2279,7 @@ ServiceWorkerManager::DispatchFetchEvent(nsIDocument* aDoc, nsIInterceptedChanne
nsRefPtr<ServiceWorker> sw;
rv = CreateServiceWorker(registration->mPrincipal,
registration->mActiveWorker->ScriptSpec(),
registration->mScope,
registration->mActiveWorker,
getter_AddRefs(sw));
serviceWorker = sw.forget();
}
@ -2418,8 +2375,7 @@ ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow, nsISupports**
nsRefPtr<ServiceWorker> serviceWorker;
rv = CreateServiceWorkerForWindow(window,
registration->mActiveWorker->ScriptSpec(),
registration->mScope,
registration->mActiveWorker,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -2461,15 +2417,15 @@ ServiceWorkerManager::GetActive(nsIDOMWindow* aWindow,
NS_IMETHODIMP
ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
const nsACString& aScriptSpec,
const nsACString& aScope,
ServiceWorkerInfo* aInfo,
ServiceWorker** aServiceWorker)
{
AssertIsOnMainThread();
MOZ_ASSERT(aPrincipal);
WorkerLoadInfo info;
nsresult rv = NS_NewURI(getter_AddRefs(info.mBaseURI), aScriptSpec, nullptr, nullptr);
nsresult rv = NS_NewURI(getter_AddRefs(info.mBaseURI), aInfo->ScriptSpec(),
nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -2491,7 +2447,6 @@ ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
// them here.
WorkerPrivate::OverrideLoadInfoLoadGroup(info);
nsRefPtr<ServiceWorker> serviceWorker;
RuntimeService* rs = RuntimeService::GetOrCreateService();
if (!rs) {
return NS_ERROR_FAILURE;
@ -2499,15 +2454,19 @@ ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
AutoJSAPI jsapi;
jsapi.Init();
rv = rs->CreateServiceWorkerFromLoadInfo(jsapi.cx(), &info,
NS_ConvertUTF8toUTF16(aScriptSpec),
aScope,
getter_AddRefs(serviceWorker));
nsRefPtr<SharedWorker> sharedWorker;
rv = rs->CreateSharedWorkerForServiceWorkerFromLoadInfo(jsapi.cx(), &info,
NS_ConvertUTF8toUTF16(aInfo->ScriptSpec()),
aInfo->Scope(),
getter_AddRefs(sharedWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsRefPtr<ServiceWorker> serviceWorker =
new ServiceWorker(nullptr, aInfo, sharedWorker);
serviceWorker.forget(aServiceWorker);
return NS_OK;
}
@ -2721,4 +2680,54 @@ ServiceWorkerManager::RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistr
}
mActor->SendUnregisterServiceWorker(principalInfo, NS_ConvertUTF8toUTF16(reg->mScope));
}
void
ServiceWorkerInfo::AppendWorker(ServiceWorker* aWorker)
{
MOZ_ASSERT(aWorker);
#ifdef DEBUG
nsAutoString workerURL;
aWorker->GetScriptURL(workerURL);
MOZ_ASSERT(workerURL.Equals(NS_ConvertUTF8toUTF16(mScriptSpec)));
#endif
MOZ_ASSERT(!mInstances.Contains(aWorker));
mInstances.AppendElement(aWorker);
aWorker->SetState(State());
}
void
ServiceWorkerInfo::RemoveWorker(ServiceWorker* aWorker)
{
MOZ_ASSERT(aWorker);
#ifdef DEBUG
nsAutoString workerURL;
aWorker->GetScriptURL(workerURL);
MOZ_ASSERT(workerURL.Equals(NS_ConvertUTF8toUTF16(mScriptSpec)));
#endif
MOZ_ASSERT(mInstances.Contains(aWorker));
mInstances.RemoveElement(aWorker);
}
void
ServiceWorkerInfo::UpdateState(ServiceWorkerState aState)
{
#ifdef DEBUG
// Any state can directly transition to redundant, but everything else is
// ordered.
if (aState != ServiceWorkerState::Redundant) {
MOZ_ASSERT_IF(mState == ServiceWorkerState::EndGuard_, aState == ServiceWorkerState::Installing);
MOZ_ASSERT_IF(mState == ServiceWorkerState::Installing, aState == ServiceWorkerState::Installed);
MOZ_ASSERT_IF(mState == ServiceWorkerState::Installed, aState == ServiceWorkerState::Activating);
MOZ_ASSERT_IF(mState == ServiceWorkerState::Activating, aState == ServiceWorkerState::Activated);
}
// Activated can only go to redundant.
MOZ_ASSERT_IF(mState == ServiceWorkerState::Activated, aState == ServiceWorkerState::Redundant);
#endif
mState = aState;
for (uint32_t i = 0; i < mInstances.Length(); ++i) {
mInstances[i]->QueueStateChangeEvent(mState);
}
}
END_WORKERS_NAMESPACE

View File

@ -201,9 +201,6 @@ public:
void
FinishActivate(bool aSuccess);
void
QueueStateChangeEvent(ServiceWorkerInfo* aInfo,
ServiceWorkerState aState) const;
};
/*
@ -218,6 +215,11 @@ private:
const ServiceWorkerRegistrationInfo* mRegistration;
nsCString mScriptSpec;
ServiceWorkerState mState;
// We hold rawptrs since the ServiceWorker constructor and destructor ensure
// addition and removal.
// There is a high chance of there being at least one ServiceWorker
// associated with this all the time.
nsAutoTArray<ServiceWorker*, 1> mInstances;
~ServiceWorkerInfo()
{ }
@ -231,6 +233,12 @@ public:
return mScriptSpec;
}
const nsCString&
Scope() const
{
return mRegistration->mScope;
}
void SetScriptSpec(const nsCString& aSpec)
{
MOZ_ASSERT(!aSpec.IsEmpty());
@ -253,23 +261,7 @@ public:
}
void
UpdateState(ServiceWorkerState aState)
{
#ifdef DEBUG
// Any state can directly transition to redundant, but everything else is
// ordered.
if (aState != ServiceWorkerState::Redundant) {
MOZ_ASSERT_IF(mState == ServiceWorkerState::EndGuard_, aState == ServiceWorkerState::Installing);
MOZ_ASSERT_IF(mState == ServiceWorkerState::Installing, aState == ServiceWorkerState::Installed);
MOZ_ASSERT_IF(mState == ServiceWorkerState::Installed, aState == ServiceWorkerState::Activating);
MOZ_ASSERT_IF(mState == ServiceWorkerState::Activating, aState == ServiceWorkerState::Activated);
}
// Activated can only go to redundant.
MOZ_ASSERT_IF(mState == ServiceWorkerState::Activated, aState == ServiceWorkerState::Redundant);
#endif
mState = aState;
mRegistration->QueueStateChangeEvent(this, mState);
}
UpdateState(ServiceWorkerState aState);
// Only used to set initial state when loading from disk!
void
@ -277,6 +269,12 @@ public:
{
mState = aState;
}
void
AppendWorker(ServiceWorker* aWorker);
void
RemoveWorker(ServiceWorker* aWorker);
};
#define NS_SERVICEWORKERMANAGER_IMPL_IID \
@ -404,14 +402,12 @@ private:
NS_IMETHOD
CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
const nsACString& aScriptSpec,
const nsACString& aScope,
ServiceWorkerInfo* aInfo,
ServiceWorker** aServiceWorker);
NS_IMETHOD
CreateServiceWorker(nsIPrincipal* aPrincipal,
const nsACString& aScriptSpec,
const nsACString& aScope,
ServiceWorkerInfo* aInfo,
ServiceWorker** aServiceWorker);
NS_IMETHODIMP

View File

@ -265,28 +265,6 @@ ServiceWorkerRegistration::InvalidateWorkerReference(WhichServiceWorker aWhichOn
}
}
void
ServiceWorkerRegistration::QueueStateChangeEvent(WhichServiceWorker aWhichOne,
ServiceWorkerState aState) const
{
nsRefPtr<ServiceWorker> worker;
if (aWhichOne == WhichServiceWorker::INSTALLING_WORKER) {
worker = mInstallingWorker;
} else if (aWhichOne == WhichServiceWorker::WAITING_WORKER) {
worker = mWaitingWorker;
} else if (aWhichOne == WhichServiceWorker::ACTIVE_WORKER) {
worker = mActiveWorker;
} else {
MOZ_CRASH("Invalid case");
}
if (worker) {
worker->SetState(aState);
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(worker, &ServiceWorker::DispatchStateChange);
NS_DispatchToMainThread(r);
}
}
// XXXnsm, maybe this can be optimized to only add when a event handler is
// registered.
void

View File

@ -59,9 +59,6 @@ public:
void
InvalidateWorkerReference(WhichServiceWorker aWhichOnes);
void
QueueStateChangeEvent(WhichServiceWorker aWhichOne, ServiceWorkerState aState) const;
// DOMEventTargethelper
virtual void DisconnectFromOwner() MOZ_OVERRIDE;