Backed out 11 changesets (bug 916893, bug 1114554) for various mochitest and Gij failures.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 25 Jun 2015 19:52:40 -0400
changeset 282646 531f100d2bd8861ee165e3e585f08c325ad0948f
parent 282645 1a326aaaba371e18e090f98ca1c4474bbdce2fca
child 282647 04239448fe0b82467db334a876ca4d59df921c60
push id897
push userjlund@mozilla.com
push dateMon, 14 Sep 2015 18:56:12 +0000
treeherdermozilla-release@9411e2d2b214 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs916893, 1114554
milestone41.0a1
backs out247ca4bf258ea72aa5be01b6e79daf8174b6fc3c
5578d5c280a6781a0ad9e064aded80ed26f463d5
404830c1ecf70d7075bd48ccc4d20f89e3e9a090
15bdf9c78e6e7b69199f1b6a61e43f558afae1ab
f92abe5ec78447a2bcd9c06658dae0df914f68a5
75324b6862a8545eeeb1e1fddff80f93dc1c5754
ce8a768782f234b8d70c30164c687024c7905dfb
0d860fd125343f67d71dafddd4e435cd624884f4
7dc2448065a98863e8df27b21d9708921edf0057
c3b07f0d1a6000e231395e3a2261f980271779e1
61c3f24cc908f0d46008dfa38939298841dfbee2
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 11 changesets (bug 916893, bug 1114554) for various mochitest and Gij failures. Backed out changeset 247ca4bf258e (bug 1114554) Backed out changeset 5578d5c280a6 (bug 1114554) Backed out changeset 404830c1ecf7 (bug 1114554) Backed out changeset 15bdf9c78e6e (bug 1114554) Backed out changeset f92abe5ec784 (bug 1114554) Backed out changeset 75324b6862a8 (bug 1114554) Backed out changeset ce8a768782f2 (bug 1114554) Backed out changeset 0d860fd12534 (bug 1114554) Backed out changeset 7dc2448065a9 (bug 916893) Backed out changeset c3b07f0d1a60 (bug 916893) Backed out changeset 61c3f24cc908 (bug 916893) CLOSED TREE
dom/base/nsGkAtomList.h
dom/bindings/Bindings.conf
dom/bindings/Errors.msg
dom/interfaces/base/nsIServiceWorkerManager.idl
dom/interfaces/notification/nsINotificationStorage.idl
dom/notification/Notification.cpp
dom/notification/Notification.h
dom/notification/NotificationEvent.cpp
dom/notification/NotificationEvent.h
dom/notification/NotificationStorage.js
dom/notification/moz.build
dom/promise/Promise.cpp
dom/tests/mochitest/notification/MockServices.js
dom/webidl/Notification.webidl
dom/webidl/NotificationEvent.webidl
dom/webidl/ServiceWorker.webidl
dom/webidl/moz.build
dom/workers/RuntimeService.cpp
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerRegistration.cpp
dom/workers/ServiceWorkerRegistration.h
dom/workers/WorkerPrivate.h
dom/workers/WorkerScope.h
dom/workers/Workers.h
dom/workers/test/mochitest.ini
dom/workers/test/notification_permission_worker.js
dom/workers/test/notification_worker.js
dom/workers/test/notification_worker_child-child.js
dom/workers/test/notification_worker_child-parent.js
dom/workers/test/serviceworkers/mochitest.ini
dom/workers/test/serviceworkers/notification/listener.html
dom/workers/test/serviceworkers/notification/register.html
dom/workers/test/serviceworkers/notification_alt/register.html
dom/workers/test/serviceworkers/notification_constructor_error.js
dom/workers/test/serviceworkers/notification_get_sw.js
dom/workers/test/serviceworkers/notificationclick.html
dom/workers/test/serviceworkers/notificationclick.js
dom/workers/test/serviceworkers/test_notification_constructor_error.html
dom/workers/test/serviceworkers/test_notification_get.html
dom/workers/test/serviceworkers/test_notificationclick.html
dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
dom/workers/test/test_notification.html
dom/workers/test/test_notification_child.html
dom/workers/test/test_notification_permission.html
modules/libpref/init/all.js
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -817,17 +817,16 @@ GK_ATOM(onmozfullscreenerror, "onmozfull
 GK_ATOM(onmozpointerlockchange, "onmozpointerlockchange")
 GK_ATOM(onmozpointerlockerror, "onmozpointerlockerror")
 GK_ATOM(onmoztimechange, "onmoztimechange")
 GK_ATOM(onMozMousePixelScroll, "onMozMousePixelScroll")
 GK_ATOM(onMozScrolledAreaChanged, "onMozScrolledAreaChanged")
 GK_ATOM(onmoznetworkupload, "onmoznetworkupload")
 GK_ATOM(onmoznetworkdownload, "onmoznetworkdownload")
 GK_ATOM(onnewrdsgroup, "onnewrdsgroup")
-GK_ATOM(onnotificationclick, "onnotificationclick")
 GK_ATOM(onnoupdate, "onnoupdate")
 GK_ATOM(onobsolete, "onobsolete")
 GK_ATOM(ononline, "ononline")
 GK_ATOM(onoffline, "onoffline")
 GK_ATOM(onopen, "onopen")
 GK_ATOM(onotastatuschange, "onotastatuschange")
 GK_ATOM(onoverflow, "onoverflow")
 GK_ATOM(onoverflowchanged, "onoverflowchanged")
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -860,24 +860,16 @@ DOMInterfaces = {
 'NodeIterator': {
     'wrapperCache': False,
 },
 
 'NodeList': {
     'nativeType': 'nsINodeList',
 },
 
-'NotificationEvent': {
-    'headerFile': 'mozilla/dom/NotificationEvent.h',
-    'nativeType': 'mozilla::dom::workers::NotificationEvent',
-    'binaryNames': {
-        'notification': 'notification_'
-    }
-},
-
 'OfflineAudioContext': {
     'nativeType': 'mozilla::dom::AudioContext',
 },
 
 'OfflineResourceList': {
     'nativeType': 'nsDOMOfflineResourceList',
 },
 
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -68,11 +68,8 @@ MSG_DEF(MSG_DEFINE_NON_CONFIGURABLE_PROP
 MSG_DEF(MSG_INVALID_ZOOMANDPAN_VALUE_ERROR, 0, JSEXN_RANGEERR, "Invalid zoom and pan value.")
 MSG_DEF(MSG_INVALID_TRANSFORM_ANGLE_ERROR, 0, JSEXN_RANGEERR, "Invalid transform angle.")
 MSG_DEF(MSG_INVALID_RESPONSE_STATUSCODE_ERROR, 0, JSEXN_RANGEERR, "Invalid response status code.")
 MSG_DEF(MSG_INVALID_REDIRECT_STATUSCODE_ERROR, 0, JSEXN_RANGEERR, "Invalid redirect status code.")
 MSG_DEF(MSG_INVALID_URL_SCHEME, 2, JSEXN_TYPEERR, "{0} URL {1} must be either http:// or https://.")
 MSG_DEF(MSG_RESPONSE_URL_IS_NULL, 0, JSEXN_TYPEERR, "Cannot set Response.finalURL when Response.url is null.")
 MSG_DEF(MSG_RESPONSE_HAS_VARY_STAR, 0, JSEXN_TYPEERR, "Invalid Response object with a 'Vary: *' header.")
 MSG_DEF(MSG_BAD_FORMDATA, 0, JSEXN_TYPEERR, "Could not parse content as FormData.")
-MSG_DEF(MSG_NO_ACTIVE_WORKER, 1, JSEXN_TYPEERR, "No active worker for scope {0}.")
-MSG_DEF(MSG_NOTIFICATION_PERMISSION_DENIED, 0, JSEXN_TYPEERR, "Permission to show Notification denied.")
-MSG_DEF(MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER, 0, JSEXN_TYPEERR, "Notification constructor cannot be used in ServiceWorkerGlobalScope. Use registration.showNotification() instead.")
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -28,17 +28,17 @@ interface nsIServiceWorkerInfo : nsISupp
   readonly attribute DOMString scope;
   readonly attribute DOMString scriptSpec;
   readonly attribute DOMString currentWorkerURL;
 
   readonly attribute DOMString activeCacheName;
   readonly attribute DOMString waitingCacheName;
 };
 
-[scriptable, builtinclass, uuid(ed1cbbf2-0400-4caa-8eb2-b09d21a94e20)]
+[scriptable, builtinclass, uuid(e9abb123-0099-4d9e-85db-c8cd0aff19e6)]
 interface nsIServiceWorkerManager : nsISupports
 {
   /**
    * Registers a ServiceWorker with script loaded from `aScriptURI` to act as
    * the ServiceWorker for aScope.  Requires a valid entry settings object on
    * the stack. This means you must call this from content code 'within'
    * a window.
    *
@@ -121,27 +121,16 @@ interface nsIServiceWorkerManager : nsIS
 
   // Note: This is meant to be used only by about:serviceworkers.
   // It calls unregister() in each child process. The callback is used to
   // inform when unregister() is completed on the current process.
   void propagateUnregister(in nsIPrincipal aPrincipal,
                            in nsIServiceWorkerUnregisterCallback aCallback,
                            in DOMString aScope);
 
-  void sendNotificationClickEvent(in ACString aOriginSuffix,
-                                  in ACString scope,
-                                  in AString aID,
-                                  in AString aTitle,
-                                  in AString aDir,
-                                  in AString aLang,
-                                  in AString aBody,
-                                  in AString aTag,
-                                  in AString aIcon,
-                                  in AString aData,
-                                  in AString aBehavior);
   void sendPushEvent(in ACString aOriginAttributes,
                      in ACString aScope,
                      in DOMString aData);
   void sendPushSubscriptionChangeEvent(in ACString aOriginAttributes,
                                        in ACString scope);
 
   void updateAllRegistrations();
 };
--- a/dom/interfaces/notification/nsINotificationStorage.idl
+++ b/dom/interfaces/notification/nsINotificationStorage.idl
@@ -1,15 +1,15 @@
 /* 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 "domstubs.idl"
 
-[scriptable, uuid(c1622232-259c-43b0-b52e-89c39dcd9796)]
+[scriptable, uuid(9f1c43b9-f01b-4c87-ad3d-1a86520c2159)]
 interface nsINotificationStorageCallback : nsISupports
 {
   /**
    * Callback function used to pass single notification back
    * into C++ land for Notification.get return data.
    *
    * @param id: a uuid for this notification
    * @param title: the notification title
@@ -23,31 +23,30 @@ interface nsINotificationStorageCallback
   void handle(in DOMString id,
               in DOMString title,
               in DOMString dir,
               in DOMString lang,
               in DOMString body,
               in DOMString tag,
               in DOMString icon,
               in DOMString data,
-              in DOMString behavior,
-              in DOMString serviceWorkerRegistrationID);
+              in DOMString behavior);
 
   /**
    * Callback function used to notify C++ the we have returned
    * all notification objects for this Notification.get call.
    */
   [implicit_jscontext]
   void done();
 };
 
 /**
  * Interface for notification persistence layer.
  */
-[scriptable, uuid(17f85e52-fe57-440e-9ba1-5c312ca02b95)]
+[scriptable, uuid(cac01fb0-c2eb-4252-b2f4-5b1fac933bd4)]
 interface nsINotificationStorage : nsISupports
 {
 
   /**
    * Add/replace a notification to the persistence layer.
    *
    * @param origin: the origin/app of this notification
    * @param id: a uuid for this notification
@@ -57,61 +56,42 @@ interface nsINotificationStorage : nsISu
    * @param lang: the notification language
    * @param body: the notification body
    * @param tag: notification tag, will replace any existing
    *             notifications with same origin/tag pair
    * @param alertName: the alert identifier as used by system app.
    *                   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,
            in DOMString title,
            in DOMString dir,
            in DOMString lang,
            in DOMString body,
            in DOMString tag,
            in DOMString icon,
            in DOMString alertName,
            in DOMString data,
-           in DOMString behavior,
-           in DOMString serviceWorkerRegistrationID);
+           in DOMString behavior);
 
   /**
    * Retrieve a list of notifications.
    *
    * @param origin: the origin/app for which to fetch notifications from
    * @param tag: used to fetch only a specific tag
    * @param callback: nsINotificationStorageCallback, used for
    *                  returning notifications objects
    */
   void get(in DOMString origin,
            in DOMString tag,
            in nsINotificationStorageCallback aCallback);
 
   /**
-   * Retrieve a notification by ID.
-   *
-   * @param origin: the origin/app for which to fetch notifications.
-   * @param id: the id of the notification.
-   * @param callback: nsINotificationStorageCallback whose Handle method will
-   * be called *at most once* if the notification with that ID is found. Not
-   * called if that ID is not found. Done() will be called right after
-   * Handle().
-   */
-  void getByID(in DOMString origin,
-               in DOMString id,
-               in nsINotificationStorageCallback aCallback);
-
-  /**
    * Remove a notification from storage.
    *
    * @param origin: the origin/app to delete the notification from
    * @param id: the uuid for the notification to delete
    */
   void delete(in DOMString origin,
               in DOMString id);
 
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -4,227 +4,166 @@
  * 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 "mozilla/dom/Notification.h"
 #include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/OwningNonNull.h"
 #include "mozilla/dom/Promise.h"
-#include "mozilla/dom/PromiseWorkerProxy.h"
-#include "mozilla/Move.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/unused.h"
 #include "nsContentUtils.h"
 #include "nsIAlertsService.h"
 #include "nsIAppsService.h"
 #include "nsIContentPermissionPrompt.h"
 #include "nsIDocument.h"
 #include "nsINotificationStorage.h"
 #include "nsIPermissionManager.h"
-#include "nsIServiceWorkerManager.h"
 #include "nsIUUIDGenerator.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStructuredCloneContainer.h"
 #include "nsToolkitCompsCID.h"
 #include "nsGlobalWindow.h"
 #include "nsDOMJSUtils.h"
-#include "nsProxyRelease.h"
-#include "nsNetUtil.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIXPConnect.h"
-#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
-#include "mozilla/dom/NotificationEvent.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
+#include "mozilla/dom/Event.h"
 #include "mozilla/Services.h"
 #include "nsContentPermissionHelper.h"
 #include "nsILoadContext.h"
 #ifdef MOZ_B2G
 #include "nsIDOMDesktopNotification.h"
 #endif
 
-#include "ServiceWorkerManager.h"
-#include "WorkerPrivate.h"
-#include "WorkerRunnable.h"
-#include "WorkerScope.h"
-
 namespace mozilla {
 namespace dom {
 
-using namespace workers;
-
-struct NotificationStrings
+class NotificationStorageCallback final : public nsINotificationStorageCallback
 {
-  const nsString mID;
-  const nsString mTitle;
-  const nsString mDir;
-  const nsString mLang;
-  const nsString mBody;
-  const nsString mTag;
-  const nsString mIcon;
-  const nsString mData;
-  const nsString mBehavior;
-  const nsString mServiceWorkerRegistrationID;
-};
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(NotificationStorageCallback)
 
-class ScopeCheckingGetCallback : public nsINotificationStorageCallback
-{
-  const nsString mScope;
-public:
-  NS_DECL_ISUPPORTS
-
-  explicit ScopeCheckingGetCallback(const nsAString& aScope)
-    : mScope(aScope)
-  {}
+  NotificationStorageCallback(const GlobalObject& aGlobal, nsPIDOMWindow* aWindow, Promise* aPromise)
+    : mCount(0),
+      mGlobal(aGlobal.Get()),
+      mWindow(aWindow),
+      mPromise(aPromise)
+  {
+    MOZ_ASSERT(aWindow);
+    MOZ_ASSERT(aPromise);
+    JSContext* cx = aGlobal.Context();
+    JSAutoCompartment ac(cx, mGlobal);
+    mNotifications = JS_NewArrayObject(cx, 0);
+    HoldData();
+  }
 
   NS_IMETHOD Handle(const nsAString& aID,
                     const nsAString& aTitle,
                     const nsAString& aDir,
                     const nsAString& aLang,
                     const nsAString& aBody,
                     const nsAString& aTag,
                     const nsAString& aIcon,
                     const nsAString& aData,
                     const nsAString& aBehavior,
-                    const nsAString& aServiceWorkerRegistrationID,
-                    JSContext* aCx) final
+                    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;
+    options.mBody = aBody;
+    options.mTag = aTag;
+    options.mIcon = aIcon;
+    options.mMozbehavior.Init(aBehavior);
+    nsRefPtr<Notification> notification;
+    notification = Notification::CreateInternal(mWindow,
+                                                aID,
+                                                aTitle,
+                                                options);
+    ErrorResult rv;
+    notification->InitFromBase64(aCx, aData, rv);
+    if (rv.Failed()) {
+      return rv.StealNSResult();
     }
 
-    NotificationStrings strings = {
-      nsString(aID),
-      nsString(aTitle),
-      nsString(aDir),
-      nsString(aLang),
-      nsString(aBody),
-      nsString(aTag),
-      nsString(aIcon),
-      nsString(aData),
-      nsString(aBehavior),
-      nsString(aServiceWorkerRegistrationID),
-    };
+    notification->SetStoredState(true);
 
-    mStrings.AppendElement(Move(strings));
+    JSAutoCompartment ac(aCx, mGlobal);
+    JS::Rooted<JSObject*> element(aCx, notification->WrapObject(aCx, nullptr));
+    NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
+
+    JS::Rooted<JSObject*> notifications(aCx, mNotifications);
+    if (!JS_DefineElement(aCx, notifications, mCount++, element, 0)) {
+      return NS_ERROR_FAILURE;
+    }
     return NS_OK;
   }
 
-  NS_IMETHOD Done(JSContext* aCx) override = 0;
-
-protected:
-  virtual ~ScopeCheckingGetCallback()
-  {}
-
-  nsTArray<NotificationStrings> mStrings;
-};
-
-NS_IMPL_ISUPPORTS(ScopeCheckingGetCallback, nsINotificationStorageCallback)
-
-class NotificationStorageCallback final : public ScopeCheckingGetCallback
-{
-public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(NotificationStorageCallback)
-
-  NotificationStorageCallback(nsIGlobalObject* aWindow, const nsAString& aScope,
-                              Promise* aPromise)
-    : ScopeCheckingGetCallback(aScope),
-      mWindow(aWindow),
-      mPromise(aPromise)
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(aWindow);
-    MOZ_ASSERT(aPromise);
-  }
-
-  NS_IMETHOD Done(JSContext* aCx) final
+  NS_IMETHOD Done(JSContext* aCx) override
   {
-    AutoJSAPI jsapi;
-    DebugOnly<bool> ok = jsapi.Init(mWindow, aCx);
-    MOZ_ASSERT(ok);
-
-    ErrorResult result;
-    nsAutoTArray<nsRefPtr<Notification>, 5> notifications;
-
-    for (uint32_t i = 0; i < mStrings.Length(); ++i) {
-      nsRefPtr<Notification> n =
-        Notification::ConstructFromFields(mWindow,
-                                          mStrings[i].mID,
-                                          mStrings[i].mTitle,
-                                          mStrings[i].mDir,
-                                          mStrings[i].mLang,
-                                          mStrings[i].mBody,
-                                          mStrings[i].mTag,
-                                          mStrings[i].mIcon,
-                                          mStrings[i].mData,
-                                          /* mStrings[i].mBehavior, not
-                                           * supported */
-                                          mStrings[i].mServiceWorkerRegistrationID,
-                                          result);
-
-      n->SetStoredState(true);
-      unused << NS_WARN_IF(result.Failed());
-      if (!result.Failed()) {
-        notifications.AppendElement(n.forget());
-      }
-    }
-
-    mPromise->MaybeResolve(notifications);
+    JSAutoCompartment ac(aCx, mGlobal);
+    JS::Rooted<JS::Value> result(aCx, JS::ObjectValue(*mNotifications));
+    mPromise->MaybeResolve(aCx, result);
     return NS_OK;
   }
 
 private:
   virtual ~NotificationStorageCallback()
-  {}
+  {
+    DropData();
+  }
+
+  void HoldData()
+  {
+    mozilla::HoldJSObjects(this);
+  }
 
-  nsCOMPtr<nsIGlobalObject> mWindow;
+  void DropData()
+  {
+    mGlobal = nullptr;
+    mNotifications = nullptr;
+    mozilla::DropJSObjects(this);
+  }
+
+  uint32_t  mCount;
+  JS::Heap<JSObject *> mGlobal;
+  nsCOMPtr<nsPIDOMWindow> mWindow;
   nsRefPtr<Promise> mPromise;
-  const nsString mScope;
+  JS::Heap<JSObject *> mNotifications;
 };
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(NotificationStorageCallback)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(NotificationStorageCallback)
-NS_IMPL_CYCLE_COLLECTION(NotificationStorageCallback, mWindow, mPromise);
+NS_IMPL_CYCLE_COLLECTION_CLASS(NotificationStorageCallback)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NotificationStorageCallback)
-NS_INTERFACE_MAP_END_INHERITING(ScopeCheckingGetCallback)
+  NS_INTERFACE_MAP_ENTRY(nsINotificationStorageCallback)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
 
-class NotificationGetRunnable final : public nsRunnable
-{
-  const nsString mOrigin;
-  const nsString mTag;
-  nsCOMPtr<nsINotificationStorageCallback> mCallback;
-public:
-  NotificationGetRunnable(const nsAString& aOrigin,
-                          const nsAString& aTag,
-                          nsINotificationStorageCallback* aCallback)
-    : mOrigin(aOrigin), mTag(aTag), mCallback(aCallback)
-  {}
+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
 
-  NS_IMETHOD
-  Run() override
-  {
-    nsresult rv;
-    nsCOMPtr<nsINotificationStorage> notificationStorage =
-      do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID, &rv);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NotificationStorageCallback)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-    rv = notificationStorage->Get(mOrigin, mTag, mCallback);
-    //XXXnsm Is it guaranteed mCallback will be called in case of failure?
-    unused << NS_WARN_IF(NS_FAILED(rv));
-    return rv;
-  }
-};
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(NotificationStorageCallback)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromise)
+  tmp->DropData();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 class NotificationPermissionRequest : public nsIContentPermissionRequest,
                                       public nsIRunnable
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSICONTENTPERMISSIONREQUEST
   NS_DECL_NSIRUNNABLE
