From 54e0ea7180411efa29280d9b9cb72ff653283992 Mon Sep 17 00:00:00 2001 From: Nikhil Marathe Date: Mon, 27 Apr 2015 14:18:54 -0700 Subject: [PATCH] Bug 1114554 - Patch 4 - ServiceWorkerRegistration.getNotifications() on main thread. r=wchen --HG-- extra : rebase_source : 7963829964347156d091c2c8f492c546a9e5fdc0 extra : amend_source : a1bcbf20f5e4ab65b4214bc97d64deba9732b952 --- .../notification/nsINotificationStorage.idl | 14 +++- dom/notification/Notification.cpp | 80 +++++++++++++------ dom/notification/Notification.h | 7 ++ dom/notification/NotificationStorage.js | 12 +-- dom/workers/ServiceWorkerManager.cpp | 15 +++- dom/workers/ServiceWorkerRegistration.cpp | 5 +- 6 files changed, 95 insertions(+), 38 deletions(-) diff --git a/dom/interfaces/notification/nsINotificationStorage.idl b/dom/interfaces/notification/nsINotificationStorage.idl index d8338f8eeb08..1389afcdf0c6 100644 --- a/dom/interfaces/notification/nsINotificationStorage.idl +++ b/dom/interfaces/notification/nsINotificationStorage.idl @@ -4,7 +4,7 @@ #include "domstubs.idl" -[scriptable, uuid(9f1c43b9-f01b-4c87-ad3d-1a86520c2159)] +[scriptable, uuid(c1622232-259c-43b0-b52e-89c39dcd9796)] interface nsINotificationStorageCallback : nsISupports { /** @@ -28,7 +28,8 @@ interface nsINotificationStorageCallback : nsISupports in DOMString tag, in DOMString icon, in DOMString data, - in DOMString behavior); + in DOMString behavior, + in DOMString serviceWorkerRegistrationID); /** * Callback function used to notify C++ the we have returned @@ -41,7 +42,7 @@ interface nsINotificationStorageCallback : nsISupports /** * Interface for notification persistence layer. */ -[scriptable, uuid(2f8f84b7-70b5-4673-98d8-fd3f9f8e0e5c)] +[scriptable, uuid(17f85e52-fe57-440e-9ba1-5c312ca02b95)] interface nsINotificationStorage : nsISupports { @@ -61,6 +62,10 @@ interface nsINotificationStorage : nsISupports * Stored in the database to avoid re-computing * it. Built from origin and tag or id depending * whether there is a tag defined. + * @param registrationID: Opaque string that identifies the service worker + * registration this Notification is associated with. + * May be empty. Only set for Notifications created by + * showNotification(). */ void put(in DOMString origin, in DOMString id, @@ -72,7 +77,8 @@ interface nsINotificationStorage : nsISupports in DOMString icon, in DOMString alertName, in DOMString data, - in DOMString behavior); + in DOMString behavior, + in DOMString serviceWorkerRegistrationID); /** * Retrieve a list of notifications. diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index 9b7a99ba141d..10f5e23ab809 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -56,17 +56,21 @@ public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(NotificationStorageCallback) - NotificationStorageCallback(const GlobalObject& aGlobal, nsPIDOMWindow* aWindow, Promise* aPromise) + NotificationStorageCallback(nsIGlobalObject* aWindow, const nsAString& aScope, + Promise* aPromise) : mCount(0), - mGlobal(aGlobal.Get()), mWindow(aWindow), - mPromise(aPromise) + mPromise(aPromise), + mScope(aScope) { + AssertIsOnMainThread(); MOZ_ASSERT(aWindow); MOZ_ASSERT(aPromise); - JSContext* cx = aGlobal.Context(); - JSAutoCompartment ac(cx, mGlobal); - mNotifications = JS_NewArrayObject(cx, 0); + AutoJSAPI jsapi; + DebugOnly ok = jsapi.Init(aWindow); + MOZ_ASSERT(ok); + // Created in the compartment of the window. + mNotifications = JS_NewArrayObject(jsapi.cx(), 0); HoldData(); } @@ -79,10 +83,17 @@ public: const nsAString& aIcon, const nsAString& aData, const nsAString& aBehavior, + const nsAString& aServiceWorkerRegistrationID, JSContext* aCx) override { + AssertIsOnMainThread(); MOZ_ASSERT(!aID.IsEmpty()); + // Skip scopes that don't match when called from getNotifications(). + if (!mScope.IsEmpty() && !mScope.Equals(aServiceWorkerRegistrationID)) { + return NS_OK; + } + RootedDictionary options(aCx); options.mDir = Notification::StringToDirection(nsString(aDir)); options.mLang = aLang; @@ -91,7 +102,6 @@ public: options.mIcon = aIcon; options.mMozbehavior.Init(aBehavior); nsRefPtr notification; - nsCOMPtr global = do_QueryInterface(mWindow); notification = Notification::CreateInternal(aID, aTitle, options); @@ -102,10 +112,14 @@ public: return rv.StealNSResult(); } + notification->SetScope(aServiceWorkerRegistrationID); + notification->SetStoredState(true); - JSAutoCompartment ac(aCx, mGlobal); - JS::Rooted element(aCx, notification->WrapObject(aCx, nullptr)); + AutoJSAPI jsapi; + DebugOnly ok = jsapi.Init(mWindow, aCx); + MOZ_ASSERT(ok); + NS_ENSURE_TRUE(element, NS_ERROR_FAILURE); JS::Rooted notifications(aCx, mNotifications); @@ -117,7 +131,10 @@ public: NS_IMETHOD Done(JSContext* aCx) override { - JSAutoCompartment ac(aCx, mGlobal); + AutoJSAPI jsapi; + DebugOnly ok = jsapi.Init(mWindow, aCx); + MOZ_ASSERT(ok); + JS::Rooted result(aCx, JS::ObjectValue(*mNotifications)); mPromise->MaybeResolve(aCx, result); return NS_OK; @@ -136,16 +153,15 @@ private: void DropData() { - mGlobal = nullptr; mNotifications = nullptr; mozilla::DropJSObjects(this); } uint32_t mCount; - JS::Heap mGlobal; - nsCOMPtr mWindow; + nsCOMPtr mWindow; nsRefPtr mPromise; JS::Heap mNotifications; + const nsString mScope; }; NS_IMPL_CYCLE_COLLECTING_ADDREF(NotificationStorageCallback) @@ -158,7 +174,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NotificationStorageCallback) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(NotificationStorageCallback) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mGlobal) NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mNotifications) NS_IMPL_CYCLE_COLLECTION_TRACE_END @@ -750,6 +765,7 @@ Notification::ConstructFromFields( const nsAString& aTag, const nsAString& aIcon, const nsAString& aData, + const nsAString& aScope, ErrorResult& aRv) { MOZ_ASSERT(aGlobal); @@ -778,6 +794,8 @@ Notification::ConstructFromFields( return nullptr; } + notification->SetScope(aScope); + return notification.forget(); } @@ -824,7 +842,8 @@ Notification::PersistNotification() mIconUrl, alertName, dataString, - behavior); + behavior, + mScope); if (NS_FAILED(rv)) { return rv; @@ -1206,9 +1225,11 @@ public: const nsAString& aIcon, const nsAString& aData, const nsAString& aBehavior, + const nsAString& aServiceWorkerRegistrationID, JSContext* aCx) override { MOZ_ASSERT(!aID.IsEmpty()); + MOZ_ASSERT(mScope.Equals(aServiceWorkerRegistrationID)); AssertIsOnMainThread(); @@ -1621,18 +1642,14 @@ Notification::ResolveIconAndSoundURL(nsString& iconUrl, nsString& soundUrl) } already_AddRefed -Notification::Get(const GlobalObject& aGlobal, +Notification::Get(nsPIDOMWindow* aWindow, const GetNotificationOptions& aFilter, + const nsAString& aScope, ErrorResult& aRv) { - AssertIsOnMainThread(); - nsCOMPtr global = - do_QueryInterface(aGlobal.GetAsSupports()); - MOZ_ASSERT(global); - nsCOMPtr window = do_QueryInterface(global); - MOZ_ASSERT(window); + MOZ_ASSERT(aWindow); - nsCOMPtr doc = window->GetExtantDoc(); + nsCOMPtr doc = aWindow->GetExtantDoc(); if (!doc) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; @@ -1644,13 +1661,14 @@ Notification::Get(const GlobalObject& aGlobal, return nullptr; } + nsCOMPtr global = do_QueryInterface(aWindow); nsRefPtr promise = Promise::Create(global, aRv); if (aRv.Failed()) { return nullptr; } nsCOMPtr callback = - new NotificationStorageCallback(aGlobal, window, promise); + new NotificationStorageCallback(global, aScope, promise); nsRefPtr r = new NotificationGetRunnable(origin, aFilter.mTag, callback); @@ -1663,6 +1681,20 @@ Notification::Get(const GlobalObject& aGlobal, return promise.forget(); } +already_AddRefed +Notification::Get(const GlobalObject& aGlobal, + const GetNotificationOptions& aFilter, + ErrorResult& aRv) +{ + AssertIsOnMainThread(); + nsCOMPtr global = + do_QueryInterface(aGlobal.GetAsSupports()); + MOZ_ASSERT(global); + nsCOMPtr window = do_QueryInterface(global); + + return Get(window, aFilter, EmptyString(), aRv); +} + JSObject* Notification::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { diff --git a/dom/notification/Notification.h b/dom/notification/Notification.h index beb0fb41fb2c..9e8660089a2c 100644 --- a/dom/notification/Notification.h +++ b/dom/notification/Notification.h @@ -157,6 +157,7 @@ public: const nsAString& aTag, const nsAString& aIcon, const nsAString& aData, + const nsAString& aScope, ErrorResult& aRv); void GetID(nsAString& aRetval) { @@ -214,6 +215,12 @@ public: static NotificationPermission GetPermission(const GlobalObject& aGlobal, ErrorResult& aRv); + static already_AddRefed + Get(nsPIDOMWindow* aWindow, + const GetNotificationOptions& aFilter, + const nsAString& aScope, + ErrorResult& aRv); + static already_AddRefed Get(const GlobalObject& aGlobal, const GetNotificationOptions& aFilter, ErrorResult& aRv); diff --git a/dom/notification/NotificationStorage.js b/dom/notification/NotificationStorage.js index 89452a0897d7..a48fd6fed527 100644 --- a/dom/notification/NotificationStorage.js +++ b/dom/notification/NotificationStorage.js @@ -84,7 +84,7 @@ NotificationStorage.prototype = { }, put: function(origin, id, title, dir, lang, body, tag, icon, alertName, - data, behavior) { + data, behavior, serviceWorkerRegistrationID) { if (DEBUG) { debug("PUT: " + origin + " " + id + ": " + title); } var notification = { id: id, @@ -98,7 +98,8 @@ NotificationStorage.prototype = { timestamp: new Date().getTime(), origin: origin, data: data, - mozbehavior: behavior + mozbehavior: behavior, + serviceWorkerRegistrationID: serviceWorkerRegistrationID, }; this._notifications[id] = notification; @@ -140,9 +141,9 @@ NotificationStorage.prototype = { this.searchID = id; this.originalCallback = originalCallback; var self = this; - this.handle = function(id, title, dir, lang, body, tag, icon, data, behavior) { + this.handle = function(id, title, dir, lang, body, tag, icon, data, behavior, serviceWorkerRegistrationID) { if (id == this.searchID) { - self.originalCallback.handle(id, title, dir, lang, body, tag, icon, data, behavior); + self.originalCallback.handle(id, title, dir, lang, body, tag, icon, data, behavior, serviceWorkerRegistrationID); } }; this.done = function() { @@ -244,7 +245,8 @@ NotificationStorage.prototype = { notification.tag, notification.icon, notification.data, - notification.mozbehavior), + notification.mozbehavior, + notification.serviceWorkerRegistrationID), Ci.nsIThread.DISPATCH_NORMAL); } catch (e) { if (DEBUG) { debug("Error calling callback handle: " + e); } diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index b7aa554eda1b..8239036d26dc 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -2282,6 +2282,7 @@ class SendNotificationClickEventRunnable final : public WorkerRunnable const nsString mIcon; const nsString mData; const nsString mBehavior; + const nsString mScope; public: SendNotificationClickEventRunnable( @@ -2295,7 +2296,8 @@ public: const nsAString& aTag, const nsAString& aIcon, const nsAString& aData, - const nsAString& aBehavior) + const nsAString& aBehavior, + const nsAString& aScope) : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount) , mServiceWorker(aServiceWorker) , mID(aID) @@ -2307,6 +2309,7 @@ public: , mIcon(aIcon) , mData(aData) , mBehavior(aBehavior) + , mScope(aScope) { AssertIsOnMainThread(); MOZ_ASSERT(aWorkerPrivate); @@ -2322,7 +2325,9 @@ public: ErrorResult result; nsRefPtr notification = - Notification::ConstructFromFields(aWorkerPrivate->GlobalScope(), mID, mTitle, mDir, mLang, mBody, mTag, mIcon, mData, result); + Notification::ConstructFromFields(aWorkerPrivate->GlobalScope(), mID, + mTitle, mDir, mLang, mBody, mTag, mIcon, + mData, mScope, result); if (NS_WARN_IF(result.Failed())) { return false; } @@ -2370,7 +2375,11 @@ ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix new nsMainThreadPtrHolder(serviceWorker)); nsRefPtr r = - new SendNotificationClickEventRunnable(serviceWorker->GetWorkerPrivate(), serviceWorkerHandle, aID, aTitle, aDir, aLang, aBody, aTag, aIcon, aData, aBehavior); + new SendNotificationClickEventRunnable(serviceWorker->GetWorkerPrivate(), + serviceWorkerHandle, aID, aTitle, + aDir, aLang, aBody, aTag, aIcon, + aData, aBehavior, + NS_ConvertUTF8toUTF16(aScope)); AutoJSAPI jsapi; jsapi.Init(); diff --git a/dom/workers/ServiceWorkerRegistration.cpp b/dom/workers/ServiceWorkerRegistration.cpp index f0b21ca605c4..c584a8244375 100644 --- a/dom/workers/ServiceWorkerRegistration.cpp +++ b/dom/workers/ServiceWorkerRegistration.cpp @@ -630,8 +630,9 @@ ServiceWorkerRegistrationMainThread::ShowNotification(JSContext* aCx, already_AddRefed ServiceWorkerRegistrationMainThread::GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv) { - MOZ_ASSERT(false); - return nullptr; + AssertIsOnMainThread(); + nsCOMPtr window = GetOwner(); + return Notification::Get(window, aOptions, mScope, aRv); } already_AddRefed