Bug 1114554 - Patch 4 - ServiceWorkerRegistration.getNotifications() on main thread. r=wchen

This commit is contained in:
Nikhil Marathe 2015-06-25 18:50:25 -07:00
parent a191f384d8
commit 79c4d29dde
6 changed files with 95 additions and 38 deletions

View File

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

View File

@ -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<bool> 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<NotificationOptions> 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> notification;
nsCOMPtr<nsIGlobalObject> 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<JSObject*> element(aCx, notification->WrapObject(aCx, nullptr));
AutoJSAPI jsapi;
DebugOnly<bool> ok = jsapi.Init(mWindow, aCx);
MOZ_ASSERT(ok);
NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
JS::Rooted<JSObject*> notifications(aCx, mNotifications);
@ -117,7 +131,10 @@ public:
NS_IMETHOD Done(JSContext* aCx) override
{
JSAutoCompartment ac(aCx, mGlobal);
AutoJSAPI jsapi;
DebugOnly<bool> ok = jsapi.Init(mWindow, aCx);
MOZ_ASSERT(ok);
JS::Rooted<JS::Value> 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<JSObject *> mGlobal;
nsCOMPtr<nsPIDOMWindow> mWindow;
nsCOMPtr<nsIGlobalObject> mWindow;
nsRefPtr<Promise> mPromise;
JS::Heap<JSObject *> 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<Promise>
Notification::Get(const GlobalObject& aGlobal,
Notification::Get(nsPIDOMWindow* aWindow,
const GetNotificationOptions& aFilter,
const nsAString& aScope,
ErrorResult& aRv)
{
AssertIsOnMainThread();
nsCOMPtr<nsIGlobalObject> global =
do_QueryInterface(aGlobal.GetAsSupports());
MOZ_ASSERT(global);
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global);
MOZ_ASSERT(window);
MOZ_ASSERT(aWindow);
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
if (!doc) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
@ -1644,13 +1661,14 @@ Notification::Get(const GlobalObject& aGlobal,
return nullptr;
}
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aWindow);
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
nsCOMPtr<nsINotificationStorageCallback> callback =
new NotificationStorageCallback(aGlobal, window, promise);
new NotificationStorageCallback(global, aScope, promise);
nsRefPtr<NotificationGetRunnable> r =
new NotificationGetRunnable(origin, aFilter.mTag, callback);
@ -1663,6 +1681,20 @@ Notification::Get(const GlobalObject& aGlobal,
return promise.forget();
}
already_AddRefed<Promise>
Notification::Get(const GlobalObject& aGlobal,
const GetNotificationOptions& aFilter,
ErrorResult& aRv)
{
AssertIsOnMainThread();
nsCOMPtr<nsIGlobalObject> global =
do_QueryInterface(aGlobal.GetAsSupports());
MOZ_ASSERT(global);
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global);
return Get(window, aFilter, EmptyString(), aRv);
}
JSObject*
Notification::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{

View File

@ -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<Promise>
Get(nsPIDOMWindow* aWindow,
const GetNotificationOptions& aFilter,
const nsAString& aScope,
ErrorResult& aRv);
static already_AddRefed<Promise> Get(const GlobalObject& aGlobal,
const GetNotificationOptions& aFilter,
ErrorResult& aRv);

View File

@ -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); }

View File

@ -2295,6 +2295,7 @@ class SendNotificationClickEventRunnable final : public WorkerRunnable
const nsString mIcon;
const nsString mData;
const nsString mBehavior;
const nsString mScope;
public:
SendNotificationClickEventRunnable(
@ -2308,7 +2309,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)
@ -2320,6 +2322,7 @@ public:
, mIcon(aIcon)
, mData(aData)
, mBehavior(aBehavior)
, mScope(aScope)
{
AssertIsOnMainThread();
MOZ_ASSERT(aWorkerPrivate);
@ -2335,7 +2338,9 @@ public:
ErrorResult result;
nsRefPtr<Notification> 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;
}
@ -2383,7 +2388,11 @@ ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix
new nsMainThreadPtrHolder<ServiceWorker>(serviceWorker));
nsRefPtr<SendNotificationClickEventRunnable> 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();

View File

@ -637,8 +637,9 @@ ServiceWorkerRegistrationMainThread::ShowNotification(JSContext* aCx,
already_AddRefed<Promise>
ServiceWorkerRegistrationMainThread::GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv)
{
MOZ_ASSERT(false);
return nullptr;
AssertIsOnMainThread();
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
return Notification::Get(window, aOptions, mScope, aRv);
}
already_AddRefed<PushManager>