@@ -247,258 +186,49 @@ protected:
   nsresult DispatchCallback();
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsPIDOMWindow> mWindow;
   NotificationPermission mPermission;
   nsRefPtr<NotificationPermissionCallback> mCallback;
   nsCOMPtr<nsIContentPermissionRequester> mRequester;
 };
 
-namespace {
-class ReleaseNotificationControlRunnable final : public MainThreadWorkerControlRunnable
+class NotificationObserver : public nsIObserver
 {
-  Notification* mNotification;
-
 public:
-  explicit ReleaseNotificationControlRunnable(Notification* aNotification)
-    : MainThreadWorkerControlRunnable(aNotification->mWorkerPrivate)
-    , mNotification(aNotification)
-  { }
-
-  bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-  {
-    mNotification->ReleaseObject();
-    return true;
-  }
-};
-
-class GetPermissionRunnable final : public WorkerMainThreadRunnable
-{
-  NotificationPermission mPermission;
-
-public:
-  explicit GetPermissionRunnable(WorkerPrivate* aWorker)
-    : WorkerMainThreadRunnable(aWorker)
-    , mPermission(NotificationPermission::Denied)
-  { }
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
 
-  bool
-  MainThreadRun() override
-  {
-    ErrorResult result;
-    mPermission =
-      Notification::GetPermissionInternal(mWorkerPrivate->GetPrincipal(),
-                                          result);
-    return true;
-  }
-
-  NotificationPermission
-  GetPermission()
-  {
-    return mPermission;
-  }
-};
+  explicit NotificationObserver(Notification* aNotification)
+    : mNotification(aNotification) {}
 
-class FocusWindowRunnable final : public nsRunnable
-{
-  nsMainThreadPtrHandle<nsPIDOMWindow> mWindow;
-public:
-  explicit FocusWindowRunnable(const nsMainThreadPtrHandle<nsPIDOMWindow>& aWindow)
-    : mWindow(aWindow)
-  { }
+protected:
+  virtual ~NotificationObserver() {}
 
-  NS_IMETHOD
-  Run()
-  {
-    AssertIsOnMainThread();
-    if (!mWindow->IsCurrentInnerWindow()) {
-      // Window has been closed, this observer is not valid anymore
-      return NS_OK;
-    }
-
-    nsIDocument* doc = mWindow->GetExtantDoc();
-    if (doc) {
-      // Browser UI may use DOMWebNotificationClicked to focus the tab
-      // from which the event was dispatched.
-      nsContentUtils::DispatchChromeEvent(doc, mWindow->GetOuterWindow(),
-                                          NS_LITERAL_STRING("DOMWebNotificationClicked"),
-                                          true, true);
-    }
-
-    return NS_OK;
-  }
+  nsRefPtr<Notification> mNotification;
 };
 
-nsresult
-CheckScope(nsIPrincipal* aPrincipal, const nsACString& aScope)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aPrincipal);
-
-  nsCOMPtr<nsIURI> scopeURI;
-  nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  return aPrincipal->CheckMayLoad(scopeURI, /* report = */ true,
-                                  /* allowIfInheritsPrincipal = */ false);
-}
-} // anonymous namespace
-
-// Subclass that can be directly dispatched to child workers from the main
-// thread.
-class NotificationWorkerRunnable : public WorkerRunnable
-{
-protected:
-  explicit NotificationWorkerRunnable(WorkerPrivate* aWorkerPrivate)
-    : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
-  {
-  }
-
-  bool
-  PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-  {
-    return true;
-  }
-
-  void
-  PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
-               bool aDispatchResult) override
-  {
-  }
-
-  bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-  {
-    aWorkerPrivate->AssertIsOnWorkerThread();
-    aWorkerPrivate->ModifyBusyCountFromWorker(aCx, true);
-    WorkerRunInternal(aCx, aWorkerPrivate);
-    return true;
-  }
-
-  void
-  PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
-          bool aRunResult) override
-  {
-    aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false);
-  }
-
-  virtual void
-  WorkerRunInternal(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
-};
-
-// Overrides dispatch and run handlers so we can directly dispatch from main
-// thread to child workers.
-class NotificationEventWorkerRunnable final : public NotificationWorkerRunnable
-{
-  Notification* mNotification;
-  const nsString mEventName;
-public:
-  NotificationEventWorkerRunnable(Notification* aNotification,
-                                  const nsString& aEventName)
-    : NotificationWorkerRunnable(aNotification->mWorkerPrivate)
-    , mNotification(aNotification)
-    , mEventName(aEventName)
-  {}
-
-  void
-  WorkerRunInternal(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-  {
-    mNotification->DispatchTrustedEvent(mEventName);
-  }
-};
-
-// Create one whenever you require ownership of the notification. Use with
-// UniquePtr<>. See Notification.h for details.
-class NotificationRef final {
-  friend class WorkerNotificationObserver;
-
-private:
-  Notification* mNotification;
-  bool mInited;
-
-  // Only useful for workers.
-  void
-  Forget()
-  {
-    mNotification = nullptr;
-  }
-
-public:
-  explicit NotificationRef(Notification* aNotification)
-    : mNotification(aNotification)
-  {
-    MOZ_ASSERT(mNotification);
-    if (mNotification->mWorkerPrivate) {
-      mNotification->mWorkerPrivate->AssertIsOnWorkerThread();
-    } else {
-      AssertIsOnMainThread();
-    }
-
-    mInited = mNotification->AddRefObject();
-  }
-
-  // This is only required because Gecko runs script in a worker's onclose
-  // handler (non-standard, Bug 790919) where calls to AddFeature() will fail.
-  // Due to non-standardness and added complications if we decide to support
-  // this, attempts to create a Notification in onclose just throw exceptions.
-  bool
-  Initialized()
-  {
-    return mInited;
-  }
-
-  ~NotificationRef()
-  {
-    if (Initialized() && mNotification) {
-      if (mNotification->mWorkerPrivate && NS_IsMainThread()) {
-        nsRefPtr<ReleaseNotificationControlRunnable> r =
-          new ReleaseNotificationControlRunnable(mNotification);
-        AutoSafeJSContext cx;
-        if (!r->Dispatch(cx)) {
-          MOZ_CRASH("Will leak worker thread Notification!");
-        }
-      } else {
-        mNotification->AssertIsOnTargetThread();
-        mNotification->ReleaseObject();
-      }
-      mNotification = nullptr;
-    }
-  }
-
-  // XXXnsm, is it worth having some sort of WeakPtr like wrapper instead of
-  // a rawptr that the NotificationRef can invalidate?
-  Notification*
-  GetNotification()
-  {
-    MOZ_ASSERT(Initialized());
-    return mNotification;
-  }
-};
-
-class NotificationTask : public nsRunnable
+class NotificationTask : public nsIRunnable
 {
 public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIRUNNABLE
+
   enum NotificationAction {
     eShow,
     eClose
   };
 
-  NotificationTask(UniquePtr<NotificationRef> aRef, NotificationAction aAction)
-    : mNotificationRef(Move(aRef)), mAction(aAction)
-  {}
+  NotificationTask(Notification* aNotification, NotificationAction aAction)
+    : mNotification(aNotification), mAction(aAction) {}
 
-  NS_IMETHOD
-  Run() override;
 protected:
   virtual ~NotificationTask() {}
 
-  UniquePtr<NotificationRef> mNotificationRef;
+  nsRefPtr<Notification> mNotification;
   NotificationAction mAction;
 };
 
 uint32_t Notification::sCount = 0;
 
 NS_IMPL_CYCLE_COLLECTION(NotificationPermissionRequest, mWindow)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NotificationPermissionRequest)
@@ -618,275 +348,198 @@ NotificationPermissionRequest::GetTypes(
 {
   nsTArray<nsString> emptyOptions;
   return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
                                                          NS_LITERAL_CSTRING("unused"),
                                                          emptyOptions,
                                                          aTypes);
 }
 
-class NotificationObserver : public nsIObserver
-{
-public:
-  UniquePtr<NotificationRef> mNotificationRef;
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIOBSERVER
-
-  explicit NotificationObserver(UniquePtr<NotificationRef> aRef)
-    : mNotificationRef(Move(aRef))
-  {
-    AssertIsOnMainThread();
-  }
-
-protected:
-  virtual ~NotificationObserver()
-  {
-    AssertIsOnMainThread();
-  }
-};
-
-NS_IMPL_ISUPPORTS(NotificationObserver, nsIObserver)
+NS_IMPL_ISUPPORTS(NotificationTask, nsIRunnable)
 
 NS_IMETHODIMP
 NotificationTask::Run()
 {
-  AssertIsOnMainThread();
-
-  // Get a pointer to notification before the notification takes ownership of
-  // the ref (it owns itself temporarily, with ShowInternal() and
-  // CloseInternal() passing on the ownership appropriately.)
-  Notification* notif = mNotificationRef->GetNotification();
-  notif->mTempRef.swap(mNotificationRef);
-  if (mAction == eShow) {
-    notif->ShowInternal();
-  } else if (mAction == eClose) {
-    notif->CloseInternal();
-  } else {
-    MOZ_CRASH("Invalid action");
+  switch (mAction) {
+  case eShow:
+    mNotification->ShowInternal();
+    break;
+  case eClose:
+    mNotification->CloseInternal();
+    break;
+  default:
+    MOZ_CRASH("Unexpected action for NotificationTask.");
   }
-
-  MOZ_ASSERT(!mNotificationRef);
   return NS_OK;
 }
 
-// static
-bool
-Notification::PrefEnabled(JSContext* aCx, JSObject* aObj)
+NS_IMPL_ISUPPORTS(NotificationObserver, nsIObserver)
+
+NS_IMETHODIMP
+NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
+                              const char16_t* aData)
 {
-  if (NS_IsMainThread()) {
-    return Preferences::GetBool("dom.webnotifications.enabled", false);
-  }
-
-  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
-  if (!workerPrivate) {
-    return false;
+  nsCOMPtr<nsPIDOMWindow> window = mNotification->GetOwner();
+  if (!window || !window->IsCurrentInnerWindow()) {
+    // Window has been closed, this observer is not valid anymore
+    return NS_ERROR_FAILURE;
   }
 
-  return workerPrivate->DOMWorkerNotificationEnabled();
+  if (!strcmp("alertclickcallback", aTopic)) {
+    nsCOMPtr<nsIDOMEvent> event;
+    NS_NewDOMEvent(getter_AddRefs(event), mNotification, nullptr, nullptr);
+    nsresult rv = event->InitEvent(NS_LITERAL_STRING("click"), false, true);
+    NS_ENSURE_SUCCESS(rv, rv);
+    event->SetTrusted(true);
+    WantsPopupControlCheck popupControlCheck(event);
+    bool doDefaultAction = true;
+    mNotification->DispatchEvent(event, &doDefaultAction);
+    if (doDefaultAction) {
+      nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
+      if (doc) {
+        // Browser UI may use DOMWebNotificationClicked to focus the tab
+        // from which the event was dispatched.
+        nsContentUtils::DispatchChromeEvent(doc, window->GetOuterWindow(),
+                                            NS_LITERAL_STRING("DOMWebNotificationClicked"),
+                                            true, true);
+      }
+    }
+  } else if (!strcmp("alertfinished", aTopic)) {
+    nsCOMPtr<nsINotificationStorage> notificationStorage =
+      do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID);
+    if (notificationStorage && mNotification->IsStored()) {
+      nsString origin;
+      nsresult rv = Notification::GetOrigin(mNotification->GetOwner(), origin);
+      if (NS_SUCCEEDED(rv)) {
+        nsString id;
+        mNotification->GetID(id);
+        notificationStorage->Delete(origin, id);
+      }
+      mNotification->SetStoredState(false);
+    }
+    mNotification->mIsClosed = true;
+    mNotification->DispatchTrustedEvent(NS_LITERAL_STRING("close"));
+  } else if (!strcmp("alertshow", aTopic)) {
+    mNotification->DispatchTrustedEvent(NS_LITERAL_STRING("show"));
+  }
+
+  return NS_OK;
 }
 
-// static
-bool
-Notification::IsGetEnabled(JSContext* aCx, JSObject* aObj)
-{
-  return NS_IsMainThread();
-}
-
-Notification::Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
-                           const nsAString& aTitle, const nsAString& aBody,
+Notification::Notification(const nsAString& aID, const nsAString& aTitle, const nsAString& aBody,
                            NotificationDirection aDir, const nsAString& aLang,
                            const nsAString& aTag, const nsAString& aIconUrl,
-                           const NotificationBehavior& aBehavior)
-  : DOMEventTargetHelper(),
-    mWorkerPrivate(nullptr), mObserver(nullptr),
+                           const NotificationBehavior& aBehavior, nsPIDOMWindow* aWindow)
+  : DOMEventTargetHelper(aWindow),
     mID(aID), mTitle(aTitle), mBody(aBody), mDir(aDir), mLang(aLang),
-    mTag(aTag), mIconUrl(aIconUrl), mBehavior(aBehavior), mIsClosed(false),
-    mIsStored(false), mTaskCount(0)
+    mTag(aTag), mIconUrl(aIconUrl), mBehavior(aBehavior), mIsClosed(false), mIsStored(false)
 {
-  if (NS_IsMainThread()) {
-    // We can only call this on the main thread because
-    // Event::SetEventType() called down the call chain when dispatching events
-    // using DOMEventTargetHelper::DispatchTrustedEvent() will assume the event
-    // is a main thread event if it has a valid owner. It will then attempt to
-    // fetch the atom for the event name which asserts main thread only.
-    BindToOwner(aGlobal);
-  } else {
-    mWorkerPrivate = GetCurrentThreadWorkerPrivate();
-    MOZ_ASSERT(mWorkerPrivate);
-  }
-}
-
-void
-Notification::SetAlertName()
-{
-  AssertIsOnMainThread();
-  if (!mAlertName.IsEmpty()) {
-    return;
-  }
-
   nsAutoString alertName;
-  DebugOnly<nsresult> rv = GetOrigin(GetPrincipal(), alertName);
+  DebugOnly<nsresult> rv = GetOrigin(GetOwner(), alertName);
   MOZ_ASSERT(NS_SUCCEEDED(rv), "GetOrigin should not have failed");
 
   // Get the notification name that is unique per origin + tag/ID.
   // The name of the alert is of the form origin#tag/ID.
   alertName.Append('#');
   if (!mTag.IsEmpty()) {
     alertName.AppendLiteral("tag:");
     alertName.Append(mTag);
   } else {
     alertName.AppendLiteral("notag:");
     alertName.Append(mID);
   }
 
   mAlertName = alertName;
 }
 
-// May be called on any thread.
 // static
 already_AddRefed<Notification>
 Notification::Constructor(const GlobalObject& aGlobal,
                           const nsAString& aTitle,
                           const NotificationOptions& aOptions,
                           ErrorResult& aRv)
 {
-  // FIXME(nsm): If the sticky flag is set, throw an error.
-  ServiceWorkerGlobalScope* scope = nullptr;
-  UNWRAP_WORKER_OBJECT(ServiceWorkerGlobalScope, aGlobal.Get(), scope);
-  if (scope) {
-    aRv.ThrowTypeError(MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER);
-    return nullptr;
-  }
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+  MOZ_ASSERT(window, "Window should not be null.");
 
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
-  nsRefPtr<Notification> notification =
-    CreateAndShow(global, aTitle, aOptions, EmptyString(), aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
+  nsRefPtr<Notification> notification = CreateInternal(window,
+                                                       EmptyString(),
+                                                       aTitle,
+                                                       aOptions);
+
+  // Make a structured clone of the aOptions.mData object
+  JS::Rooted<JS::Value> data(aGlobal.Context(), aOptions.mData);
+  notification->InitFromJSVal(aGlobal.Context(), data, aRv);
+  if (aRv.Failed()) {
     return nullptr;
   }
 
-  // This is be ok since we are on the worker thread where this function will
-  // run to completion before the Notification has a chance to go away.
-  return notification.forget();
-}
-
-// static
-already_AddRefed<Notification>
-Notification::ConstructFromFields(
-    nsIGlobalObject* aGlobal,
-    const nsAString& aID,
-    const nsAString& aTitle,
-    const nsAString& aDir,
-    const nsAString& aLang,
-    const nsAString& aBody,
-    const nsAString& aTag,
-    const nsAString& aIcon,
-    const nsAString& aData,
-    const nsAString& aServiceWorkerRegistrationID,
-    ErrorResult& aRv)
-{
-  MOZ_ASSERT(aGlobal);
+  // Queue a task to show the notification.
+  nsCOMPtr<nsIRunnable> showNotificationTask =
+    new NotificationTask(notification, NotificationTask::eShow);
+  NS_DispatchToCurrentThread(showNotificationTask);
 
-  AutoJSAPI jsapi;
-  DebugOnly<bool> ok = jsapi.Init(aGlobal);
-  MOZ_ASSERT(ok);
-
-  RootedDictionary<NotificationOptions> options(jsapi.cx());
-  options.mDir = Notification::StringToDirection(nsString(aDir));
-  options.mLang = aLang;
-  options.mBody = aBody;
-  options.mTag = aTag;
-  options.mIcon = aIcon;
-  nsRefPtr<Notification> notification = CreateInternal(aGlobal, aID, aTitle,
-                                                       options);
-
-  notification->InitFromBase64(jsapi.cx(), aData, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return nullptr;
-  }
-
-  notification->SetScope(aServiceWorkerRegistrationID);
-
-  return notification.forget();
-}
-
-nsresult
-Notification::PersistNotification()
-{
-  AssertIsOnMainThread();
+  // Persist the notification.
   nsresult rv;
   nsCOMPtr<nsINotificationStorage> notificationStorage =
     do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID, &rv);
   if (NS_FAILED(rv)) {
-    return rv;
+    aRv.Throw(rv);
+    return nullptr;
   }
 
   nsString origin;
-  rv = GetOrigin(GetPrincipal(), origin);
-  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  aRv = GetOrigin(window, origin);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
 
   nsString id;
-  GetID(id);
+  notification->GetID(id);
 
   nsString alertName;
-  GetAlertName(alertName);
+  notification->GetAlertName(alertName);
 
   nsString dataString;
   nsCOMPtr<nsIStructuredCloneContainer> scContainer;
-  scContainer = GetDataCloneContainer();
+  scContainer = notification->GetDataCloneContainer();
   if (scContainer) {
     scContainer->GetDataAsBase64(dataString);
   }
 
   nsAutoString behavior;
-  if (!mBehavior.ToJSON(behavior)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  rv = notificationStorage->Put(origin,
-                                id,
-                                mTitle,
-                                DirectionToString(mDir),
-                                mLang,
-                                mBody,
-                                mTag,
-                                mIconUrl,
-                                alertName,
-                                dataString,
-                                behavior,
-                                mScope);
-
-  if (NS_FAILED(rv)) {
-    return rv;
+  if (!aOptions.mMozbehavior.ToJSON(behavior)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  SetStoredState(true);
-  return NS_OK;
-}
+  aRv = notificationStorage->Put(origin,
+                                 id,
+                                 aTitle,
+                                 DirectionToString(aOptions.mDir),
+                                 aOptions.mLang,
+                                 aOptions.mBody,
+                                 aOptions.mTag,
+                                 aOptions.mIcon,
+                                 alertName,
+                                 dataString,
+                                 behavior);
 
-void
-Notification::UnpersistNotification()
-{
-  AssertIsOnMainThread();
-  if (IsStored()) {
-    nsCOMPtr<nsINotificationStorage> notificationStorage =
-      do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID);
-    if (notificationStorage) {
-      nsString origin;
-      nsresult rv = GetOrigin(GetPrincipal(), origin);
-      if (NS_SUCCEEDED(rv)) {
-        notificationStorage->Delete(origin, mID);
-      }
-    }
-    SetStoredState(false);
+  if (aRv.Failed()) {
+    return nullptr;
   }
+
+  notification->SetStoredState(true);
+
+  return notification.forget();
 }
 
 already_AddRefed<Notification>
-Notification::CreateInternal(nsIGlobalObject* aGlobal,
+Notification::CreateInternal(nsPIDOMWindow* aWindow,
                              const nsAString& aID,
                              const nsAString& aTitle,
                              const NotificationOptions& aOptions)
 {
   nsString id;
   if (!aID.IsEmpty()) {
     id = aID;
   } else {
@@ -898,32 +551,29 @@ Notification::CreateInternal(nsIGlobalOb
     NS_ENSURE_SUCCESS(rv, nullptr);
 
     char buffer[NSID_LENGTH];
     uuid.ToProvidedString(buffer);
     NS_ConvertASCIItoUTF16 convertedID(buffer);
     id = convertedID;
   }
 
-  nsRefPtr<Notification> notification = new Notification(aGlobal, id, aTitle,
+  nsRefPtr<Notification> notification = new Notification(id,
+                                                         aTitle,
                                                          aOptions.mBody,
                                                          aOptions.mDir,
                                                          aOptions.mLang,
                                                          aOptions.mTag,
                                                          aOptions.mIcon,
-                                                         aOptions.mMozbehavior);
+                                                         aOptions.mMozbehavior,
+                                                         aWindow);
   return notification.forget();
 }
 
-Notification::~Notification()
-{
-  AssertIsOnTargetThread();
-  MOZ_ASSERT(!mFeature);
-  MOZ_ASSERT(!mTempRef);
-}
+Notification::~Notification() {}
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Notification)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDataObjectContainer)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
@@ -935,554 +585,131 @@ NS_IMPL_ADDREF_INHERITED(Notification, D
 NS_IMPL_RELEASE_INHERITED(Notification, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Notification)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 nsIPrincipal*
 Notification::GetPrincipal()
 {
-  AssertIsOnMainThread();
-  if (mWorkerPrivate) {
-    return mWorkerPrivate->GetPrincipal();
-  } else {
-    nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetOwner());
-    NS_ENSURE_TRUE(sop, nullptr);
-    return sop->GetPrincipal();
-  }
-}
-
-class WorkerNotificationObserver final : public NotificationObserver
-{
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIOBSERVER
-
-  explicit WorkerNotificationObserver(UniquePtr<NotificationRef> aRef)
-    : NotificationObserver(Move(aRef))
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(mNotificationRef->GetNotification()->mWorkerPrivate);
-  }
-
-  void
-  ForgetNotification()
-  {
-    AssertIsOnMainThread();
-    mNotificationRef->Forget();
-  }
-
-protected:
-  virtual ~WorkerNotificationObserver()
-  {
-    AssertIsOnMainThread();
-
-    MOZ_ASSERT(mNotificationRef);
-    Notification* notification = mNotificationRef->GetNotification();
-    if (!notification) {
-      return;
-    }
-
-    // Try to pass ownership back to the worker. If the dispatch succeeds we
-    // are guaranteed this runnable will run, and that it will run after queued
-    // event runnables, so event runnables will have a safe pointer to the
-    // Notification.
-    //
-    // If the dispatch fails, the worker isn't running anymore and the event
-    // runnables have already run. We can just let the standard NotificationRef
-    // release routine take over when ReleaseNotificationRunnable gets deleted.
-    class ReleaseNotificationRunnable final : public NotificationWorkerRunnable
-    {
-      UniquePtr<NotificationRef> mNotificationRef;
-    public:
-      explicit ReleaseNotificationRunnable(UniquePtr<NotificationRef> aRef)
-        : NotificationWorkerRunnable(aRef->GetNotification()->mWorkerPrivate)
-        , mNotificationRef(Move(aRef))
-      {}
-
-      void
-      WorkerRunInternal(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-      {
-        UniquePtr<NotificationRef> ref;
-        mozilla::Swap(ref, mNotificationRef);
-        // Gets released at the end of the function.
-      }
-    };
-
-    nsRefPtr<ReleaseNotificationRunnable> r =
-      new ReleaseNotificationRunnable(Move(mNotificationRef));
-    notification = nullptr;
-
-    AutoJSAPI jsapi;
-    jsapi.Init();
-    r->Dispatch(jsapi.cx());
-  }
-};
-
-NS_IMPL_ISUPPORTS_INHERITED0(WorkerNotificationObserver, NotificationObserver)
-
-class ServiceWorkerNotificationObserver final : public nsIObserver
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIOBSERVER
-
-  ServiceWorkerNotificationObserver(const nsAString& aScope,
-                                    nsIPrincipal* aPrincipal,
-                                    const nsAString& aID)
-    : mScope(aScope), mID(aID), mPrincipal(aPrincipal)
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(aPrincipal);
-  }
-
-private:
-  ~ServiceWorkerNotificationObserver()
-  {}
-
-  const nsString mScope;
-  const nsString mID;
-  nsCOMPtr<nsIPrincipal> mPrincipal;
-};
-
-NS_IMPL_ISUPPORTS(ServiceWorkerNotificationObserver, nsIObserver)
-
-// For ServiceWorkers.
-bool
-Notification::DispatchNotificationClickEvent()
-{
-  MOZ_ASSERT(mWorkerPrivate);
-  MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
-  mWorkerPrivate->AssertIsOnWorkerThread();
-
-  NotificationEventInit options;
-  options.mNotification = this;
-
-  ErrorResult result;
-  nsRefPtr<EventTarget> target = mWorkerPrivate->GlobalScope();
-  nsRefPtr<NotificationEvent> event =
-    NotificationEvent::Constructor(target,
-                                   NS_LITERAL_STRING("notificationclick"),
-                                   options,
-                                   result);
-  if (NS_WARN_IF(result.Failed())) {
-    return false;
-  }
-
-  event->SetTrusted(true);
-  WantsPopupControlCheck popupControlCheck(event);
-  target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
-  // We always return false since in case of dispatching on the serviceworker,
-  // there is no well defined window to focus. The script may use the
-  // Client.focus() API if it wishes.
-  return false;
-}
-
-bool
-Notification::DispatchClickEvent()
-{
-  AssertIsOnTargetThread();
-  nsCOMPtr<nsIDOMEvent> event;
-  NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
-  nsresult rv = event->InitEvent(NS_LITERAL_STRING("click"), false, true);
-  NS_ENSURE_SUCCESS(rv, false);
-  event->SetTrusted(true);
-  WantsPopupControlCheck popupControlCheck(event);
-  bool doDefaultAction = true;
-  DispatchEvent(event, &doDefaultAction);
-  return doDefaultAction;
-}
-
-// Overrides dispatch and run handlers so we can directly dispatch from main
-// thread to child workers.
-class NotificationClickWorkerRunnable final : public NotificationWorkerRunnable
-{
-  Notification* mNotification;
-  // Optional window that gets focused if click event is not
-  // preventDefault()ed.
-  nsMainThreadPtrHandle<nsPIDOMWindow> mWindow;
-public:
-  NotificationClickWorkerRunnable(Notification* aNotification,
-                                  const nsMainThreadPtrHandle<nsPIDOMWindow>& aWindow)
-    : NotificationWorkerRunnable(aNotification->mWorkerPrivate)
-    , mNotification(aNotification)
-    , mWindow(aWindow)
-  {
-    MOZ_ASSERT_IF(mWorkerPrivate->IsServiceWorker(), !mWindow);
-  }
-
-  void
-  WorkerRunInternal(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-  {
-    bool doDefaultAction = mNotification->DispatchClickEvent();
-    MOZ_ASSERT_IF(mWorkerPrivate->IsServiceWorker(), !doDefaultAction);
-    if (doDefaultAction) {
-      nsRefPtr<FocusWindowRunnable> r = new FocusWindowRunnable(mWindow);
-      NS_DispatchToMainThread(r);
-    }
-  }
-};
-
-NS_IMETHODIMP
-NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
-                              const char16_t* aData)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(mNotificationRef);
-  Notification* notification = mNotificationRef->GetNotification();
-  MOZ_ASSERT(notification);
-  if (!strcmp("alertclickcallback", aTopic)) {
-    nsCOMPtr<nsPIDOMWindow> window = notification->GetOwner();
-    if (NS_WARN_IF(!window || !window->IsCurrentInnerWindow())) {
-      // Window has been closed, this observer is not valid anymore
-      return NS_ERROR_FAILURE;
-    }
-
-    bool doDefaultAction = notification->DispatchClickEvent();
-    if (doDefaultAction) {
-      nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
-      if (doc) {
-        // Browser UI may use DOMWebNotificationClicked to focus the tab
-        // from which the event was dispatched.
-        nsContentUtils::DispatchChromeEvent(doc, window->GetOuterWindow(),
-                                            NS_LITERAL_STRING("DOMWebNotificationClicked"),
-                                            true, true);
-      }
-    }
-  } else if (!strcmp("alertfinished", aTopic)) {
-    notification->UnpersistNotification();
-    notification->mIsClosed = true;
-    notification->DispatchTrustedEvent(NS_LITERAL_STRING("close"));
-  } else if (!strcmp("alertshow", aTopic)) {
-    notification->DispatchTrustedEvent(NS_LITERAL_STRING("show"));
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-WorkerNotificationObserver::Observe(nsISupports* aSubject, const char* aTopic,
-                                    const char16_t* aData)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(mNotificationRef);
-  // For an explanation of why it is OK to pass this rawptr to the event
-  // runnables, see the Notification class comment.
-  Notification* notification = mNotificationRef->GetNotification();
-  // We can't assert notification here since the feature could've unset it.
-  if (NS_WARN_IF(!notification)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  MOZ_ASSERT(notification->mWorkerPrivate);
-
-  nsRefPtr<WorkerRunnable> r;
-  if (!strcmp("alertclickcallback", aTopic)) {
-    nsPIDOMWindow* window = nullptr;
-    if (!notification->mWorkerPrivate->IsServiceWorker()) {
-      WorkerPrivate* top = notification->mWorkerPrivate;
-      while (top->GetParent()) {
-        top = top->GetParent();
-      }
-
-      window = top->GetWindow();
-      if (NS_WARN_IF(!window || !window->IsCurrentInnerWindow())) {
-        // Window has been closed, this observer is not valid anymore
-        return NS_ERROR_FAILURE;
-      }
-    }
-
-    // Instead of bothering with adding features and other worker lifecycle
-    // management, we simply hold strongrefs to the window and document.
-    nsMainThreadPtrHandle<nsPIDOMWindow> windowHandle(
-      new nsMainThreadPtrHolder<nsPIDOMWindow>(window));
-
-    r = new NotificationClickWorkerRunnable(notification, windowHandle);
-  } else if (!strcmp("alertfinished", aTopic)) {
-    notification->UnpersistNotification();
-    notification->mIsClosed = true;
-    r = new NotificationEventWorkerRunnable(notification,
-                                            NS_LITERAL_STRING("close"));
-  } else if (!strcmp("alertshow", aTopic)) {
-    r = new NotificationEventWorkerRunnable(notification,
-                                            NS_LITERAL_STRING("show"));
-  }
-
-  MOZ_ASSERT(r);
-  AutoSafeJSContext cx;
-  if (!r->Dispatch(cx)) {
-    NS_WARNING("Could not dispatch event to worker notification");
-  }
-  return NS_OK;
-}
-
-class NotificationClickEventCallback final : public nsINotificationStorageCallback
-{
-public:
-  NS_DECL_ISUPPORTS
-
-  NotificationClickEventCallback(nsIPrincipal* aPrincipal,
-                                 const nsAString& aScope)
-  : mPrincipal(aPrincipal), mScope(aScope)
-  {
-    MOZ_ASSERT(aPrincipal);
-  }
-
-  NS_IMETHOD Handle(const nsAString& aID,
-                    const nsAString& aTitle,
-                    const nsAString& aDir,
-                    const nsAString& aLang,
-                    const nsAString& aBody,
-                    const nsAString& aTag,
-                    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();
-
-    nsAutoCString originSuffix;
-    nsresult rv = mPrincipal->GetOriginSuffix(originSuffix);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    nsCOMPtr<nsIServiceWorkerManager> swm =
-      mozilla::services::GetServiceWorkerManager();
-
-    if (swm) {
-      swm->SendNotificationClickEvent(originSuffix,
-                                      NS_ConvertUTF16toUTF8(mScope),
-                                      aID,
-                                      aTitle,
-                                      aDir,
-                                      aLang,
-                                      aBody,
-                                      aTag,
-                                      aIcon,
-                                      aData,
-                                      aBehavior);
-    }
-    return NS_OK;
-  }
-
-  NS_IMETHOD Done(JSContext* aCx) override
-  {
-    return NS_OK;
-  }
-
-private:
-  ~NotificationClickEventCallback()
-  {
-  }
-
-  nsCOMPtr<nsIPrincipal> mPrincipal;
-  nsString mScope;
-};
-
-NS_IMPL_ISUPPORTS(NotificationClickEventCallback, nsINotificationStorageCallback)
-
-NS_IMETHODIMP
-ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
-                                           const char* aTopic,
-                                           const char16_t* aData)
-{
-  AssertIsOnMainThread();
-  // Persistent notifications only care about the click event.
-  if (!strcmp("alertclickcallback", aTopic)) {
-    nsresult rv;
-    nsCOMPtr<nsINotificationStorage> notificationStorage =
-      do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID, &rv);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    nsCOMPtr<nsINotificationStorageCallback> callback =
-      new NotificationClickEventCallback(mPrincipal, mScope);
-
-    nsAutoString origin;
-    rv = Notification::GetOrigin(mPrincipal, origin);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    rv = notificationStorage->GetByID(origin, mID, callback);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-  }
-
-  return NS_OK;
+  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetOwner());
+  NS_ENSURE_TRUE(sop, nullptr);
+  return sop->GetPrincipal();
 }
 
 void
 Notification::ShowInternal()
 {
-  AssertIsOnMainThread();
-  MOZ_ASSERT(mTempRef, "Notification should take ownership of itself before"
-                       "calling ShowInternal!");
-  // A notification can only have one observer and one call to ShowInternal.
-  MOZ_ASSERT(!mObserver);
-
-  // Transfer ownership to local scope so we can either release it at the end
-  // of this function or transfer it to the observer.
-  UniquePtr<NotificationRef> ownership;
-  mozilla::Swap(ownership, mTempRef);
-  MOZ_ASSERT(ownership->GetNotification() == this);
-
-  nsresult rv = PersistNotification();
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Could not persist Notification");
-  }
-
   nsCOMPtr<nsIAlertsService> alertService =
     do_GetService(NS_ALERTSERVICE_CONTRACTID);
 
   ErrorResult result;
-  NotificationPermission permission = NotificationPermission::Denied;
-  if (mWorkerPrivate) {
-    permission = GetPermissionInternal(mWorkerPrivate->GetPrincipal(), result);
-  } else {
-    permission = GetPermissionInternal(GetOwner(), result);
-  }
-  if (permission != NotificationPermission::Granted || !alertService) {
-    if (mWorkerPrivate) {
-      nsRefPtr<NotificationEventWorkerRunnable> r =
-        new NotificationEventWorkerRunnable(this,
-                                            NS_LITERAL_STRING("error"));
-      AutoSafeJSContext cx;
-      if (!r->Dispatch(cx)) {
-        NS_WARNING("Could not dispatch event to worker notification");
-      }
-    } else {
-      DispatchTrustedEvent(NS_LITERAL_STRING("error"));
-    }
+  if (GetPermissionInternal(GetOwner(), result) !=
+    NotificationPermission::Granted || !alertService) {
+    // We do not have permission to show a notification or alert service
+    // is not available.
+    DispatchTrustedEvent(NS_LITERAL_STRING("error"));
     return;
   }
 
-  nsAutoString iconUrl;
+  nsresult rv;
+  nsAutoString absoluteUrl;
   nsAutoString soundUrl;
-  ResolveIconAndSoundURL(iconUrl, soundUrl);
+  // Resolve image URL against document base URI.
+  nsIDocument* doc = GetOwner()->GetExtantDoc();
+  if (doc) {
+    nsCOMPtr<nsIURI> baseUri = doc->GetBaseURI();
+    if (baseUri) {
+      if (mIconUrl.Length() > 0) {
+        nsCOMPtr<nsIURI> srcUri;
+        rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(srcUri),
+                                                       mIconUrl, doc, baseUri);
+        if (NS_SUCCEEDED(rv)) {
+          nsAutoCString src;
+          srcUri->GetSpec(src);
+          absoluteUrl = NS_ConvertUTF8toUTF16(src);
+        }
+      }
+      if (mBehavior.mSoundFile.Length() > 0) {
+        nsCOMPtr<nsIURI> srcUri;
+        rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(srcUri),
+            mBehavior.mSoundFile, doc, baseUri);
+        if (NS_SUCCEEDED(rv)) {
+          nsAutoCString src;
+          srcUri->GetSpec(src);
+          soundUrl = NS_ConvertUTF8toUTF16(src);
+        }
+      }
+    }
+  }
 
-  nsCOMPtr<nsIObserver> observer;
-  if (mScope.IsEmpty()) {
-    // Ownership passed to observer.
-    if (mWorkerPrivate) {
-      // Scope better be set on ServiceWorker initiated requests.
-      MOZ_ASSERT(!mWorkerPrivate->IsServiceWorker());
-      // Keep a pointer so that the feature can tell the observer not to release
-      // the notification.
-      mObserver = new WorkerNotificationObserver(Move(ownership));
-      observer = mObserver;
-    } else {
-      observer = new NotificationObserver(Move(ownership));
-    }
-  } else {
-    // This observer does not care about the Notification. It will be released
-    // at the end of this function.
-    //
-    // The observer is wholly owned by the alerts service.
-    observer = new ServiceWorkerNotificationObserver(mScope, GetPrincipal(), mID);
-  }
-  MOZ_ASSERT(observer);
+  nsCOMPtr<nsIObserver> observer = new NotificationObserver(this);
 
   // mDataObjectContainer might be uninitialized here because the notification
   // was constructed with an undefined data property.
   nsString dataStr;
   if (mDataObjectContainer) {
     mDataObjectContainer->GetDataAsBase64(dataStr);
   }
 
 #ifdef MOZ_B2G
   nsCOMPtr<nsIAppNotificationService> appNotifier =
     do_GetService("@mozilla.org/system-alerts-service;1");
   if (appNotifier) {
-    uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
-    if (mWorkerPrivate) {
-      appId = mWorkerPrivate->GetPrincipal()->GetAppId();
-    } else {
-      nsCOMPtr<nsPIDOMWindow> window = GetOwner();
-      appId = (window.get())->GetDoc()->NodePrincipal()->GetAppId();
-    }
+    nsCOMPtr<nsPIDOMWindow> window = GetOwner();
+    uint32_t appId = (window.get())->GetDoc()->NodePrincipal()->GetAppId();
 
     if (appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
       nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1");
       nsString manifestUrl = EmptyString();
-      nsresult rv = appsService->GetManifestURLByLocalId(appId, manifestUrl);
+      rv = appsService->GetManifestURLByLocalId(appId, manifestUrl);
       if (NS_SUCCEEDED(rv)) {
         mozilla::AutoSafeJSContext cx;
         JS::Rooted<JS::Value> val(cx);
         AppNotificationServiceOptions ops;
         ops.mTextClickable = true;
         ops.mManifestURL = manifestUrl;
-        GetAlertName(ops.mId);
+        ops.mId = mAlertName;
         ops.mDbId = mID;
         ops.mDir = DirectionToString(mDir);
         ops.mLang = mLang;
         ops.mTag = mTag;
         ops.mData = dataStr;
         ops.mMozbehavior = mBehavior;
         ops.mMozbehavior.mSoundFile = soundUrl;
 
         if (!ToJSValue(cx, ops, &val)) {
           NS_WARNING("Converting dict to object failed!");
           return;
         }
 
-        appNotifier->ShowAppNotification(iconUrl, mTitle, mBody,
+        appNotifier->ShowAppNotification(absoluteUrl, mTitle, mBody,
                                          observer, val);
         return;
       }
     }
   }
 #endif
 
   // In the case of IPC, the parent process uses the cookie to map to
   // nsIObserver. Thus the cookie must be unique to differentiate observers.
   nsString uniqueCookie = NS_LITERAL_STRING("notification:");
   uniqueCookie.AppendInt(sCount++);
-  //XXXnsm Should this default to true?
   bool inPrivateBrowsing = false;
-  nsIDocument* doc = mWorkerPrivate ? mWorkerPrivate->GetDocument()
-                                    : GetOwner()->GetExtantDoc();
   if (doc) {
     nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
     inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
-  } else if (mWorkerPrivate) {
-    // Not all workers may have a document, but with Bug 1107516 fixed, they
-    // should all have a loadcontext.
-    nsCOMPtr<nsILoadGroup> loadGroup = mWorkerPrivate->GetLoadGroup();
-    nsCOMPtr<nsILoadContext> loadContext;
-    NS_QueryNotificationCallbacks(nullptr, loadGroup, NS_GET_IID(nsILoadContext),
-                                  getter_AddRefs(loadContext));
-    inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
   }
-
-  nsAutoString alertName;
-  GetAlertName(alertName);
-  alertService->ShowAlertNotification(iconUrl, mTitle, mBody, true,
-                                      uniqueCookie, observer, alertName,
+  alertService->ShowAlertNotification(absoluteUrl, mTitle, mBody, true,
+                                      uniqueCookie, observer, mAlertName,
                                       DirectionToString(mDir), mLang,
                                       dataStr, GetPrincipal(),
                                       inPrivateBrowsing);
 }
 
-/* static */ bool
-Notification::RequestPermissionEnabledForScope(JSContext* aCx, JSObject* /* unused */)
-{
-  // requestPermission() is not allowed on workers. The calling page should ask
-  // for permission on the worker's behalf. This is to prevent 'which window
-  // should show the browser pop-up'. See discussion:
-  // http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2013-October/041272.html
-  return NS_IsMainThread();
-}
-
 void
 Notification::RequestPermission(const GlobalObject& aGlobal,
                                 const Optional<OwningNonNull<NotificationPermissionCallback> >& aCallback,
                                 ErrorResult& aRv)
 {
   // Get principal from global to make permission request for notifications.
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal.GetAsSupports());
@@ -1497,71 +724,39 @@ Notification::RequestPermission(const Gl
     permissionCallback = &aCallback.Value();
   }
   nsCOMPtr<nsIRunnable> request =
     new NotificationPermissionRequest(principal, window, permissionCallback);
 
   NS_DispatchToMainThread(request);
 }
 
-// static
 NotificationPermission
 Notification::GetPermission(const GlobalObject& aGlobal, ErrorResult& aRv)
 {
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
-  return GetPermission(global, aRv);
+  return GetPermissionInternal(aGlobal.GetAsSupports(), aRv);
 }
 
-// static
 NotificationPermission
-Notification::GetPermission(nsIGlobalObject* aGlobal, ErrorResult& aRv)
-{
-  if (NS_IsMainThread()) {
-    return GetPermissionInternal(aGlobal, aRv);
-  } else {
-    WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
-    MOZ_ASSERT(worker);
-    nsRefPtr<GetPermissionRunnable> r =
-      new GetPermissionRunnable(worker);
-    if (!r->Dispatch(worker->GetJSContext())) {
-      aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
-      return NotificationPermission::Denied;
-    }
-
-    return r->GetPermission();
-  }
-}
-
-/* static */ NotificationPermission
 Notification::GetPermissionInternal(nsISupports* aGlobal, ErrorResult& aRv)
 {
   // Get principal from global to check permission for notifications.
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal);
   if (!sop) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return NotificationPermission::Denied;
   }
 
   nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
-  return GetPermissionInternal(principal, aRv);
-}
-
-/* static */ NotificationPermission
-Notification::GetPermissionInternal(nsIPrincipal* aPrincipal,
-                                    ErrorResult& aRv)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(aPrincipal);
-
-  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+  if (nsContentUtils::IsSystemPrincipal(principal)) {
     return NotificationPermission::Granted;
   } else {
     // Allow files to show notifications by default.
     nsCOMPtr<nsIURI> uri;
-    aPrincipal->GetURI(getter_AddRefs(uri));
+    principal->GetURI(getter_AddRefs(uri));
     if (uri) {
       bool isFile;
       uri->SchemeIs("file", &isFile);
       if (isFile) {
         return NotificationPermission::Granted;
       }
     }
   }
@@ -1575,393 +770,138 @@ Notification::GetPermissionInternal(nsIP
     }
   }
 
   uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
 
   nsCOMPtr<nsIPermissionManager> permissionManager =
     services::GetPermissionManager();
 
-  permissionManager->TestPermissionFromPrincipal(aPrincipal,
+  permissionManager->TestPermissionFromPrincipal(principal,
                                                  "desktop-notification",
                                                  &permission);
 
   // Convert the result to one of the enum types.
   switch (permission) {
   case nsIPermissionManager::ALLOW_ACTION:
     return NotificationPermission::Granted;
   case nsIPermissionManager::DENY_ACTION:
     return NotificationPermission::Denied;
   default:
     return NotificationPermission::Default;
   }
 }
 
-nsresult
-Notification::ResolveIconAndSoundURL(nsString& iconUrl, nsString& soundUrl)
-{
-  AssertIsOnMainThread();
-  nsresult rv = NS_OK;
-
-  nsCOMPtr<nsIURI> baseUri;
-
-  // XXXnsm If I understand correctly, the character encoding for resolving
-  // URIs in new specs is dictated by the URL spec, which states that unless
-  // the URL parser is passed an override encoding, the charset to be used is
-  // UTF-8. The new Notification icon/sound specification just says to use the
-  // Fetch API, where the Request constructor defers to URL parsing specifying
-  // the API base URL and no override encoding. So we've to use UTF-8 on
-  // workers, but for backwards compat keeping it document charset on main
-  // thread.
-  const char* charset = "UTF-8";
-
-  if (mWorkerPrivate) {
-    baseUri = mWorkerPrivate->GetBaseURI();
-  } else {
-    nsIDocument* doc = GetOwner()->GetExtantDoc();
-    if (doc) {
-      baseUri = doc->GetBaseURI();
-      charset = doc->GetDocumentCharacterSet().get();
-    } else {
-      NS_WARNING("No document found for main thread notification!");
-      return NS_ERROR_FAILURE;
-    }
-  }
-
-  if (baseUri) {
-    if (mIconUrl.Length() > 0) {
-      nsCOMPtr<nsIURI> srcUri;
-      rv = NS_NewURI(getter_AddRefs(srcUri), mIconUrl, charset, baseUri);
-      if (NS_SUCCEEDED(rv)) {
-        nsAutoCString src;
-        srcUri->GetSpec(src);
-        iconUrl = NS_ConvertUTF8toUTF16(src);
-      }
-    }
-    if (mBehavior.mSoundFile.Length() > 0) {
-      nsCOMPtr<nsIURI> srcUri;
-      rv = NS_NewURI(getter_AddRefs(srcUri), mBehavior.mSoundFile, charset, baseUri);
-      if (NS_SUCCEEDED(rv)) {
-        nsAutoCString src;
-        srcUri->GetSpec(src);
-        soundUrl = NS_ConvertUTF8toUTF16(src);
-      }
-    }
-  }
-
-  return rv;
-}
-
 already_AddRefed<Promise>
-Notification::Get(nsPIDOMWindow* aWindow,
+Notification::Get(const GlobalObject& aGlobal,
                   const GetNotificationOptions& aFilter,
-                  const nsAString& aScope,
                   ErrorResult& aRv)
 {
-  MOZ_ASSERT(aWindow);
-
-  nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
+  nsCOMPtr<nsIGlobalObject> global =
+    do_QueryInterface(aGlobal.GetAsSupports());
+  MOZ_ASSERT(global);
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global);
+  MOZ_ASSERT(window);
+  nsIDocument* doc = window->GetExtantDoc();
   if (!doc) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsString origin;
-  aRv = GetOrigin(doc->NodePrincipal(), origin);
+  aRv = GetOrigin(window, origin);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aWindow);
+  nsresult rv;
+  nsCOMPtr<nsINotificationStorage> notificationStorage =
+    do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID, &rv);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return nullptr;
+  }
+
   nsRefPtr<Promise> promise = Promise::Create(global, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
-
   nsCOMPtr<nsINotificationStorageCallback> callback =
-    new NotificationStorageCallback(global, aScope, promise);
-
-  nsRefPtr<NotificationGetRunnable> r =
-    new NotificationGetRunnable(origin, aFilter.mTag, callback);
-
-  aRv = NS_DispatchToMainThread(r);
-  if (NS_WARN_IF(aRv.Failed())) {
+    new NotificationStorageCallback(aGlobal, window, promise);
+  nsString tag = aFilter.mTag.WasPassed() ?
+                 aFilter.mTag.Value() :
+                 EmptyString();
+  aRv = notificationStorage->Get(origin, tag, callback);
+  if (aRv.Failed()) {
     return nullptr;
   }
 
   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);
-}
-
-class WorkerGetResultRunnable final : public NotificationWorkerRunnable
-{
-  nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
-  const nsTArray<NotificationStrings> mStrings;
-public:
-  WorkerGetResultRunnable(WorkerPrivate* aWorkerPrivate,
-                          PromiseWorkerProxy* aPromiseProxy,
-                          const nsTArray<NotificationStrings>&& aStrings)
-    : NotificationWorkerRunnable(aWorkerPrivate)
-    , mPromiseProxy(aPromiseProxy)
-    , mStrings(Move(aStrings))
-  {
-  }
-
-  void
-  WorkerRunInternal(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-  {
-    nsRefPtr<Promise> workerPromise = mPromiseProxy->GetWorkerPromise();
-
-    ErrorResult result;
-    nsAutoTArray<nsRefPtr<Notification>, 5> notifications;
-    for (uint32_t i = 0; i < mStrings.Length(); ++i) {
-      nsRefPtr<Notification> n =
-        Notification::ConstructFromFields(aWorkerPrivate->GlobalScope(),
-                                          mStrings[i].mID,
-                                          mStrings[i].mTitle,
-                                          mStrings[i].mDir,
-                                          mStrings[i].mLang,
-                                          mStrings[i].mBody,
-                                          mStrings[i].mTag,
-                                          mStrings[i].mIcon,
-                                          mStrings[i].mData,
-                                          /* mStrings[i].mBehavior, not
-                                           * supported */
-                                          mStrings[i].mServiceWorkerRegistrationID,
-                                          result);
-
-      n->SetStoredState(true);
-      unused << NS_WARN_IF(result.Failed());
-      if (!result.Failed()) {
-        notifications.AppendElement(n.forget());
-      }
-    }
-
-    workerPromise->MaybeResolve(notifications);
-    mPromiseProxy->CleanUp(aCx);
-  }
-};
-
-class WorkerGetCallback final : public ScopeCheckingGetCallback
-{
-  nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-
-  WorkerGetCallback(PromiseWorkerProxy* aProxy, const nsAString& aScope)
-    : ScopeCheckingGetCallback(aScope), mPromiseProxy(aProxy)
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(aProxy);
-  }
-
-  NS_IMETHOD Done(JSContext* aCx) final
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(mPromiseProxy, "Was Done() called twice?");
-    MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
-    if (mPromiseProxy->IsClean()) {
-      return NS_OK;
-    }
-
-    MOZ_ASSERT(mPromiseProxy->GetWorkerPrivate());
-    nsRefPtr<WorkerGetResultRunnable> r =
-      new WorkerGetResultRunnable(mPromiseProxy->GetWorkerPrivate(),
-                                  mPromiseProxy,
-                                  Move(mStrings));
-
-    if (!r->Dispatch(aCx)) {
-      nsRefPtr<PromiseWorkerProxyControlRunnable> cr =
-        new PromiseWorkerProxyControlRunnable(mPromiseProxy->GetWorkerPrivate(),
-                                              mPromiseProxy);
-
-      DebugOnly<bool> ok = cr->Dispatch(aCx);
-      MOZ_ASSERT(ok);
-    }
-
-    mPromiseProxy = nullptr;
-    return NS_OK;
-  }
-
-private:
-  ~WorkerGetCallback()
-  {}
-};
-
-NS_IMPL_ISUPPORTS_INHERITED0(WorkerGetCallback, ScopeCheckingGetCallback)
-
-class WorkerGetRunnable final : public nsRunnable
-{
-  nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
-  const nsString mTag;
-  const nsString mScope;
-public:
-  WorkerGetRunnable(WorkerPrivate* aWorkerPrivate,
-                    Promise* aWorkerPromise,
-                    const nsAString& aTag,
-                    const nsAString& aScope)
-    : mTag(aTag), mScope(aScope)
-  {
-    aWorkerPrivate->AssertIsOnWorkerThread();
-    mPromiseProxy =
-      PromiseWorkerProxy::Create(aWorkerPrivate,
-                                 aWorkerPromise);
-
-    if (!mPromiseProxy || !mPromiseProxy->GetWorkerPromise()) {
-      aWorkerPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
-      mPromiseProxy = nullptr;
-    }
-  }
-
-  NS_IMETHOD
-  Run() override
-  {
-    AssertIsOnMainThread();
-    if (!mPromiseProxy) {
-      return NS_OK;
-    }
-
-    nsCOMPtr<nsINotificationStorageCallback> callback =
-      new WorkerGetCallback(mPromiseProxy, mScope);
-
-    AutoJSAPI jsapi;
-    jsapi.Init();
-
-    nsresult rv;
-    nsCOMPtr<nsINotificationStorage> notificationStorage =
-      do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID, &rv);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      callback->Done(jsapi.cx());
-      return rv;
-    }
-
-    MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
-    if (mPromiseProxy->IsClean()) {
-      return NS_OK;
-    }
-
-    nsString origin;
-    rv =
-      Notification::GetOrigin(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(),
-                              origin);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      callback->Done(jsapi.cx());
-      return rv;
-    }
-
-    rv = notificationStorage->Get(origin, mTag, callback);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      callback->Done(jsapi.cx());
-      return rv;
-    }
-
-    return NS_OK;
-  }
-private:
-  ~WorkerGetRunnable()
-  {}
-};
-
-already_AddRefed<Promise>
-Notification::WorkerGet(WorkerPrivate* aWorkerPrivate,
-                        const GetNotificationOptions& aFilter,
-                        const nsAString& aScope,
-                        ErrorResult& aRv)
-{
-  MOZ_ASSERT(aWorkerPrivate);
-  aWorkerPrivate->AssertIsOnWorkerThread();
-  nsRefPtr<Promise> p = Promise::Create(aWorkerPrivate->GlobalScope(), aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return nullptr;
-  }
-
-  nsRefPtr<WorkerGetRunnable> r =
-    new WorkerGetRunnable(aWorkerPrivate, p, aFilter.mTag, aScope);
-  if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(r)))) {
-    aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
-    return nullptr;
-  }
-
-  return p.forget();
-}
-
 JSObject*
 Notification::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return mozilla::dom::NotificationBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 Notification::Close()
 {
-  AssertIsOnTargetThread();
-  auto ref = MakeUnique<NotificationRef>(this);
-  if (!ref->Initialized()) {
-    return;
-  }
-
+  // Queue a task to close the notification.
   nsCOMPtr<nsIRunnable> closeNotificationTask =
-    new NotificationTask(Move(ref), NotificationTask::eClose);
-  nsresult rv = NS_DispatchToMainThread(closeNotificationTask);
-
-  if (NS_FAILED(rv)) {
-    DispatchTrustedEvent(NS_LITERAL_STRING("error"));
-    // If dispatch fails, NotificationTask will release the ref when it goes
-    // out of scope at the end of this function.
-  }
+    new NotificationTask(this, NotificationTask::eClose);
+  NS_DispatchToMainThread(closeNotificationTask);
 }
 
 void
 Notification::CloseInternal()
 {
-  AssertIsOnMainThread();
-  // Transfer ownership (if any) to local scope so we can release it at the end
-  // of this function. This is relevant when the call is from
-  // NotificationTask::Run().
-  UniquePtr<NotificationRef> ownership;
-  mozilla::Swap(ownership, mTempRef);
-
-  SetAlertName();
-  UnpersistNotification();
+  if (mIsStored) {
+    // Don't bail out if notification storage fails, since we still
+    // want to send the close event through the alert service.
+    nsCOMPtr<nsINotificationStorage> notificationStorage =
+      do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID);
+    if (notificationStorage) {
+      nsString origin;
+      nsresult rv = GetOrigin(GetOwner(), origin);
+      if (NS_SUCCEEDED(rv)) {
+        notificationStorage->Delete(origin, mID);
+      }
+    }
+    SetStoredState(false);
+  }
   if (!mIsClosed) {
     nsCOMPtr<nsIAlertsService> alertService =
       do_GetService(NS_ALERTSERVICE_CONTRACTID);
     if (alertService) {
-      nsAutoString alertName;
-      GetAlertName(alertName);
-      alertService->CloseAlert(alertName, GetPrincipal());
+      alertService->CloseAlert(mAlertName, GetPrincipal());
     }
   }
 }
 
 nsresult
-Notification::GetOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin)
+Notification::GetOrigin(nsPIDOMWindow* aWindow, nsString& aOrigin)
 {
-  MOZ_ASSERT(aPrincipal);
-  uint16_t appStatus = aPrincipal->GetAppStatus();
-  uint32_t appId = aPrincipal->GetAppId();
+  if (!aWindow) {
+    return NS_ERROR_FAILURE;
+  }
+  nsresult rv;
+  nsIDocument* doc = aWindow->GetExtantDoc();
+  NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
+  nsIPrincipal* principal = doc->NodePrincipal();
+  NS_ENSURE_TRUE(principal, NS_ERROR_UNEXPECTED);
 
-  nsresult rv;
+  uint16_t appStatus = principal->GetAppStatus();
+  uint32_t appId = principal->GetAppId();
+
   if (appStatus == nsIPrincipal::APP_STATUS_NOT_INSTALLED ||
       appId == nsIScriptSecurityManager::NO_APP_ID ||
       appId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
-    rv = nsContentUtils::GetUTFOrigin(aPrincipal, aOrigin);
+    rv = nsContentUtils::GetUTFOrigin(principal, aOrigin);
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     // If we are in "app code", use manifest URL as unique origin since
     // multiple apps can share the same origin but not same notifications.
     nsCOMPtr<nsIAppsService> appsService =
       do_GetService("@mozilla.org/AppsService;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     appsService->GetManifestURLByLocalId(appId, aOrigin);
@@ -2013,297 +953,11 @@ void Notification::InitFromBase64(JSCont
   }
 
   auto container = new nsStructuredCloneContainer();
   aRv = container->InitFromBase64(aData, JS_STRUCTURED_CLONE_VERSION,
                                   aCx);
   mDataObjectContainer = container;
 }
 
-bool
-Notification::AddRefObject()
-{
-  AssertIsOnTargetThread();
-  MOZ_ASSERT_IF(mWorkerPrivate && !mFeature, mTaskCount == 0);
-  MOZ_ASSERT_IF(mWorkerPrivate && mFeature, mTaskCount > 0);
-  if (mWorkerPrivate && !mFeature) {
-    if (!RegisterFeature()) {
-      return false;
-    }
-  }
-  AddRef();
-  ++mTaskCount;
-  return true;
-}
-
-void
-Notification::ReleaseObject()
-{
-  AssertIsOnTargetThread();
-  MOZ_ASSERT(mTaskCount > 0);
-  MOZ_ASSERT_IF(mWorkerPrivate, mFeature);
-
-  --mTaskCount;
-  if (mWorkerPrivate && mTaskCount == 0) {
-    UnregisterFeature();
-  }
-  Release();
-}
-
-NotificationFeature::NotificationFeature(Notification* aNotification)
-  : mNotification(aNotification)
-{
-  MOZ_ASSERT(mNotification->mWorkerPrivate);
-  mNotification->mWorkerPrivate->AssertIsOnWorkerThread();
-}
-
-/*
- * Called from the worker, runs on main thread, blocks worker.
- *
- * We can freely access mNotification here because the feature supplied it and
- * the Notification owns the feature.
- */
-class CloseNotificationRunnable final
-  : public WorkerMainThreadRunnable
-{
-  Notification* mNotification;
-
-  public:
-  explicit CloseNotificationRunnable(Notification* aNotification)
-    : WorkerMainThreadRunnable(aNotification->mWorkerPrivate)
-    , mNotification(aNotification)
-  {}
-
-  bool
-  MainThreadRun() override
-  {
-    if (mNotification->mObserver) {
-      // The Notify() take's responsibility of releasing the Notification.
-      mNotification->mObserver->ForgetNotification();
-      mNotification->mObserver = nullptr;
-    }
-    mNotification->CloseInternal();
-    return true;
-  }
-};
-
-bool
-NotificationFeature::Notify(JSContext* aCx, Status aStatus)
-{
-  MOZ_ASSERT(aStatus >= Canceling);
-
-  // Dispatched to main thread, blocks on closing the Notification.
-  nsRefPtr<CloseNotificationRunnable> r =
-    new CloseNotificationRunnable(mNotification);
-  r->Dispatch(aCx);
-
-  mNotification->ReleaseObject();
-  // From this point we cannot touch properties of this feature because
-  // ReleaseObject() may have led to the notification going away and the
-  // notification owns this feature!
-  return true;
-}
-
-bool
-Notification::RegisterFeature()
-{
-  MOZ_ASSERT(mWorkerPrivate);
-  mWorkerPrivate->AssertIsOnWorkerThread();
-  MOZ_ASSERT(!mFeature);
-  mFeature = MakeUnique<NotificationFeature>(this);
-  return mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(),
-                                    mFeature.get());
-}
-
-void
-Notification::UnregisterFeature()
-{
-  MOZ_ASSERT(mWorkerPrivate);
-  mWorkerPrivate->AssertIsOnWorkerThread();
-  MOZ_ASSERT(mFeature);
-  mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(),
-                                mFeature.get());
-  mFeature = nullptr;
-}
-
-/*
- * Checks:
- * 1) Is aWorker allowed to show a notification for scope?
- * 2) Is aWorker an active worker?
- *
- * If it is not an active worker, Result() will be NS_ERROR_NOT_AVAILABLE.
- */
-class CheckLoadRunnable final : public WorkerMainThreadRunnable
-{
-  nsresult mRv;
-  nsCString mScope;
-
-public:
-  explicit CheckLoadRunnable(WorkerPrivate* aWorker, const nsACString& aScope)
-    : WorkerMainThreadRunnable(aWorker)
-    , mRv(NS_ERROR_DOM_SECURITY_ERR)
-    , mScope(aScope)
-  { }
-
-  bool
-  MainThreadRun() override
-  {
-    nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
-    mRv = CheckScope(principal, mScope);
-
-    if (NS_FAILED(mRv)) {
-      return true;
-    }
-
-    nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    nsRefPtr<ServiceWorkerRegistrationInfo> registration =
-      swm->GetRegistration(principal, mScope);
-
-    // This is coming from a ServiceWorkerRegistrationWorkerThread.
-    MOZ_ASSERT(registration);
-
-    if (!registration->mActiveWorker ||
-        registration->mActiveWorker->ID() != mWorkerPrivate->ServiceWorkerID()) {
-      mRv = NS_ERROR_NOT_AVAILABLE;
-    }
-
-    return true;
-  }
-
-  nsresult
-  Result()
-  {
-    return mRv;
-  }
-
-};
-
-/* static */
-already_AddRefed<Promise>
-Notification::ShowPersistentNotification(nsIGlobalObject *aGlobal,
-                                         const nsAString& aScope,
-                                         const nsAString& aTitle,
-                                         const NotificationOptions& aOptions,
-                                         ErrorResult& aRv)
-{
-  MOZ_ASSERT(aGlobal);
-
-  // Validate scope.
-  // XXXnsm: This may be slow due to blocking the worker and waiting on the main
-  // thread. On calls from content, we can be sure the scope is valid since
-  // ServiceWorkerRegistrations have their scope set correctly. Can this be made
-  // debug only? The problem is that there would be different semantics in
-  // debug and non-debug builds in such a case.
-  if (NS_IsMainThread()) {
-    nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal);
-    if (NS_WARN_IF(!sop)) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
-
-    nsIPrincipal* principal = sop->GetPrincipal();
-    if (NS_WARN_IF(!principal)) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
-
-    aRv = CheckScope(principal, NS_ConvertUTF16toUTF8(aScope));
-    if (NS_WARN_IF(aRv.Failed())) {
-      aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-      return nullptr;
-    }
-  } else {
-    WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
-    MOZ_ASSERT(worker);
-    worker->AssertIsOnWorkerThread();
-    nsRefPtr<CheckLoadRunnable> loadChecker =
-      new CheckLoadRunnable(worker, NS_ConvertUTF16toUTF8(aScope));
-    if (!loadChecker->Dispatch(worker->GetJSContext())) {
-      aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
-      return nullptr;
-    }
-
-    if (NS_WARN_IF(NS_FAILED(loadChecker->Result()))) {
-      if (loadChecker->Result() == NS_ERROR_NOT_AVAILABLE) {
-        aRv.ThrowTypeError(MSG_NO_ACTIVE_WORKER);
-      } else {
-        aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-      }
-      return nullptr;
-    }
-  }
-
-
-  nsRefPtr<Promise> p = Promise::Create(aGlobal, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return nullptr;
-  }
-
-  // We check permission here rather than pass the Promise to NotificationTask
-  // which leads to uglier code.
-  NotificationPermission permission = GetPermission(aGlobal, aRv);
-
-  // "If permission for notification’s origin is not "granted", reject promise with a TypeError exception, and terminate these substeps."
-  if (NS_WARN_IF(aRv.Failed()) || permission == NotificationPermission::Denied) {
-    ErrorResult result;
-    result.ThrowTypeError(MSG_NOTIFICATION_PERMISSION_DENIED);
-    p->MaybeReject(result);
-    return p.forget();
-  }
-
-  // "Otherwise, resolve promise with undefined."
-  // The Notification may still not be shown due to other errors, but the spec
-  // is not concerned with those.
-  p->MaybeResolve(JS::UndefinedHandleValue);
-
-  nsRefPtr<Notification> notification =
-    CreateAndShow(aGlobal, aTitle, aOptions, aScope, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return nullptr;
-  }
-
-  return p.forget();
-}
-
-/* static */ already_AddRefed<Notification>
-Notification::CreateAndShow(nsIGlobalObject* aGlobal,
-                            const nsAString& aTitle,
-                            const NotificationOptions& aOptions,
-                            const nsAString& aScope,
-                            ErrorResult& aRv)
-{
-  MOZ_ASSERT(aGlobal);
-
-  AutoJSAPI jsapi;
-  jsapi.Init(aGlobal);
-  JSContext* cx = jsapi.cx();
-
-  nsRefPtr<Notification> notification = CreateInternal(aGlobal, EmptyString(),
-                                                       aTitle, aOptions);
-
-  // Make a structured clone of the aOptions.mData object
-  JS::Rooted<JS::Value> data(cx, aOptions.mData);
-  notification->InitFromJSVal(cx, data, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  notification->SetScope(aScope);
-
-  auto ref = MakeUnique<NotificationRef>(notification);
-  if (!ref->Initialized()) {
-    aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
-    return nullptr;
-  }
-
-  // Queue a task to show the notification.
-  nsCOMPtr<nsIRunnable> showNotificationTask =
-    new NotificationTask(Move(ref), NotificationTask::eShow);
-  nsresult rv = NS_DispatchToMainThread(showNotificationTask);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    notification->DispatchTrustedEvent(NS_LITERAL_STRING("error"));
-  }
-
-  return notification.forget();
-}
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/notification/Notification.h
+++ b/dom/notification/Notification.h
@@ -3,169 +3,53 @@
 /* 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_notification_h__
 #define mozilla_dom_notification_h__
 
 #include "mozilla/DOMEventTargetHelper.h"
-#include "mozilla/UniquePtr.h"
 #include "mozilla/dom/NotificationBinding.h"
-#include "mozilla/dom/workers/bindings/WorkerFeature.h"
 
 #include "nsIObserver.h"
 
 #include "nsCycleCollectionParticipant.h"
 
 class nsIPrincipal;
 class nsIStructuredCloneContainer;
 class nsIVariant;
 
 namespace mozilla {
 namespace dom {
 
-class NotificationRef;
-class WorkerNotificationObserver;
+
+class NotificationObserver;
 class Promise;
 
-namespace workers {
-  class WorkerPrivate;
-} // namespace workers
-
-class Notification;
-class NotificationFeature final : public workers::WorkerFeature
-{
-  // Since the feature is strongly held by a Notification, it is ok to hold
-  // a raw pointer here.
-  Notification* mNotification;
-
-public:
-  explicit NotificationFeature(Notification* aNotification);
-
-  bool
-  Notify(JSContext* aCx, workers::Status aStatus) override;
-};
-
-
-/*
- * Notifications on workers introduce some lifetime issues. The property we
- * are trying to satisfy is:
- *   Whenever a task is dispatched to the main thread to operate on
- *   a Notification, the Notification should be addrefed on the worker thread
- *   and a feature should be added to observe the worker lifetime. This main
- *   thread owner should ensure it properly releases the reference to the
- *   Notification, additionally removing the feature if necessary.
- *
- * To enforce the correct addref and release, along with managing the feature,
- * we introduce a NotificationRef. Only one object may ever own
- * a NotificationRef, so UniquePtr<> is used throughout.  The NotificationRef
- * constructor calls AddRefObject(). When it is destroyed (on any thread) it
- * releases the Notification on the correct thread.
- *
- * Code should only access the underlying Notification object when it can
- * guarantee that it retains ownership of the NotificationRef while doing so.
- *
- * The one kink in this mechanism is that the worker feature may be Notify()ed
- * if the worker stops running script, even if the Notification's corresponding
- * UI is still visible to the user. We handle this case with the following
- * steps:
- *   a) Close the notification. This is done by blocking the worker on the main
- *   thread. This ensures that there are no main thread holders when the worker
- *   resumes. This also deals with the case where Notify() runs on the worker
- *   before the observer has been created on the main thread. Even in such
- *   a situation, the CloseNotificationRunnable() will only run after the
- *   Show task that was previously queued. Since the show task is only queued
- *   once when the Notification is created, we can be sure that no new tasks
- *   will follow the Notify().
- *
- *   b) Ask the observer to let go of its NotificationRef's underlying
- *   Notification without proper cleanup since the feature will handle the
- *   release. This is only OK because every notification has only one
- *   associated observer. The NotificationRef itself is still owned by the
- *   observer and deleted by the UniquePtr, but it doesn't do anything since
- *   the underlying Notification is null.
- *
- * To unify code-paths, we use the same NotificationRef in the main
- * thread implementation too.
- *
- * Note that the Notification's JS wrapper does it's standard
- * AddRef()/Release() and is not affected by any of this.
- *
- * There is one case related to the WorkerNotificationObserver having to
- * dispatch WorkerRunnables to the worker thread which will use the
- * Notification object. We can end up in a situation where an event runnable is
- * dispatched to the worker, gets queued in the worker's event queue, but then,
- * the worker yields to the main thread. Here the main thread observer is
- * destroyed, which frees its NotificationRef. The NotificationRef dispatches
- * a ControlRunnable to the worker, which runs before the event runnable,
- * leading to the event runnable possibly not having a valid Notification
- * reference.
- * We solve this problem by having WorkerNotificationObserver's dtor
- * dispatching a standard WorkerRunnable to do the release (this guarantees the
- * ordering of the release is after the event runnables). All WorkerRunnables
- * that get dispatched successfully are guaranteed to run on the worker before
- * it shuts down. If that dispatch fails, the standard ControlRunnable based
- * shutdown is acceptable since the already dispatched event runnables have
- * already run or canceled (the worker is already past Running).
- *
- */
 class Notification : public DOMEventTargetHelper
 {
-  friend class CloseNotificationRunnable;
   friend class NotificationTask;
   friend class NotificationPermissionRequest;
   friend class NotificationObserver;
   friend class NotificationStorageCallback;
-  friend class ServiceWorkerNotificationObserver;
-  friend class WorkerGetRunnable;
-  friend class WorkerNotificationObserver;
 
 public:
   IMPL_EVENT_HANDLER(click)
   IMPL_EVENT_HANDLER(show)
   IMPL_EVENT_HANDLER(error)
   IMPL_EVENT_HANDLER(close)
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Notification, DOMEventTargetHelper)
 
-  static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
-  // Returns if Notification.get() is allowed for the current global.
-  static bool IsGetEnabled(JSContext* aCx, JSObject* aObj);
-
   static already_AddRefed<Notification> Constructor(const GlobalObject& aGlobal,
                                                     const nsAString& aTitle,
                                                     const NotificationOptions& aOption,
                                                     ErrorResult& aRv);
-
-  /**
-   * Used when dispatching the ServiceWorkerEvent.
-   *
-   * Does not initialize the Notification's behavior.
-   * This is because:
-   * 1) The Notification is not shown to the user and so the behavior
-   *    parameters don't matter.
-   * 2) The default binding requires main thread for parsing the JSON from the
-   *    string behavior.
-   */
-  static already_AddRefed<Notification>
-  ConstructFromFields(
-    nsIGlobalObject* aGlobal,
-    const nsAString& aID,
-    const nsAString& aTitle,
-    const nsAString& aDir,
-    const nsAString& aLang,
-    const nsAString& aBody,
-    const nsAString& aTag,
-    const nsAString& aIcon,
-    const nsAString& aData,
-    const nsAString& aServiceWorkerRegistrationID,
-    ErrorResult& aRv);
-
   void GetID(nsAString& aRetval) {
     aRetval = mID;
   }
 
   void GetTitle(nsAString& aRetval)
   {
     aRetval = mTitle;
   }
@@ -202,105 +86,49 @@ public:
 
   bool IsStored()
   {
     return mIsStored;
   }
 
   nsIStructuredCloneContainer* GetDataCloneContainer();
 
-  static bool RequestPermissionEnabledForScope(JSContext* aCx, JSObject* /* unused */);
-
   static void RequestPermission(const GlobalObject& aGlobal,
                                 const Optional<OwningNonNull<NotificationPermissionCallback> >& aCallback,
                                 ErrorResult& aRv);
 
   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);
 
-  static already_AddRefed<Promise> WorkerGet(workers::WorkerPrivate* aWorkerPrivate,
-                                             const GetNotificationOptions& aFilter,
-                                             const nsAString& aScope,
-                                             ErrorResult& aRv);
-
-  // Notification implementation of
-  // ServiceWorkerRegistration.showNotification.
-  static already_AddRefed<Promise>
-  ShowPersistentNotification(nsIGlobalObject* aGlobal,
-                             const nsAString& aScope,
-                             const nsAString& aTitle,
-                             const NotificationOptions& aOptions,
-                             ErrorResult& aRv);
-
   void Close();
 
   nsPIDOMWindow* GetParentObject()
   {
     return GetOwner();
   }
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
 
   void InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aData, ErrorResult& aRv);
 
   void InitFromBase64(JSContext* aCx, const nsAString& aData, ErrorResult& aRv);
 
-  void AssertIsOnTargetThread() const
-  {
-    MOZ_ASSERT(IsTargetThread());
-  }
-
-  // Initialized on the worker thread, never unset, and always used in
-  // a read-only capacity. Used on any thread.
-  workers::WorkerPrivate* mWorkerPrivate;
-
-  // Main thread only.
-  WorkerNotificationObserver* mObserver;
-
-  // The NotificationTask calls ShowInternal()/CloseInternal() on the
-  // Notification. At this point the task has ownership of the Notification. It
-  // passes this on to the Notification itself via mTempRef so that
-  // ShowInternal()/CloseInternal() may pass it along appropriately (or release
-  // it).
-  //
-  // Main thread only.
-  UniquePtr<NotificationRef> mTempRef;
-
-  // Returns true if addref succeeded.
-  bool AddRefObject();
-  void ReleaseObject();
-
-  static NotificationPermission GetPermission(nsIGlobalObject* aGlobal,
-                                              ErrorResult& aRv);
-
-  static NotificationPermission GetPermissionInternal(nsIPrincipal* aPrincipal,
-                                                      ErrorResult& rv);
-
-  bool DispatchClickEvent();
-  bool DispatchNotificationClickEvent();
 protected:
-  Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
-               const nsAString& aTitle, const nsAString& aBody,
+  Notification(const nsAString& aID, const nsAString& aTitle, const nsAString& aBody,
                NotificationDirection aDir, const nsAString& aLang,
                const nsAString& aTag, const nsAString& aIconUrl,
-               const NotificationBehavior& aBehavior);
+               const NotificationBehavior& aBehavior, nsPIDOMWindow* aWindow);
 
-  static already_AddRefed<Notification> CreateInternal(nsIGlobalObject* aGlobal,
+  static already_AddRefed<Notification> CreateInternal(nsPIDOMWindow* aWindow,
                                                        const nsAString& aID,
                                                        const nsAString& aTitle,
                                                        const NotificationOptions& aOptions);
 
   void ShowInternal();
   void CloseInternal();
 
   static NotificationPermission GetPermissionInternal(nsISupports* aGlobal,
@@ -324,101 +152,51 @@ protected:
       return NotificationDirection::Ltr;
     }
     if (aDirection.EqualsLiteral("rtl")) {
       return NotificationDirection::Rtl;
     }
     return NotificationDirection::Auto;
   }
 
-  static nsresult GetOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin);
+  static nsresult GetOrigin(nsPIDOMWindow* aWindow, nsString& aOrigin);
 
   void GetAlertName(nsAString& aRetval)
   {
-    workers::AssertIsOnMainThread();
-    if (mAlertName.IsEmpty()) {
-      SetAlertName();
-    }
     aRetval = mAlertName;
   }
 
-  void GetScope(nsAString& aScope)
-  {
-    aScope = mScope;
-  }
-
-  void
-  SetScope(const nsAString& aScope)
-  {
-    MOZ_ASSERT(mScope.IsEmpty());
-    mScope = aScope;
-  }
-
-  const nsString mID;
-  const nsString mTitle;
-  const nsString mBody;
-  const NotificationDirection mDir;
-  const nsString mLang;
-  const nsString mTag;
-  const nsString mIconUrl;
+  nsString mID;
+  nsString mTitle;
+  nsString mBody;
+  NotificationDirection mDir;
+  nsString mLang;
+  nsString mTag;
+  nsString mIconUrl;
   nsCOMPtr<nsIStructuredCloneContainer> mDataObjectContainer;
-  const NotificationBehavior mBehavior;
+  NotificationBehavior mBehavior;
 
   // It's null until GetData is first called
   nsCOMPtr<nsIVariant> mData;
 
   nsString mAlertName;
-  nsString mScope;
 
-  // Main thread only.
   bool mIsClosed;
 
   // We need to make a distinction between the notification being closed i.e.
   // removed from any pending or active lists, and the notification being
   // removed from the database. NotificationDB might fail when trying to remove
   // the notification.
   bool mIsStored;
 
   static uint32_t sCount;
 
 private:
   virtual ~Notification();
 
-  // Creates a Notification and shows it. Returns a reference to the
-  // Notification if result is NS_OK. The lifetime of this Notification is tied
-  // to an underlying NotificationRef. Do not hold a non-stack raw pointer to
-  // it. Be careful about thread safety if acquiring a strong reference.
-  static already_AddRefed<Notification>
-  CreateAndShow(nsIGlobalObject* aGlobal,
-                const nsAString& aTitle,
-                const NotificationOptions& aOptions,
-                const nsAString& aScope,
-                ErrorResult& aRv);
-
   nsIPrincipal* GetPrincipal();
-
-  nsresult PersistNotification();
-  void UnpersistNotification();
-
-  void
-  SetAlertName();
-
-  bool IsTargetThread() const
-  {
-    return NS_IsMainThread() == !mWorkerPrivate;
-  }
-
-  bool RegisterFeature();
-  void UnregisterFeature();
-
-  nsresult ResolveIconAndSoundURL(nsString&, nsString&);
-
-  // Only used for Notifications on Workers, worker thread only.
-  UniquePtr<NotificationFeature> mFeature;
-  // Target thread only.
-  uint32_t mTaskCount;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_notification_h__
 
deleted file mode 100644
--- a/dom/notification/NotificationEvent.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=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 "NotificationEvent.h"
-
-using namespace mozilla::dom;
-
-BEGIN_WORKERS_NAMESPACE
-
-NotificationEvent::NotificationEvent(EventTarget* aOwner)
-  : ExtendableEvent(aOwner)
-{
-}
-
-NS_IMPL_ADDREF_INHERITED(NotificationEvent, ExtendableEvent)
-NS_IMPL_RELEASE_INHERITED(NotificationEvent, ExtendableEvent)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(NotificationEvent)
-NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(NotificationEvent, ExtendableEvent, mNotification)
-
-END_WORKERS_NAMESPACE
deleted file mode 100644
--- a/dom/notification/NotificationEvent.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* 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_workers_notificationevent_h__
-#define mozilla_dom_workers_notificationevent_h__
-
-#include "mozilla/dom/Event.h"
-#include "mozilla/dom/NotificationEventBinding.h"
-#include "mozilla/dom/ServiceWorkerEvents.h"
-#include "mozilla/dom/workers/Workers.h"
-
-BEGIN_WORKERS_NAMESPACE
-
-class ServiceWorker;
-class ServiceWorkerClient;
-
-class NotificationEvent final : public ExtendableEvent
-{
-protected:
-  explicit NotificationEvent(EventTarget* aOwner);
-  ~NotificationEvent()
-  {}
-
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(NotificationEvent, ExtendableEvent)
-  NS_FORWARD_TO_EVENT
-
-  virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
-  {
-    return NotificationEventBinding::Wrap(aCx, this, aGivenProto);
-  }
-
-  static already_AddRefed<NotificationEvent>
-  Constructor(mozilla::dom::EventTarget* aOwner,
-              const nsAString& aType,
-              const NotificationEventInit& aOptions,
-              ErrorResult& aRv)
-  {
-    nsRefPtr<NotificationEvent> e = new NotificationEvent(aOwner);
-    bool trusted = e->Init(aOwner);
-    e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
-    e->SetTrusted(trusted);
-    e->mNotification = aOptions.mNotification;
-    e->SetWantsPopupControlCheck(e->IsTrusted());
-    return e.forget();
-  }
-
-  static already_AddRefed<NotificationEvent>
-  Constructor(const GlobalObject& aGlobal,
-              const nsAString& aType,
-              const NotificationEventInit& aOptions,
-              ErrorResult& aRv)
-  {
-    nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
-    return Constructor(owner, aType, aOptions, aRv);
-  }
-
-  already_AddRefed<Notification>
-  Notification_()
-  {
-    nsRefPtr<Notification> n = mNotification;
-    return n.forget();
-  }
-
-private:
-  nsRefPtr<Notification> mNotification;
-};
-
-END_WORKERS_NAMESPACE
-#endif /* mozilla_dom_workers_notificationevent_h__ */
-
--- a/dom/notification/NotificationStorage.js
+++ b/dom/notification/NotificationStorage.js
@@ -1,15 +1,15 @@
 /* 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/. */
 
 "use strict";
 
-const DEBUG = true;
+const DEBUG = false;
 function debug(s) { dump("-*- NotificationStorage.js: " + s + "\n"); }
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
@@ -79,32 +79,31 @@ NotificationStorage.prototype = {
   canPut: function(aOrigin) {
     if (DEBUG) debug("Querying appService for: " + aOrigin);
     let rv = !!appsService.getAppByManifestURL(aOrigin);
     if (DEBUG) debug("appService returned: " + rv);
     return rv;
   },
 
   put: function(origin, id, title, dir, lang, body, tag, icon, alertName,
-                data, behavior, serviceWorkerRegistrationID) {
-    if (DEBUG) { debug("PUT: " + origin + " " + id + ": " + title); }
+                data, behavior) {
+    if (DEBUG) { debug("PUT: " + id + ": " + title); }
     var notification = {
       id: id,
       title: title,
       dir: dir,
       lang: lang,
       body: body,
       tag: tag,
       icon: icon,
       alertName: alertName,
       timestamp: new Date().getTime(),
       origin: origin,
       data: data,
-      mozbehavior: behavior,
-      serviceWorkerRegistrationID: serviceWorkerRegistrationID,
+      mozbehavior: behavior
     };
 
     this._notifications[id] = notification;
     if (tag) {
       if (!this._byTag[origin]) {
         this._byTag[origin] = {};
       }
 
@@ -130,35 +129,16 @@ NotificationStorage.prototype = {
     if (DEBUG) { debug("GET: " + origin + " " + tag); }
     if (this._cached) {
       this._fetchFromCache(origin, tag, callback);
     } else {
       this._fetchFromDB(origin, tag, callback);
     }
   },
 
-  getByID: function(origin, id, callback) {
-    if (DEBUG) { debug("GETBYID: " + origin + " " + id); }
-    var GetByIDProxyCallback = function(id, originalCallback) {
-      this.searchID = id;
-      this.originalCallback = originalCallback;
-      var self = this;
-      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, serviceWorkerRegistrationID);
-        }
-      };
-      this.done = function() {
-        self.originalCallback.done();
-      };
-    };
-
-    return this.get(origin, "", new GetByIDProxyCallback(id, callback));
-  },
-
   delete: function(origin, id) {
     if (DEBUG) { debug("DELETE: " + id); }
     var notification = this._notifications[id];
     if (notification) {
       if (notification.tag) {
         delete this._byTag[origin][notification.tag];
       }
       delete this._notifications[id];
@@ -226,40 +206,33 @@ NotificationStorage.prototype = {
       for (var id in this._notifications) {
         if (this._notifications[id].origin === origin) {
           notifications.push(this._notifications[id]);
         }
       }
     }
 
     // Pass each notification back separately.
-    // The callback is called asynchronously to match the behaviour when
-    // fetching from the database.
     notifications.forEach(function(notification) {
       try {
-        Services.tm.currentThread.dispatch(
-          callback.handle.bind(callback,
-                               notification.id,
-                               notification.title,
-                               notification.dir,
-                               notification.lang,
-                               notification.body,
-                               notification.tag,
-                               notification.icon,
-                               notification.data,
-                               notification.mozbehavior,
-                               notification.serviceWorkerRegistrationID),
-          Ci.nsIThread.DISPATCH_NORMAL);
+        callback.handle(notification.id,
+                        notification.title,
+                        notification.dir,
+                        notification.lang,
+                        notification.body,
+                        notification.tag,
+                        notification.icon,
+                        notification.data,
+                        notification.mozbehavior);
       } catch (e) {
         if (DEBUG) { debug("Error calling callback handle: " + e); }
       }
     });
     try {
-      Services.tm.currentThread.dispatch(callback.done,
-                                         Ci.nsIThread.DISPATCH_NORMAL);
+      callback.done();
     } catch (e) {
       if (DEBUG) { debug("Error calling callback done: " + e); }
     }
   },
 
   _populateCache: function(notifications) {
     notifications.forEach(function(notification) {
       this._notifications[notification.id] = notification;
--- a/dom/notification/moz.build
+++ b/dom/notification/moz.build
@@ -13,29 +13,26 @@ EXTRA_COMPONENTS += [
 
 EXTRA_JS_MODULES += [
     'NotificationDB.jsm'
 ]
 
 EXPORTS.mozilla.dom += [
     'DesktopNotification.h',
     'Notification.h',
-    'NotificationEvent.h',
 ]
 
 UNIFIED_SOURCES += [
     'DesktopNotification.cpp',
     'Notification.cpp',
-    'NotificationEvent.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/dom/base',
     '/dom/ipc',
-    '/dom/workers',
 ]
 
 XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -1606,19 +1606,19 @@ PromiseWorkerProxyControlRunnable::Worke
 
 void
 PromiseWorkerProxy::RunCallback(JSContext* aCx,
                                 JS::Handle<JS::Value> aValue,
                                 RunCallbackFunc aFunc)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  MutexAutoLock lock(GetCleanUpLock());
+  MutexAutoLock lock(mCleanUpLock);
   // If the worker thread's been cancelled we don't need to resolve the Promise.
-  if (IsClean()) {
+  if (mCleanedUp) {
     return;
   }
 
   // The |aValue| is written into the buffer. Note that we also pass |this|
   // into the structured-clone write in order to set its |mSupportsArray| to
   // keep objects alive until the structured-clone read/write is done.
   JSAutoStructuredCloneBuffer buffer;
   if (!buffer.write(aCx, aValue, mCallbacks, this)) {
--- a/dom/tests/mochitest/notification/MockServices.js
+++ b/dom/tests/mochitest/notification/MockServices.js
@@ -38,20 +38,19 @@ var MockServices = (function () {
         title: title
       };
 
       // fake async alert show event
       if (listener) {
         setTimeout(function () {
           listener.observe(null, "alertshow", cookie);
         }, 100);
-        setTimeout(function () {
-          listener.observe(null, "alertclickcallback", cookie);
-        }, 100);
       }
+
+      // ?? SpecialPowers.wrap(alertListener).observe(null, "alertclickcallback", cookie);
     },
 
     showAppNotification: function(aImageUrl, aTitle, aText, aAlertListener, aDetails) {
       var listener = aAlertListener || (activeAlertNotifications[aDetails.id] ? activeAlertNotifications[aDetails.id].listener : undefined);
       activeAppNotifications[aDetails.id] = {
         observer: listener,
         title: aTitle,
         text: aText,
--- a/dom/webidl/Notification.webidl
+++ b/dom/webidl/Notification.webidl
@@ -6,28 +6,27 @@
  * The origin of this IDL file is
  * http://notifications.spec.whatwg.org/
  *
  * Copyright:
  * To the extent possible under law, the editors have waived all copyright and
  * related or neighboring rights to this work.
  */
 
-[Constructor(DOMString title, optional NotificationOptions options),
- Exposed=(Window,Worker),
- Func="mozilla::dom::Notification::PrefEnabled",
+[Pref="dom.webnotifications.enabled",
+ Constructor(DOMString title, optional NotificationOptions options),
  UnsafeInPrerendering]
 interface Notification : EventTarget {
   [GetterThrows]
   static readonly attribute NotificationPermission permission;
 
-  [Throws, Func="mozilla::dom::Notification::RequestPermissionEnabledForScope"]
+  [Throws]
   static void requestPermission(optional NotificationPermissionCallback permissionCallback);
 
-  [Throws, Func="mozilla::dom::Notification::IsGetEnabled"]
+  [Throws]
   static Promise<sequence<Notification>> get(optional GetNotificationOptions filter);
 
   attribute EventHandler onclick;
 
   attribute EventHandler onshow;
 
   attribute EventHandler onerror;
 
@@ -63,17 +62,17 @@ dictionary NotificationOptions {
   DOMString body = "";
   DOMString tag = "";
   DOMString icon = "";
   any data = null;
   NotificationBehavior mozbehavior = null;
 };
 
 dictionary GetNotificationOptions {
-  DOMString tag = "";
+  DOMString tag;
 };
 
 dictionary NotificationBehavior {
   boolean noscreen = false;
   boolean noclear = false;
   boolean showOnlyOnce = false;
   DOMString soundFile = "";
   sequence<unsigned long> vibrationPattern;
@@ -88,14 +87,8 @@ enum NotificationPermission {
 callback NotificationPermissionCallback = void (NotificationPermission permission);
 
 enum NotificationDirection {
   "auto",
   "ltr",
   "rtl"
 };
 
-partial interface ServiceWorkerRegistration {
-  [Throws]
-  Promise<void> showNotification(DOMString title, optional NotificationOptions options);
-  [Throws]
-  Promise<sequence<Notification>> getNotifications(optional GetNotificationOptions filter);
-};
deleted file mode 100644
--- a/dom/webidl/NotificationEvent.webidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- 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/.
- *
- * The origin of this IDL file is
- * http://notifications.spec.whatwg.org/
- *
- * Copyright:
- * To the extent possible under law, the editors have waived all copyright and
- * related or neighboring rights to this work.
- */
-
-[Constructor(DOMString type, optional NotificationEventInit eventInitDict),
- Exposed=ServiceWorker,Func="mozilla::dom::Notification::PrefEnabled"]
-interface NotificationEvent : ExtendableEvent {
-  readonly attribute Notification notification;
-};
-
-dictionary NotificationEventInit : ExtendableEventInit {
-  required Notification notification;
-};
-
-partial interface ServiceWorkerGlobalScope {
-  attribute EventHandler onnotificationclick;
-};
--- a/dom/webidl/ServiceWorker.webidl
+++ b/dom/webidl/ServiceWorker.webidl
@@ -7,17 +7,17 @@
  * http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-obj
  *
  */
 
 // Still unclear what should be subclassed.
 // https://github.com/slightlyoff/ServiceWorker/issues/189
 [Func="mozilla::dom::workers::ServiceWorkerVisible",
  // FIXME(nsm): Bug 1113522. This is exposed to satisfy webidl constraints, but it won't actually work.
- Exposed=(Window,Worker)]
+ Exposed=(Worker,Window)]
 interface ServiceWorker : EventTarget {
   readonly attribute USVString scriptURL;
   readonly attribute ServiceWorkerState state;
 
   attribute EventHandler onstatechange;
 
   // FIXME(catalinb): Should inherit this from Worker.
   [Throws]
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -325,17 +325,16 @@ WEBIDL_FILES = [
     'NetDashboard.webidl',
     'NetworkInformation.webidl',
     'NetworkOptions.webidl',
     'Node.webidl',
     'NodeFilter.webidl',
     'NodeIterator.webidl',
     'NodeList.webidl',
     'Notification.webidl',
-    'NotificationEvent.webidl',
     'NotifyPaintEvent.webidl',
     'OfflineAudioCompletionEvent.webidl',
     'OfflineAudioContext.webidl',
     'OfflineResourceList.webidl',
     'OscillatorNode.webidl',
     'PaintRequest.webidl',
     'PaintRequestList.webidl',
     'PannerNode.webidl',
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -153,17 +153,16 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 
 #define PREF_GCZEAL "gcZeal"
 
 #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
 #define DUMP_CONTROLLED_BY_PREF 1
 #define PREF_DOM_WINDOW_DUMP_ENABLED "browser.dom.window.dump.enabled"
 #endif
 
 #define PREF_DOM_CACHES_ENABLED        "dom.caches.enabled"
-#define PREF_DOM_WORKERNOTIFICATION_ENABLED  "dom.webnotifications.workers.enabled"
 #define PREF_WORKERS_LATEST_JS_VERSION "dom.workers.latestJSVersion"
 #define PREF_INTL_ACCEPT_LANGUAGES     "intl.accept_languages"
 #define PREF_SERVICEWORKERS_ENABLED    "dom.serviceWorkers.enabled"
 #define PREF_INTERCEPTION_ENABLED      "dom.serviceWorkers.interception.enabled"
 
 namespace {
 
 const uint32_t kNoIndex = uint32_t(-1);
@@ -1900,20 +1899,16 @@ RuntimeService::Init()
                                   reinterpret_cast<void *>(WORKERPREF_DUMP))) ||
 #endif
       NS_FAILED(Preferences::RegisterCallbackAndCall(
                                   WorkerPrefChanged,
                                   PREF_DOM_CACHES_ENABLED,
                                   reinterpret_cast<void *>(WORKERPREF_DOM_CACHES))) ||
       NS_FAILED(Preferences::RegisterCallbackAndCall(
                                   WorkerPrefChanged,
-                                  PREF_DOM_WORKERNOTIFICATION_ENABLED,
-                                  reinterpret_cast<void *>(WORKERPREF_DOM_WORKERNOTIFICATION))) ||
-      NS_FAILED(Preferences::RegisterCallbackAndCall(
-                                  WorkerPrefChanged,
                                   PREF_SERVICEWORKERS_ENABLED,
                                   reinterpret_cast<void *>(WORKERPREF_SERVICEWORKERS))) ||
       NS_FAILED(Preferences::RegisterCallbackAndCall(
                                   WorkerPrefChanged,
                                   PREF_INTERCEPTION_ENABLED,
                                   reinterpret_cast<void *>(WORKERPREF_INTERCEPTION_ENABLED))) ||
       NS_FAILED(Preferences::RegisterCallback(LoadRuntimeOptions,
                                               PREF_JS_OPTIONS_PREFIX,
@@ -2117,20 +2112,16 @@ RuntimeService::Cleanup()
         NS_FAILED(Preferences::UnregisterCallback(
                                   WorkerPrefChanged,
                                   PREF_SERVICEWORKERS_ENABLED,
                                   reinterpret_cast<void *>(WORKERPREF_SERVICEWORKERS))) ||
         NS_FAILED(Preferences::UnregisterCallback(
                                   WorkerPrefChanged,
                                   PREF_DOM_CACHES_ENABLED,
                                   reinterpret_cast<void *>(WORKERPREF_DOM_CACHES))) ||
-        NS_FAILED(Preferences::UnregisterCallback(
-                                  WorkerPrefChanged,
-                                  PREF_DOM_WORKERNOTIFICATION_ENABLED,
-                                  reinterpret_cast<void *>(WORKERPREF_DOM_WORKERNOTIFICATION))) ||
 #if DUMP_CONTROLLED_BY_PREF
         NS_FAILED(Preferences::UnregisterCallback(
                                   WorkerPrefChanged,
                                   PREF_DOM_WINDOW_DUMP_ENABLED,
                                   reinterpret_cast<void *>(WORKERPREF_DUMP))) ||
 #endif
 #ifdef JS_GC_ZEAL
         NS_FAILED(Preferences::UnregisterCallback(
@@ -2655,36 +2646,38 @@ RuntimeService::WorkerPrefChanged(const 
   AssertIsOnMainThread();
 
   uintptr_t tmp = reinterpret_cast<uintptr_t>(aClosure);
   MOZ_ASSERT(tmp < WORKERPREF_COUNT);
   WorkerPreference key = static_cast<WorkerPreference>(tmp);
 
 #ifdef DUMP_CONTROLLED_BY_PREF
   if (key == WORKERPREF_DUMP) {
-    sDefaultPreferences[key] =
+    key = WORKERPREF_DUMP;
+    sDefaultPreferences[WORKERPREF_DUMP] =
       Preferences::GetBool(PREF_DOM_WINDOW_DUMP_ENABLED, false);
   }
 #endif
 
   if (key == WORKERPREF_DOM_CACHES) {
+    key = WORKERPREF_DOM_CACHES;
     sDefaultPreferences[WORKERPREF_DOM_CACHES] =
       Preferences::GetBool(PREF_DOM_CACHES_ENABLED, false);
-  } else if (key == WORKERPREF_DOM_WORKERNOTIFICATION) {
-    sDefaultPreferences[key] =
-      Preferences::GetBool(PREF_DOM_WORKERNOTIFICATION_ENABLED, false);
   } else if (key == WORKERPREF_SERVICEWORKERS) {
     key = WORKERPREF_SERVICEWORKERS;
     sDefaultPreferences[WORKERPREF_SERVICEWORKERS] =
       Preferences::GetBool(PREF_SERVICEWORKERS_ENABLED, false);
   } else if (key == WORKERPREF_INTERCEPTION_ENABLED) {
     key = WORKERPREF_INTERCEPTION_ENABLED;
     sDefaultPreferences[key] =
       Preferences::GetBool(PREF_INTERCEPTION_ENABLED, false);
   }
+  // This function should never be registered as a callback for a preference it
+  // does not handle.
+  MOZ_ASSERT(key != WORKERPREF_COUNT);
 
   RuntimeService* rts = RuntimeService::GetService();
   if (rts) {
     rts->UpdateAllWorkerPreference(key, sDefaultPreferences[key]);
   }
 }
 
 void
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -34,17 +34,16 @@
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/Headers.h"
 #include "mozilla/dom/indexedDB/IDBFactory.h"
 #include "mozilla/dom/InternalHeaders.h"
 #include "mozilla/dom/Navigator.h"
-#include "mozilla/dom/NotificationEvent.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "mozilla/unused.h"
 
@@ -2265,143 +2264,16 @@ ServiceWorkerManager::SendPushSubscripti
   if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 #endif
 }
 
-class SendNotificationClickEventRunnable final : public WorkerRunnable
-{
-  nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
-  const nsString mID;
-  const nsString mTitle;
-  const nsString mDir;
-  const nsString mLang;
-  const nsString mBody;
-  const nsString mTag;
-  const nsString mIcon;
-  const nsString mData;
-  const nsString mBehavior;
-  const nsString mScope;
-
-public:
-  SendNotificationClickEventRunnable(
-    WorkerPrivate* aWorkerPrivate,
-    nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
-    const nsAString& aID,
-    const nsAString& aTitle,
-    const nsAString& aDir,
-    const nsAString& aLang,
-    const nsAString& aBody,
-    const nsAString& aTag,
-    const nsAString& aIcon,
-    const nsAString& aData,
-    const nsAString& aBehavior,
-    const nsAString& aScope)
-      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
-      , mServiceWorker(aServiceWorker)
-      , mID(aID)
-      , mTitle(aTitle)
-      , mDir(aDir)
-      , mLang(aLang)
-      , mBody(aBody)
-      , mTag(aTag)
-      , mIcon(aIcon)
-      , mData(aData)
-      , mBehavior(aBehavior)
-      , mScope(aScope)
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(aWorkerPrivate);
-    MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
-  }
-
-  bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
-  {
-    MOZ_ASSERT(aWorkerPrivate);
-
-    nsRefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
-
-    ErrorResult result;
-    nsRefPtr<Notification> notification =
-      Notification::ConstructFromFields(aWorkerPrivate->GlobalScope(), mID,
-                                        mTitle, mDir, mLang, mBody, mTag, mIcon,
-                                        mData, mScope, result);
-    if (NS_WARN_IF(result.Failed())) {
-      return false;
-    }
-
-    NotificationEventInit nei;
-    nei.mNotification = notification;
-    nei.mBubbles = false;
-    nei.mCancelable = true;
-
-    nsRefPtr<NotificationEvent> event =
-      NotificationEvent::Constructor(target, NS_LITERAL_STRING("notificationclick"), nei, result);
-    if (NS_WARN_IF(result.Failed())) {
-      return false;
-    }
-
-    event->SetTrusted(true);
-    nsRefPtr<Promise> waitUntilPromise =
-      DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(), event);
-
-    if (waitUntilPromise) {
-      nsRefPtr<KeepAliveHandler> handler = new KeepAliveHandler(mServiceWorker);
-      waitUntilPromise->AppendNativeHandler(handler);
-    }
-
-    return true;
-  }
-};
-
-NS_IMETHODIMP
-ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix,
-                                                 const nsACString& aScope,
-                                                 const nsAString& aID,
-                                                 const nsAString& aTitle,
-                                                 const nsAString& aDir,
-                                                 const nsAString& aLang,
-                                                 const nsAString& aBody,
-                                                 const nsAString& aTag,
-                                                 const nsAString& aIcon,
-                                                 const nsAString& aData,
-                                                 const nsAString& aBehavior)
-{
-  OriginAttributes attrs;
-  if (!attrs.PopulateFromSuffix(aOriginSuffix)) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  nsRefPtr<ServiceWorker> serviceWorker = CreateServiceWorkerForScope(attrs, aScope);
-  if (!serviceWorker) {
-    return NS_ERROR_FAILURE;
-  }
-  nsMainThreadPtrHandle<ServiceWorker> serviceWorkerHandle(
-    new nsMainThreadPtrHolder<ServiceWorker>(serviceWorker));
-
-  nsRefPtr<SendNotificationClickEventRunnable> r =
-    new SendNotificationClickEventRunnable(serviceWorker->GetWorkerPrivate(),
-                                           serviceWorkerHandle, aID, aTitle,
-                                           aDir, aLang, aBody, aTag, aIcon,
-                                           aData, aBehavior,
-                                           NS_ConvertUTF8toUTF16(aScope));
-
-  AutoJSAPI jsapi;
-  jsapi.Init();
-  if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
-}
-
 NS_IMETHODIMP
 ServiceWorkerManager::GetReadyPromise(nsIDOMWindow* aWindow,
                                       nsISupports** aPromise)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -1,17 +1,16 @@
 /* -*- 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 "ServiceWorkerRegistration.h"
 
-#include "mozilla/dom/Notification.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseWorkerProxy.h"
 #include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
 #include "mozilla/Services.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "ServiceWorker.h"
@@ -584,62 +583,16 @@ ServiceWorkerRegistrationMainThread::Unr
   aRv = swm->Unregister(documentPrincipal, cb, scope);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   return promise.forget();
 }
 
-// Notification API extension.
-already_AddRefed<Promise>
-ServiceWorkerRegistrationMainThread::ShowNotification(JSContext* aCx,
-                                                      const nsAString& aTitle,
-                                                      const NotificationOptions& aOptions,
-                                                      ErrorResult& aRv)
-{
-  AssertIsOnMainThread();
-  MOZ_ASSERT(GetOwner());
-  nsCOMPtr<nsPIDOMWindow> window = GetOwner();
-  if (NS_WARN_IF(!window)) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return nullptr;
-  }
-
-  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
-  if (NS_WARN_IF(!doc)) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return nullptr;
-  }
-
-  nsRefPtr<workers::ServiceWorker> worker = GetActive();
-  if (!worker) {
-    aRv.ThrowTypeError(MSG_NO_ACTIVE_WORKER);
-    return nullptr;
-  }
-
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(window);
-  nsRefPtr<Promise> p =
-    Notification::ShowPersistentNotification(global,
-                                             mScope, aTitle, aOptions, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return nullptr;
-  }
-
-  return p.forget();
-}
-
-already_AddRefed<Promise>
-ServiceWorkerRegistrationMainThread::GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv)
-{
-  AssertIsOnMainThread();
-  nsCOMPtr<nsPIDOMWindow> window = GetOwner();
-  return Notification::Get(window, aOptions, mScope, aRv);
-}
-
 already_AddRefed<PushManager>
 ServiceWorkerRegistrationMainThread::GetPushManager(ErrorResult& aRv)
 {
   AssertIsOnMainThread();
 
 #ifdef MOZ_SIMPLEPUSH
   return nullptr;
 #else
@@ -1033,38 +986,10 @@ WorkerListener::UpdateFound()
     nsRefPtr<FireUpdateFoundRunnable> r =
       new FireUpdateFoundRunnable(mWorkerPrivate, this);
     AutoJSAPI jsapi;
     jsapi.Init();
     if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) {
     }
   }
 }
-
-// Notification API extension.
-already_AddRefed<Promise>
-ServiceWorkerRegistrationWorkerThread::ShowNotification(JSContext* aCx,
-                                                        const nsAString& aTitle,
-                                                        const NotificationOptions& aOptions,
-                                                        ErrorResult& aRv)
-{
-  // Until Bug 1131324 exposes ServiceWorkerContainer on workers,
-  // ShowPersistentNotification() checks for valid active worker while it is
-  // also verifying scope so that we block the worker on the main thread only
-  // once.
-  nsRefPtr<Promise> p =
-    Notification::ShowPersistentNotification(mWorkerPrivate->GlobalScope(),
-                                             mScope, aTitle, aOptions, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return nullptr;
-  }
-
-  return p.forget();
-}
-
-already_AddRefed<Promise>
-ServiceWorkerRegistrationWorkerThread::GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv)
-{
-  return Notification::WorkerGet(mWorkerPrivate, aOptions, mScope, aRv);
-}
-
 } // dom namespace
 } // mozilla namespace
--- a/dom/workers/ServiceWorkerRegistration.h
+++ b/dom/workers/ServiceWorkerRegistration.h
@@ -7,19 +7,16 @@
 #ifndef mozilla_dom_ServiceWorkerRegistration_h
 #define mozilla_dom_ServiceWorkerRegistration_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/ServiceWorkerBinding.h"
 #include "mozilla/dom/ServiceWorkerCommon.h"
 #include "mozilla/dom/workers/bindings/WorkerFeature.h"
 
-// Support for Notification API extension.
-#include "mozilla/dom/NotificationBinding.h"
-
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class Promise;
 class PushManager;
 class WorkerListener;
@@ -109,26 +106,16 @@ public:
   Update();
 
   already_AddRefed<Promise>
   Unregister(ErrorResult& aRv);
 
   JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  // Partial interface from Notification API.
-  already_AddRefed<Promise>
-  ShowNotification(JSContext* aCx,
-                   const nsAString& aTitle,
-                   const NotificationOptions& aOptions,
-                   ErrorResult& aRv);
-
-  already_AddRefed<Promise>
-  GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv);
-
   already_AddRefed<workers::ServiceWorker>
   GetInstalling() override;
 
   already_AddRefed<workers::ServiceWorker>
   GetWaiting() override;
 
   already_AddRefed<workers::ServiceWorker>
   GetActive() override;
@@ -198,26 +185,16 @@ public:
   Update();
 
   already_AddRefed<Promise>
   Unregister(ErrorResult& aRv);
 
   JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  // Partial interface from Notification API.
-  already_AddRefed<Promise>
-  ShowNotification(JSContext* aCx,
-                   const nsAString& aTitle,
-                   const NotificationOptions& aOptions,
-                   ErrorResult& aRv);
-
-  already_AddRefed<Promise>
-  GetNotifications(const GetNotificationOptions& aOptions, ErrorResult& aRv);
-
   already_AddRefed<workers::ServiceWorker>
   GetInstalling() override;
 
   already_AddRefed<workers::ServiceWorker>
   GetWaiting() override;
 
   already_AddRefed<workers::ServiceWorker>
   GetActive() override;
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -1240,23 +1240,16 @@ public:
   }
 
   bool
   InterceptionEnabled() const
   {
     AssertIsOnWorkerThread();
     return mPreferences[WORKERPREF_INTERCEPTION_ENABLED];
   }
-  
-  bool
-  DOMWorkerNotificationEnabled() const
-  {
-    AssertIsOnWorkerThread();
-    return mPreferences[WORKERPREF_DOM_WORKERNOTIFICATION];
-  }
 
   bool
   OnLine() const
   {
     AssertIsOnWorkerThread();
     return mOnLine;
   }
 
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -203,17 +203,16 @@ class ServiceWorkerGlobalScope final : p
   nsRefPtr<ServiceWorkerRegistrationWorkerThread> mRegistration;
 
   ~ServiceWorkerGlobalScope();
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerGlobalScope,
                                            WorkerGlobalScope)
-  IMPL_EVENT_HANDLER(notificationclick)
 
   ServiceWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, const nsACString& aScope);
 
   virtual bool
   WrapGlobalObject(JSContext* aCx,
                    JS::MutableHandle<JSObject*> aReflector) override;
 
   static bool
--- a/dom/workers/Workers.h
+++ b/dom/workers/Workers.h
@@ -194,17 +194,16 @@ struct JSSettings
 };
 
 enum WorkerPreference
 {
   WORKERPREF_DUMP = 0, // browser.dom.window.dump.enabled
   WORKERPREF_DOM_CACHES, // dom.caches.enabled
   WORKERPREF_SERVICEWORKERS, // dom.serviceWorkers.enabled
   WORKERPREF_INTERCEPTION_ENABLED, // dom.serviceWorkers.interception.enabled
-  WORKERPREF_DOM_WORKERNOTIFICATION, // dom.webnotifications.workers.enabled
   WORKERPREF_COUNT
 };
 
 // Implemented in WorkerPrivate.cpp
 
 struct WorkerLoadInfo
 {
   // All of these should be released in WorkerPrivateParent::ForgetMainThreadObjects.
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -36,20 +36,16 @@ support-files =
   loadEncoding_worker.js
   location_worker.js
   longThread_worker.js
   multi_sharedWorker_frame.html
   multi_sharedWorker_sharedWorker.js
   navigator_languages_worker.js
   navigator_worker.js
   newError_worker.js
-  notification_worker.js
-  notification_worker_child-child.js
-  notification_worker_child-parent.js
-  notification_permission_worker.js
   onLine_worker.js
   onLine_worker_child.js
   onLine_worker_head.js
   promise_worker.js
   recursion_worker.js
   recursiveOnerror_worker.js
   relativeLoad_import.js
   relativeLoad_worker.js
@@ -157,19 +153,16 @@ skip-if = (toolkit == 'gonk' && debug) #
 [test_location.html]
 [test_longThread.html]
 [test_multi_sharedWorker.html]
 [test_multi_sharedWorker_lifetimes.html]
 [test_navigator.html]
 [test_navigator_languages.html]
 skip-if = buildapp == 'mulet'
 [test_newError.html]
-[test_notification.html]
-[test_notification_child.html]
-[test_notification_permission.html]
 [test_onLine.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_performance_user_timing.html]
 [test_promise.html]
 [test_promise_resolved_with_string.html]
 [test_recursion.html]
 [test_recursiveOnerror.html]
 [test_relativeLoad.html]
deleted file mode 100644
--- a/dom/workers/test/notification_permission_worker.js
+++ /dev/null
@@ -1,56 +0,0 @@
-function info(message) {
-  dump("INFO: " + message + "\n");
-}
-
-function ok(test, message) {
-  postMessage({ type: 'ok', test: test, message: message });
-}
-
-function is(a, b, message) {
-  postMessage({ type: 'is', test1: a, test2: b, message: message });
-}
-
-if (self.Notification) {
-  var steps = [
-    function (done) {
-      info("Test notification permission");
-      ok(typeof Notification === "function", "Notification constructor exists");
-      ok(Notification.permission === "denied", "Notification.permission is denied.");
-
-      var n = new Notification("Hello");
-      n.onerror = function(e) {
-        ok(true, "error called due to permission denied.");
-        done();
-      }
-    },
-  ];
-
-  onmessage = function(e) {
-    var context = {};
-    (function executeRemainingTests(remainingTests) {
-      if (!remainingTests.length) {
-        postMessage({type: 'finish'});
-        return;
-      }
-
-      var nextTest = remainingTests.shift();
-      var finishTest = executeRemainingTests.bind(null, remainingTests);
-      var startTest = nextTest.call.bind(nextTest, context, finishTest);
-
-      try {
-        startTest();
-        // if no callback was defined for test function,
-        // we must manually invoke finish to continue
-        if (nextTest.length === 0) {
-          finishTest();
-        }
-      } catch (e) {
-        ok(false, "Test threw exception! " + nextTest + " " + e);
-        finishTest();
-      }
-    })(steps);
-  }
-} else {
-  ok(true, "Notifications are not enabled in workers on the platform.");
-  postMessage({ type: 'finish' });
-}
deleted file mode 100644
--- a/dom/workers/test/notification_worker.js
+++ /dev/null
@@ -1,89 +0,0 @@
-function ok(test, message) {
-  postMessage({ type: 'ok', test: test, message: message });
-}
-
-function is(a, b, message) {
-  postMessage({ type: 'is', test1: a, test2: b, message: message });
-}
-
-if (self.Notification) {
-  var steps = [
-    function () {
-      ok(typeof Notification === "function", "Notification constructor exists");
-      ok(Notification.permission, "Notification.permission exists");
-      ok(typeof Notification.requestPermission === "undefined", "Notification.requestPermission should not exist");
-    },
-
-    function (done) {
-      var options = {
-        dir: "auto",
-        lang: "",
-        body: "This is a notification body",
-        tag: "sometag",
-        icon: "icon.png"
-      };
-      var notification = new Notification("This is a title", options);
-
-      ok(notification !== undefined, "Notification exists");
-      is(notification.onclick, null, "onclick() should be null");
-      is(notification.onshow, null, "onshow() should be null");
-      is(notification.onerror, null, "onerror() should be null");
-      is(notification.onclose, null, "onclose() should be null");
-      is(typeof notification.close, "function", "close() should exist");
-
-      is(notification.dir, options.dir, "auto should get set");
-      is(notification.lang, options.lang, "lang should get set");
-      is(notification.body, options.body, "body should get set");
-      is(notification.tag, options.tag, "tag should get set");
-      is(notification.icon, options.icon, "icon should get set");
-
-      // store notification in test context
-      this.notification = notification;
-
-      notification.onshow = function () {
-        ok(true, "onshow handler should be called");
-        done();
-      };
-    },
-
-    function (done) {
-      var notification = this.notification;
-
-      notification.onclose = function () {
-        ok(true, "onclose handler should be called");
-        done();
-      };
-
-      notification.close();
-    },
-  ];
-
-  onmessage = function(e) {
-    var context = {};
-    (function executeRemainingTests(remainingTests) {
-      if (!remainingTests.length) {
-        postMessage({type: 'finish'});
-        return;
-      }
-
-      var nextTest = remainingTests.shift();
-      var finishTest = executeRemainingTests.bind(null, remainingTests);
-      var startTest = nextTest.call.bind(nextTest, context, finishTest);
-
-      try {
-        startTest();
-        // if no callback was defined for test function,
-        // we must manually invoke finish to continue
-        if (nextTest.length === 0) {
-          finishTest();
-        }
-      } catch (e) {
-        ok(false, "Test threw exception! " + nextTest + " " + e);
-        finishTest();
-      }
-    })(steps);
-  }
-} else {
-  ok(true, "Notifications are not enabled in workers on the platform.");
-  postMessage({ type: 'finish' });
-}
deleted file mode 100644
--- a/dom/workers/test/notification_worker_child-child.js
+++ /dev/null
@@ -1,92 +0,0 @@
-function ok(test, message) {
-  postMessage({ type: 'ok', test: test, message: message });
-}
-
-function is(a, b, message) {
-  postMessage({ type: 'is', test1: a, test2: b, message: message });
-}
-
-if (self.Notification) {
-  var steps = [
-    function () {
-      ok(typeof Notification === "function", "Notification constructor exists");
-      ok(Notification.permission, "Notification.permission exists");
-      ok(typeof Notification.requestPermission === "undefined", "Notification.requestPermission should not exist");
-      //ok(typeof Notification.get === "function", "Notification.get exists");
-    },
-
-    function (done) {
-
-      var options = {
-        dir: "auto",
-        lang: "",
-        body: "This is a notification body",
-        tag: "sometag",
-        icon: "icon.png"
-      };
-      var notification = new Notification("This is a title", options);
-
-      ok(notification !== undefined, "Notification exists");
-      is(notification.onclick, null, "onclick() should be null");
-      is(notification.onshow, null, "onshow() should be null");
-      is(notification.onerror, null, "onerror() should be null");
-      is(notification.onclose, null, "onclose() should be null");
-      is(typeof notification.close, "function", "close() should exist");
-
-      is(notification.dir, options.dir, "auto should get set");
-      is(notification.lang, options.lang, "lang should get set");
-      is(notification.body, options.body, "body should get set");
-      is(notification.tag, options.tag, "tag should get set");
-      is(notification.icon, options.icon, "icon should get set");
-
-      // store notification in test context
-      this.notification = notification;
-
-      notification.onshow = function () {
-        ok(true, "onshow handler should be called");
-        done();
-      };
-    },
-
-    function (done) {
-      var notification = this.notification;
-
-      notification.onclose = function () {
-        ok(true, "onclose handler should be called");
-        done();
-      };
-
-      notification.close();
-    },
-  ];
-
-  onmessage = function(e) {
-    var context = {};
-    (function executeRemainingTests(remainingTests) {
-      if (!remainingTests.length) {
-        postMessage({type: 'finish'});
-        return;
-      }
-
-      var nextTest = remainingTests.shift();
-      var finishTest = executeRemainingTests.bind(null, remainingTests);
-      var startTest = nextTest.call.bind(nextTest, context, finishTest);
-
-      try {
-        startTest();
-        // if no callback was defined for test function,
-        // we must manually invoke finish to continue
-        if (nextTest.length === 0) {
-          finishTest();
-        }
-      } catch (e) {
-        ok(false, "Test threw exception! " + nextTest + " " + e);
-        finishTest();
-      }
-    })(steps);
-  }
-} else {
-  ok(true, "Notifications are not enabled in workers on the platform.");
-  postMessage({ type: 'finish' });
-}
-
deleted file mode 100644
--- a/dom/workers/test/notification_worker_child-parent.js
+++ /dev/null
@@ -1,26 +0,0 @@
-function ok(test, message) {
-  postMessage({ type: 'ok', test: test, message: message });
-}
-
-function is(a, b, message) {
-  postMessage({ type: 'is', test1: a, test2: b, message: message });
-}
-
-if (self.Notification) {
-  var child = new Worker("notification_worker_child-child.js");
-  child.onerror = function(e) {
-    ok(false, "Error loading child worker " + e);
-    postMessage({ type: 'finish' });
-  }
-
-  child.onmessage = function(e) {
-    postMessage(e.data);
-  }
-
-  onmessage = function(e) {
-    child.postMessage('start');
-  }
-} else {
-  ok(true, "Notifications are not enabled in workers on the platform.");
-  postMessage({ type: 'finish' });
-}
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -84,33 +84,26 @@ support-files =
   source_message_posting_worker.js
   scope/scope_worker.js
   redirect_serviceworker.sjs
   importscript.sjs
   importscript_worker.js
   client_focus_worker.js
   bug1151916_worker.js
   bug1151916_driver.html
-  notificationclick.html
-  notificationclick.js
   worker_updatefoundevent.js
   worker_updatefoundevent2.js
   updatefoundevent.html
   empty.js
   periodic_update_test.js
   periodic.sjs
   periodic/frame.html
   periodic/register.html
   periodic/wait_for_update.html
   periodic/unregister.html
-  notification_constructor_error.js
-  notification_get_sw.js
-  notification/register.html
-  notification/listener.html
-  notification_alt/register.html
   sanitize/frame.html
   sanitize/register.html
   sanitize/example_check_and_unregister.html
   sanitize_worker.js
   swa/worker_scope_different.js
   swa/worker_scope_different.js^headers^
   swa/worker_scope_different2.js
   swa/worker_scope_different2.js^headers^
@@ -187,19 +180,16 @@ support-files =
 [test_post_message_advanced.html]
 [test_post_message_source.html]
 [test_register_base.html]
 [test_register_https_in_http.html]
 [test_request_context.html]
 skip-if = toolkit == 'android' # Bug 1163410
 [test_scopes.html]
 [test_sandbox_intercept.html]
-[test_notificationclick.html]
-[test_notification_constructor_error.html]
-[test_notification_get.html]
 [test_sanitize.html]
 [test_sanitize_domain.html]
 [test_service_worker_allowed.html]
 [test_serviceworker_interfaces.html]
 [test_serviceworker_not_sharedworker.html]
 [test_skip_waiting.html]
 [test_strict_mode_error.html]
 [test_third_party_iframes.html]
deleted file mode 100644
--- a/dom/workers/test/serviceworkers/notification/listener.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Bug 1114554 - proxy to forward messages from SW to test</title>
-<script class="testbody" type="text/javascript">
-  var testWindow = parent;
-  if (opener) {
-    testWindow = opener;
-  }
-
-  navigator.serviceWorker.onmessage = function(msg) {
-    // worker message;
-    testWindow.postMessage(msg.data, "*");
-    if (msg.data.type == 'finish') {
-      window.close();
-    }
-  };
-</script>
-
-</head>
-<body>
-</body>
-</html>
deleted file mode 100644
--- a/dom/workers/test/serviceworkers/notification/register.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<script>
-  function done() {
-    parent.callback();
-  }
-
-  navigator.serviceWorker.ready.then(done);
-  navigator.serviceWorker.register("../notification_get_sw.js", {scope: "."}).catch(function(e) {
-    dump("Registration failure " + e.message + "\n");
-  });
-</script>
deleted file mode 100644
--- a/dom/workers/test/serviceworkers/notification_alt/register.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<script>
-  function done() {
-    parent.callback();
-  }
-
-  navigator.serviceWorker.ready.then(done);
-  navigator.serviceWorker.register("../notification_get_sw.js", {scope: "."}).catch(function(e) {
-    dump("Registration failure " + e.message + "\n");
-  });
-</script>
deleted file mode 100644
--- a/dom/workers/test/serviceworkers/notification_constructor_error.js
+++ /dev/null
@@ -1,1 +0,0 @@
-new Notification("Hi there");
deleted file mode 100644
--- a/dom/workers/test/serviceworkers/notification_get_sw.js
+++ /dev/null
@@ -1,49 +0,0 @@
-function postAll(data) {
-  self.clients.matchAll().then(function(clients) {
-    if (clients.length == 0) {
-      dump("***************** NO CLIENTS FOUND! Test messages are being lost *******************\n");
-    }
-    clients.forEach(function(client) {
-      client.postMessage(data);
-    });
-  });
-}
-
-function ok(a, msg) {
-  postAll({type: 'status', status: !!a, msg: a + ": " + msg });
-}
-
-function is(a, b, msg) {
-  postAll({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg });
-}
-
-function done() {
-  postAll({type: 'finish'});
-}
-
-onmessage = function(e) {
-dump("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MESSAGE " + e.data + "\n");
-  var start;
-  if (e.data == 'create') {
-    start = registration.showNotification("This is a title");
-  } else {
-    start = Promise.resolve();
-  }
-
-  start.then(function() {
-  dump("CALLING getNotification\n");
-    registration.getNotifications().then(function(notifications) {
-  dump("RECD getNotification\n");
-      is(notifications.length, 1, "There should be one stored notification");
-      var notification = notifications[0];
-      if (!notification) {
-        done();
-        return;
-      }
-      ok(notification instanceof Notification, "Should be a Notification");
-      is(notification.title, "This is a title", "Title should match");
-      notification.close();
-      done();
-    });
-  });
-}
deleted file mode 100644
--- a/dom/workers/test/serviceworkers/notificationclick.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Bug 1114554 - controlled page</title>
-<script class="testbody" type="text/javascript">
-  var testWindow = parent;
-  if (opener) {
-    testWindow = opener;
-  }
-
-  navigator.serviceWorker.ready.then(function(swr) {
-    swr.showNotification("Hi there. The ServiceWorker should receive a click event for this.");
-  });
-
-  navigator.serviceWorker.onmessage = function(msg) {
-    testWindow.callback();
-  };
-</script>
-
-</head>
-<body>
-</body>
-</html>
deleted file mode 100644
--- a/dom/workers/test/serviceworkers/notificationclick.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/publicdomain/zero/1.0/
-//
-onnotificationclick = function(e) {
-  self.clients.matchAll().then(function(clients) {
-    if (clients.length === 0) {
-      dump("********************* CLIENTS LIST EMPTY! Test will timeout! ***********************\n");
-      return;
-    }
-
-    clients.forEach(function(client) {
-      client.postMessage("done");
-    });
-  });
-}
deleted file mode 100644
--- a/dom/workers/test/serviceworkers/test_notification_constructor_error.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Bug XXXXXXX - Check that Notification constructor throws in ServiceWorkerGlobalScope</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<p id="display"></p>
-<div id="content" style="display: none"></div>
-<pre id="test"></pre>
-<script class="testbody" type="text/javascript">
-
-  function simpleRegister() {
-    return navigator.serviceWorker.register("notification_constructor_error.js", { scope: "notification_constructor_error/" }).then(function(swr) {
-      ok(false, "Registration should fail.");
-    }, function(e) {
-      ok(e.message.indexOf("Notification") != -1, "Registration should fail.");
-    });
-  }
-
-  function runTest() {
-    MockServices.register();
-    simpleRegister()
-      .then(function() {
-        MockServices.unregister();
-        SimpleTest.finish();
-      }).catch(function(e) {
-        ok(false, "Some test failed with error " + e);
-        MockServices.unregister();
-        SimpleTest.finish();
-      });
-  }
-
-  SimpleTest.waitForExplicitFinish();
-  SpecialPowers.pushPrefEnv({"set": [
-    ["dom.serviceWorkers.exemptFromPerDomainMax", true],
-    ["dom.serviceWorkers.enabled", true],
-    ["dom.serviceWorkers.testing.enabled", true],
-    ["notification.prompt.testing", true],
-  ]}, runTest);
-</script>
-</pre>
-</body>
-</html>
-
deleted file mode 100644
--- a/dom/workers/test/serviceworkers/test_notification_get.html
+++ /dev/null
@@ -1,164 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>ServiceWorkerRegistration.getNotifications() on main thread and worker thread.</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<p id="display"></p>
-<div id="content" style="display: none"></div>
-<pre id="test"></pre>
-<script type="text/javascript">
-
-  SimpleTest.requestFlakyTimeout("untriaged");
-
-  function testFrame(src) {
-    return new Promise(function(resolve, reject) {
-      var iframe = document.createElement("iframe");
-      iframe.src = src;
-      window.callback = function(result) {
-        iframe.src = "about:blank";
-        document.body.removeChild(iframe);
-        iframe = null;
-        SpecialPowers.exactGC(window, function() {
-          resolve(result);
-        });
-      };
-      document.body.appendChild(iframe);
-    });
-  }
-
-  function registerSW() {
-    return testFrame('notification/register.html').then(function() {
-      ok(true, "Registered service worker.");
-    });
-  }
-
-  // To check that the scope is respected when retrieving notifications.
-  function registerAlternateSWAndAddNotification() {
-    return testFrame('notification_alt/register.html').then(function() {
-      ok(true, "Registered alternate service worker.");
-      return navigator.serviceWorker.getRegistration("./notification_alt/").then(function(reg) {
-        return reg.showNotification("This is a notification_alt");
-      });
-    });
-  }
-
-  function testGet() {
-    // Non persistent notifications will not show up in getNotification().
-    var n = new Notification("Scope does not match");
-    var options = NotificationTest.payload;
-    return navigator.serviceWorker.getRegistration("./notification/")
-      .then(function(reg) {
-        return reg.showNotification("This is a title", options)
-                 .then(function() {
-                  return reg;
-                 });
-      }).then(function(reg) {
-        return registerAlternateSWAndAddNotification().then(function() {
-          return reg;
-        });
-      }).then(function(reg) {
-        return reg.getNotifications();
-      }).then(function(notifications) {
-        is(notifications.length, 1, "There should be one stored notification");
-        var notification = notifications[0];
-        ok(notification instanceof Notification, "Should be a Notification");
-        is(notification.title, "This is a title", "Title should match");
-        for (var key in options) {
-          if (key === "data") {
-            ok(NotificationTest.customDataMatches(notification.data),
-               "data property should match");
-            continue;
-          }
-          is(notification[key], options[key], key + " property should match");
-        }
-        notification.close();
-      }).then(function() {
-        return navigator.serviceWorker.getRegistration("./notification/").then(function(reg) {
-          return reg.getNotifications();
-        });
-      }).then(function(notifications) {
-        // Make sure closed notifications are no longer retrieved.
-        is(notifications.length, 0, "There should be no more stored notifications");
-      }).catch(function(e) {
-        ok(false, "Something went wrong " + e.message);
-      });
-  }
-
-  function testGetWorker() {
-    todo(false, "navigator.serviceWorker is not available on workers yet");
-    return Promise.resolve();
-  }
-
-  function waitForSWTests(reg, msg) {
-    return new Promise(function(resolve, reject) {
-      var content = document.getElementById("content");
-
-      iframe = document.createElement("iframe");
-
-      content.appendChild(iframe);
-      iframe.setAttribute('src', "notification/listener.html");
-
-      window.onmessage = function(e) {
-        if (e.data.type == 'status') {
-          ok(e.data.status, "Service worker test: " + e.data.msg);
-        } else if (e.data.type == 'finish') {
-          content.removeChild(iframe);
-          resolve();
-        }
-      }
-
-      iframe.onload = function(e) {
-        iframe.onload = null;
-        reg.active.postMessage(msg);
-      }
-    });
-  }
-
-  function testGetServiceWorker() {
-    return navigator.serviceWorker.getRegistration("./notification/")
-      .then(function(reg) {
-        return waitForSWTests(reg, 'create');
-      });
-  }
-
-  // Create a Notification here, make sure ServiceWorker sees it.
-  function testAcrossThreads() {
-    return navigator.serviceWorker.getRegistration("./notification/")
-      .then(function(reg) {
-        return reg.showNotification("This is a title")
-                 .then(function() {
-                  return reg;
-                 });
-      }).then(function(reg) {
-        return waitForSWTests(reg, 'do-not-create');
-      });
-  }
-
-  SimpleTest.waitForExplicitFinish();
-
-  MockServices.register();
-  SpecialPowers.pushPrefEnv({"set": [
-    ["dom.serviceWorkers.exemptFromPerDomainMax", true],
-    ["dom.serviceWorkers.enabled", true],
-    ["dom.serviceWorkers.testing.enabled", true],
-    ["dom.webnotifications.workers.enabled", true],
-    ["notification.prompt.testing", true],
-  ]}, function() {
-    registerSW()
-      .then(testGet)
-      .then(testGetWorker)
-      .then(testGetServiceWorker)
-      .then(testAcrossThreads)
-      .then(function() {
-        MockServices.unregister();
-        SimpleTest.finish();
-      });
-  });
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/workers/test/serviceworkers/test_notificationclick.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=916893
--->
-<head>
-  <title>Bug 1114554 - Test ServiceWorkerGlobalScope.notificationclick event.</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114554">Bug 1114554</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-</pre>
-<script type="text/javascript">
-  SimpleTest.requestFlakyTimeout("Mock alert service dispatches show and click events.");
-
-  function testFrame(src) {
-    var iframe = document.createElement("iframe");
-    iframe.src = src;
-    window.callback = function() {
-      window.callback = null;
-      document.body.removeChild(iframe);
-      iframe = null;
-      ok(true, "Got notificationclick event.");
-      MockServices.unregister();
-      SimpleTest.finish();
-    };
-    document.body.appendChild(iframe);
-  }
-
-  function runTest() {
-    MockServices.register();
-    testFrame('notificationclick.html');
-    navigator.serviceWorker.register("notificationclick.js", { scope: "notificationclick.html" }).then(function(reg) {
-    }, function(e) {
-      ok(false, "registration should have passed!");
-    });
-  };
-
-  SimpleTest.waitForExplicitFinish();
-  SpecialPowers.pushPrefEnv({"set": [
-    ["dom.serviceWorkers.exemptFromPerDomainMax", true],
-    ["dom.serviceWorkers.enabled", true],
-    ["dom.serviceWorkers.testing.enabled", true],
-    ["dom.webnotifications.workers.enabled", true],
-    ["notification.prompt.testing", true],
-  ]}, runTest);
-</script>
-</body>
-</html>
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -148,18 +148,16 @@ var interfaceNamesInGlobalScope =
     "ImageData",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MessageChannel",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MessageEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MessagePort",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "NotificationEvent",
-// IMPORTANT: Do not change this list without review from a DOM peer!
     "Performance",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PerformanceEntry",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PerformanceMark",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PerformanceMeasure",
 // IMPORTANT: Do not change this list without review from a DOM peer!
deleted file mode 100644
--- a/dom/workers/test/test_notification.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=916893
--->
-<head>
-  <title>Bug 916893</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=916893">Bug 916893</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-</pre>
-<script type="text/javascript">
-  SimpleTest.requestFlakyTimeout("Mock alert service dispatches show and click events.");
-
-  function runTest() {
-    MockServices.register();
-    var w = new Worker("notification_worker.js");
-    w.onmessage = function(e) {
-      if (e.data.type === 'finish') {
-        MockServices.unregister();
-        SimpleTest.finish();
-      } else if (e.data.type === 'ok') {
-        ok(e.data.test, e.data.message);
-      } else if (e.data.type === 'is') {
-        is(e.data.test1, e.data.test2, e.data.message);
-      }
-    }
-
-    SimpleTest.waitForExplicitFinish();
-    // turn on testing pref (used by notification.cpp, and mock the alerts
-    SpecialPowers.setBoolPref("notification.prompt.testing", true);
-    w.postMessage('start')
-  }
-
-  SimpleTest.waitForExplicitFinish();
-  SpecialPowers.pushPrefEnv(
-    {"set": [["dom.webnotifications.workers.enabled", true]]},
-    runTest
-  );
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/workers/test/test_notification_child.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=916893
--->
-<head>
-  <title>Bug 916893 - Test Notifications in child workers.</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=916893">Bug 916893</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-</pre>
-<script type="text/javascript">
-  SimpleTest.requestFlakyTimeout("Mock alert service dispatches show event.");
-  function runTest() {
-    MockServices.register();
-    var w = new Worker("notification_worker_child-parent.js");
-    w.onmessage = function(e) {
-      if (e.data.type === 'finish') {
-        MockServices.unregister();
-        SimpleTest.finish();
-      } else if (e.data.type === 'ok') {
-        ok(e.data.test, e.data.message);
-      } else if (e.data.type === 'is') {
-        is(e.data.test1, e.data.test2, e.data.message);
-      }
-    }
-
-    SimpleTest.waitForExplicitFinish();
-    // turn on testing pref (used by notification.cpp, and mock the alerts
-    SpecialPowers.setBoolPref("notification.prompt.testing", true);
-    w.postMessage('start')
-  }
-
-  SimpleTest.waitForExplicitFinish();
-  SpecialPowers.pushPrefEnv(
-    {"set": [["dom.webnotifications.workers.enabled", true]]},
-    runTest
-  );
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/workers/test/test_notification_permission.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=916893
--->
-<head>
-  <title>Bug 916893 - Make sure error is fired on Notification if permission is denied.</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
-  <script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=916893">Bug 916893</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-</pre>
-<script type="text/javascript">
-  SimpleTest.requestFlakyTimeout("Mock alert service dispatches show event.");
-  function runTest() {
-    MockServices.register();
-    var w = new Worker("notification_permission_worker.js");
-    w.onmessage = function(e) {
-      if (e.data.type === 'finish') {
-        SpecialPowers.setBoolPref("notification.prompt.testing.allow", true);
-        MockServices.unregister();
-        SimpleTest.finish();
-      } else if (e.data.type === 'ok') {
-        ok(e.data.test, e.data.message);
-      } else if (e.data.type === 'is') {
-        is(e.data.test1, e.data.test2, e.data.message);
-      }
-    }
-
-    SimpleTest.waitForExplicitFinish();
-    // turn on testing pref (used by notification.cpp, and mock the alerts
-    SpecialPowers.setBoolPref("notification.prompt.testing", true);
-    SpecialPowers.setBoolPref("notification.prompt.testing.allow", false);
-    w.postMessage('start')
-  }
-
-  SimpleTest.waitForExplicitFinish();
-  SpecialPowers.pushPrefEnv(
-    {"set": [["dom.webnotifications.workers.enabled", true]]},
-    runTest
-  );
-</script>
-</body>
-</html>
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1002,17 +1002,17 @@ pref("dom.disable_window_open_feature.sc
 pref("dom.disable_window_open_feature.resizable",   true);
 pref("dom.disable_window_open_feature.minimizable", false);
 pref("dom.disable_window_open_feature.status",      true);
 
 pref("dom.allow_scripts_to_close_windows",          false);
 
 pref("dom.disable_open_during_load",                false);
 pref("dom.popup_maximum",                           20);
-pref("dom.popup_allowed_events", "change click dblclick mouseup notificationclick reset submit touchend");
+pref("dom.popup_allowed_events", "change click dblclick mouseup reset submit touchend");
 pref("dom.disable_open_click_delay", 1000);
 
 pref("dom.storage.enabled", true);
 pref("dom.storage.default_quota",      5120);
 
 pref("dom.send_after_paint_to_content", false);
 
 // Timeout clamp in ms for timeouts we clamp
@@ -4318,17 +4318,16 @@ pref("extensions.minCompatiblePlatformVe
 pref("network.buffer.cache.count", 24);
 pref("network.buffer.cache.size",  32768);
 
 // Desktop Notification
 pref("notification.feature.enabled", false);
 
 // Web Notification
 pref("dom.webnotifications.enabled", true);
-pref("dom.webnotifications.workers.enabled", false);
 
 // Alert animation effect, name is disableSlidingEffect for backwards-compat.
 pref("alerts.disableSlidingEffect", false);
 
 // DOM full-screen API.
 pref("full-screen-api.enabled", false);
 pref("full-screen-api.allow-trusted-requests-only", true);
 pref("full-screen-api.pointer-lock.enabled", true);